Vue学习笔记

2,460 阅读11分钟

一、Vue的基本语法

1.Vue的安装方式

方式一:直接CDN引入

<!-- 开发环境版本,包含了有帮助的命令行警告-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/uve.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script> 

方式二:下载和引入
开发环境 vuejs.org/js/vue.js
生产环境 vuejs.org/js/vue.min.… 方式三:NPM安装 后续通过webpack和CLI的使用,我们使用该方式。

2.Vue的使用案例

  • vue的基本使用方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <h1>{{ message }}</h1>
        <h2>{{ name }}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //编程方式: 声明式编程
        const app = new Vue({
            el: '#app', //用于挂在要管理的元素
            data: { //定义数据
                message: '你好啊,李银河',
                name: 'coderwhy'
            }
        });

        // 元素js的做法(编程范式: 命令式编程)
        // 1.创建div元素,设置id属性

        // 2.定义一个变量叫message

        // 3.将message变量放在前面的div元素中显示

        // 4.修改message的数据: 今天天气不错!

        // 5.将修改后的数据再次替换到div元素
    </script>
</body>
</html>

  • 列表展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <ul>
            <li v-for="item in movies">{{ item }}</li>
        </ul>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                movies: ['星际穿越', '大话西游', '少年派', '盗梦空间']
            }
        });
    </script>
    
</body>
</html>

  • 计数器示例
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <h2>当前计数: {{ counter }}</h2>
        <!-- <button v-on:click="counter++">+</button>
        <button v-on:click="counter--">-</button> -->
        <button v-on:click="add">+</button>
        <button v-on:click="sub">-</button>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                counter: 0
            },
            methods: {
                add: function () {
                    console.log('add被执行');
                    this.counter++;
                },
                sub: function () {
                    console.log('sub被执行');
                    this.counter--;
                }
            }
        });

        // 1.拿button元素

        // 2.添加监听事件
    </script>
</body>

</html>

3.Vue示例传入的options

  • el:类型:string | HTMLElement(决定之后Vue示例会管理哪一个DOM)
  • data:类型:Object | Function组件当中data必须是一个函数(Vue实例对应的数据对象)
  • methods:类型{[key:string]:Function}(定义属于Vue的一些方法,可以在其他地方调用,也可以在指令中使用)

4.Vue的生命周期(事物从诞生到消亡的整个过程)

5.插值操作

  • mustache{{}}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id='app'>
    <h2>{{ message }}</h2>
    <h2>{{ message }}, 李银河!</h2>
    <!-- mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式-->
    <h2>{{ firstName + lastName }}</h2>
    <h2>{{ firstName + ' ' + lastName }}</h2>
    <h2>{{ firstName }}  {{ lastName }}</h2>
    <h2>{{ counter * 2 }}</h2>
  </div>
  <script> src = '../js/vue.js'</script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        firstName: 'kobe',
        lastName: 'bryant',
        counter: 100
      }
    });
  </script>
</body>
</html>
  • v-once:该指令后不用加表达式(表示元素和组件只渲染一次,不会随着数据的改变而改变)。
  • v-html:后面往往会跟上一个string类型(将string的html解析出来并且进行渲染)
  • v-text:作用和Mustache比较相似,用于将数据显示在界面中(通常情况下,接收一个string类型)
  • v-pre:将{{ message }}不解析
  • v-cloak:防止浏览器直接显示出未解析的mustache表达式(在渲染前存在,渲染后不存在)

6.绑定操作

  • v-bind:any | Object(动态绑定一个属性)可以简写为语法糖:
********v-bind绑定class********
用法一:直接通过{}绑定一个类
<h2 :class="{'active':isActive}">Hello World</h2>
用法二:也可以通过判断,传入多个值
<h2 :class="{'active':isActive, 'line':isLine}">Hello World</h2>
用法三:和普通的类同时存在,并不冲突
注:如果isActive和isLine都为true,那么会有title/active/line三个类
<h2 class="title" :class="{'active':isActive, 'line':isLine}">Hello World</h2>
用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>
********v-bind绑定style********
<div :style="{color: currentColor, fontSize: fontSize + 'ps'}"></div>
style后面跟的是一个对象类型
<div v-bind:style="[baseStyles, overridingStyles]"></div>
style后面跟的是一个数组类型

7.计算属性(computed)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id='app'>
    <!-- 1.直接拼接:语法过于繁琐-->
    <h2>{{ firstName }} {{ lastName }}</h2>
    <!-- 2.通过定义methods,多次调用会多次执行 -->
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <h2>{{ getFullName() }}</h2>
    <!-- 3.通过computed,通过缓存只执行一次 -->
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
    <h2>{{ fullName }}</h2>
  </div>
  <script src='../js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        firstName: 'Lebron',
        lastName: 'James'
      },
      computed: {
        fullName: function() {
          console.log('fullName');
          return this.firstName + ' ' + this.lastName;
        }
      },
      methods: {
        getFullName: function() {
          console.log('getFullName');
          return this.firstName + ' ' + this.lastName;
        }
      }
    });
  </script>
</body>

</html>

8.事件监听

v-on(语法糖@):如果不需要参数可以不写(),如果有一个参数默认将event传过去。

****** 参数相关 ******
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id='app'>
    <!-- 时间调用的方法没有参数 -->
    <button @click="btn1Click()">按钮1</button>
    <button @click="btn1Click">按钮1</button>

    <!-- 在时间定义时,写函数时省略了小括号,但是方法本身是需要一个参数的 -->
    <button @click="btn2Click(123)">按钮2</button>
    <!-- <button @click="btn2Click()">按钮2</button> -->
    <button @click="btn2Click">按钮2</button>

    <!-- 方法定义时,我们需要event对象,同时又需要其他参数 -->
    <button @click="btn3Click(123, $event)">按钮3</button>
    <button @click="btn3Click(123)">按钮4</button>
  </div>
  <script src='../js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      methods: {
        btn1Click() {
          console.log('btn1Click');
        },
        btn2Click(event) {
          console.log(event);
        },
        btn3Click(num, event) {
          console.log(num);
          console.log(event);
        }
      }
    });
  </script>
</body>

</html>
****** 修饰符 ******
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id='app'>
    <!-- 1..stop修饰符的使用(防止冒泡) -->
    <div @click="divClick">
      Div HTMLElement
      <button @click.stop="btnClick">按钮</button>
    </div><br>

    <!-- 2..prevent修饰符的使用(阻止默认事件) -->
    <form action="baidu">
      <input type="submit" value="提交" @click.prevent="submitClick">
    </form>

    <!-- 3.. 监听某个键盘的键帽-->
    <input type="text" @keyup.enter="keyUp">

    <!-- 4..once修饰符的使用(只触发一次回调) -->
    <button @click.once="btn2Click">按钮2</button>
  </div>
  <script src='../js/vue.js'></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      methods: {
        divClick() {
          console.log('divClick');
        },
        btnClick() {
          console.log('btnClick');
        },
        btn2Click() {
          console.log('btnClick');
        },
        submitClick() {
          console.log('submitClick')
        },
        keyUp() {
          console.log('keyUp');
        }
      }
    });
  </script>
</body>

</html>

9.v-if、v-else、v-else-if

会根据key判断是否复用(即当前dom的唯一标识)

10.v-show

11.v-for循环遍历

  • 遍历数组
  • 遍历对象
  • 绑定一个唯一的key可以提高性能(Diff算法)
  • 可以响应式渲染页面的数组方法

12.v-model的使用

  • v-model双向绑定的原理 1.绑定了对应dom的value值 2.绑定了对应dom的input事件
  • v-model结合checkbox的使用
  • v-model结合select的使用
  • v-model修饰符的使用

13.组件化开发

  • 组件的基本使用
  • 父组件和子组件
  • 组件的语法糖注册方式
  • 组件模块的分离写法
  • 组件通信-父组件向子组件传递数据
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <div id='app'>
    <cpn :cmovies="movies" :cmessage="message"></cpn>
  </div>

  <template id="cpn">
    <div>
      <ul>
        <li v-for="item in cmovies">{{ item }}</li>
      </ul>
      <h2>{{ cmessage }}</h2>
    </div>
  </template>
  <script src='../js/vue.js'></script>
  <script>
    // 父传子: props
    const cpn = {
      template: '#cpn',
      // props: ['cmovies', 'cmessage'],
      props: {
        // 1.类型限制
        // cmovies: Array,
        // cmessage: String

        // 2.提供一些默认值
        cmessage: {
          type: String,
          default: '',
          // 必须值
          required: true,
          validator() {
            return ['success','warning','danger'].indexOf(value) !== -1;
          }
        },
        // 类型是对象或者数组时,默认值必须是一个函数
        cmovies: {
          type: Array,
          default() {
            return []
          }
        }
      },
      data() {
        return {}
      },
      methods: {

      }
    };

    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        movies: ['海王', '海贼王', '海尔兄弟']
      },
      components: {
        cpn
      }
    });
  </script>
</body>

</html>
  • 组件通信-子传父
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <!-- 父组件模板 -->
  <div id='app'>
    <cpn @itemclick="cpnClick"></cpn>
  </div>

  <!-- 子组件模板 -->
  <template id="cpn">
    <div>
      <button @click="btnClick(item)" v-for="item in categories">{{ item.name }}</button>
    </div>
  </template>

  <script src='../js/vue.js'></script>
  <script>

    // 1.子组件
    const cpn = {
      template: '#cpn',
      data() {
        return {
          categories: [
            {id:'aaa', name:'热门推荐'},
            {id:'bbb', name:'手机数码'},
            {id:'ccc', name:'家装家电'},
            {id:'ddd', name:'电脑办公'}
          ]
        }
      },
      methods: {
        btnClick(item) {
          //发射事件
          this.$emit('itemclick', item);
        }
      }
    }

    // 2.父组件
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      components: {
        cpn
      },
      methods: {
        cpnClick(item) {
          console.log(item);
        }
      }
    });
  </script>
</body>

</html>
  • 父子组件的访问方式($children)-父访问子

  • 父子组件的访问方式(children和root)-子访问父

14.组件的插槽(slot)

  • 插槽的基本使用
  • 具名插槽的使用
  • 作用域插槽(父组件获取子组件元素)

二、webpack详解

1.webpack的安装

  • 查看自己的node版本

  • 全局安装webpack

  • 局部安装webpack --save-dev是开发时依赖,项目打包后不需要继续使用的

2.webpack的起步

****** info.js(使用ES6的模块化导入) ******
export const name = 'why';
export const age = 18;
export const height = 1.88;
****** mathUtils.js(使用commonJs的模块化导入) ******
function add(num1, num2) {
  return num1 + num2;
}

function mul(num1, num2) {
  return num1 * num2;
}

module.exports = {
  add,
  mul
}
****** main.js实际调用的类 ******
const {add, mul} = require('./mathUtils.js');

console.log(add(20, 30));
console.log(mul(20, 30));

import { name, age, height } from './info';
console.log(name);
console.log(age);
console.log(height);
****** index.html ******
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script src="./dist/bundle.js"></script>
</body>
</html>

打包成对应的bundle

3.webpack的配置

  • 创建webpack.config.js文件
const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    //动态获取路径
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
}
****** 可以直接执行webpack命令 ******
  • node包的管理文件(通过npm init命令生成)

  • package.json中的script可以通过npm run命令执行定义的命令

4.webpack的loader

5.webpack配置Vue

  • 安装vue

  • 配置webpack文件

  • 下载vue文件的解析loader

配置webpack.config.js

{
    test: /\.vue$/,
    use: ['vue-loader']
},

6.配置webpack插件

  • 添加打包文件版权描述信息插件

  • 指定根据什么模板文件来生成index.html 下载html-webpack-plugin插件

    生成后的index.html文件

  • 压缩js文件代码 下载uglifyjs-webpack-plugin插件

    添加配置信息

  • 搭建本地服务器 安装webpack-dev-server

    配置执行命令

执行npm run dev启动本地服务器

7.webpack配置文件的抽离

  • 将webpack的配置信息分成三个文件 base.config.js:公共的配置信息 dev.config.js:开发环境的配置信息 prod.config.js:生产环境的配置信息
    下载webpack-merge插件
    将公共配置信息和开发或生产环境的配置文件合并

三、Vue CLI(脚手架使用)

1.安装Vue脚手架

  • 安装vue最新版本
  • 安装vue2.x版本

2.Vue2.x脚手架的使用

3.vue+complier和vue-only的区别

vue+complier:template->ast->render->vdom->UI
vue-only:render->vdom->UI(通过下载的vue-template-complier将template直接解析成render了)

4.Vue3.x脚手架的使用

指定下载3.2.1版本的脚手架指令

创建3.2.1版本的vue脚手架

5.修改Vue3.x脚手架的配置方式

启动可视化配置项目

四、路由的使用(vue-router)

1.vue-router的基本使用

  • 安装vue-router
  • 配置router文件,并将router组件挂在到App.vue中

2.vue-router的嵌套路由

3.vue-router的参数传递

  • 通过:to的方式跳转并传递数据

  • 通过按钮事件的方式跳转并传递数据

4.vue-router的导航守卫(beforeEach() | afterEach())

5.keep-alive

  • keep-alive -> activated/deactivated
  • 首页中使用path属性记录离开时的路径,在beforeRouteLeave中记录。
  • keep-alive的属性 include-字符串或正则,只有匹配的组件会被缓存 exclude-字符串或正则,任何匹配的组件都不会被缓存

五、Promise的使用

1. Promise的基本使用

// 1.使用setTimeout
    // setTimeout(() => {
    //   console.log('Hello World');
    // }, 1000)

    // 参数 -> 函数(resolve, reject)
    // resolve, reject本身它们又是函数
    // 链式编程
    new Promise((resolve, reject) => {
      // 第一次网络请求的代码
      setTimeout(() => {
        resolve();
      }, 1000)
    }).then(() => {
      // 第一次处理代码
      console.log('Hello World');
      return new Promise((resolve, reject) => {
        // 第二次网络请求的代码
        setTimeout(() => {
          resolve();
        }, 1000)
      })
    }).then(() => {
      // 第二次处理代码
      console.log('Hello Vuejs');
      return new Promise((resolve, reject) => {
        // 第三次网络请求的代码
        setTimeout(() => {
          resolve();
        }, 1000)
      })
    }).then(() => {
      // 第三次处理代码
      console.log('Hello End');
    });
    
    // 什么情况下会用到Promise?
    // 一般情况下是有异步操作时,使用Promise对这个异步操作进行封装
    // new -> 构造函数(1.保存一些状态信息 2.执行传入的函数)
    // 在执行传入的回调函数时,会传入两个参数,resolve,reject,本身又是函数
    new Promise((resolve, reject) => {
      setTimeout((data) => {
        // 成功的时候调用reslove
        resolve('Hello World')

        // 失败的时候调用reject
        reject('error message');
      }, 1000)
    }).then(data => {
      console.log(data);
    }).catch(err => {
      console.log(err);
    });
    
    // 或者可以不用catch只使用then获取error信息
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("Hello World");
        reject("Error Data");
      }, 1000) 
    }).then(data => {
      console.log(data);
    }, error => {
      console.log(error);
    });

2. Promise的链式调用(三种写法)

<script>
    // 网络请求: aaa -> 自己处理(10行)
    // 处理: aaa111 -> 自己处理(10行)
    // 处理: aaa111222 -> 自己处理

    // 第一种写法
    // new Promise((resolve, reject) => {
    //   setTimeout(() => {
    //     resolve('aaa');
    //     reject('error')
    //   },1000)
    // }).then(res => {
    //   console.log(res + '第一层的10行处理代码');

    //   return new Promise((resolve, reject) => {
    //     resolve(res + '111');
    //     reject('error')
    //   })
    // }).then(res => {
    //   console.log(res + '第二层的10行处理代码');

    //   return new Promise((resolve, reject) => {
    //     resolve(res + '222');
    //     reject('error')
    //   })
    // }).then(res => {
    //   console.log(res + '第三层的10行处理代码');
    // }).catch(err => {
    //   console.log(err)
    // });

    // 第二种写法
    // new Promise((resolve, reject) => {
    //   setTimeout(() => {
    //     resolve('aaa');
    //   }, 1000)
    // }).then(res => {
    //   console.log(res + '第一层的10行处理代码');

    //   return Promise.resolve(res + '111');

    // 两种抛出异常的方式
    //   return Promise.reject('error');
    //   throw 'error message'
    // }).then(res => {
    //   console.log(res + '第二层的10行处理代码');

    //   return Promise.resolve(res + '222');
    //   return Promise.reject('error');
    // }).then(res => {
    //   console.log(res + '第三层的10行处理代码');
    // }).catch(err => {
    //   console.log(err);
    // });

    // 第三种写法(省略掉Promise.resolve直接对数据进行处理)
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('aaa');
      }, 1000)
    }).then(res => {
      console.log(res + '第一层的10行处理代码');

      return res + '111';
    }).then(res => {
      console.log(res + '第二层的10行处理代码');

      return res + '222';
    }).then(res => {
      console.log(res + '第三层的10行处理代码');
    })
  </script>

3.Promise的All方法

<script>
    // 两次请求都执行完resolve方法后才调用then方法
    Promise.all([
      // new Promise((resolve, reject) => {
      //   $ajax({
      //     url: 'url1',
      //     success: function (data) {
      //       resolve(data);
      //     }
      //   })
      // }),
      // new Promise((resolve, reject) => {
      //   $ajax({
      //     url: 'url2',
      //     success: function (data) {
      //       resolve(data);
      //     }
      //   })
      // })

      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('result1');
        }, 2000)
      }),
      new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('result2');
        }, 1000)
      })
    ]).then(results => {
      console.log(results[0]);
      console.log(results[1]);
    })
  </script>

六、Vuex详解

1.安装Vuex

  • 执行vuex插件安装命令
  • 新建vuex配置文件的目录及文件
  • 添加vuex配置文件代码
import Vue from 'vue';
import Vuex from 'vuex';

// 1.安装插件
Vue.use(Vuex);

// 2.创建对象
const store = new Vuex.Store({
  state: {
    counter: 1000
  },
  mutations: {

  },
  actions: {

  },
  getters: {

  },
  modules: {

  }
});

// 3.导出store独享
export default store;
  • 在Vue实例中注册

2. Vuex的使用

七、axios请求框架详解

1.axios的基本使用

2.axios发送并发请求

3.axios全局配置

4.axios实例

5.axios拦截器(请求成功,请求失败,响应成功,响应失败)

export function request(config) {
  // 1.创建axios的实例
  const instance = axios.create({
    baseURL: 'http://123.207.32.32:8000',
    timeout: 5000
  })
  // 2.axios的拦截器
  // 2.1请求拦截的作用
  instance.interceptors.request.use(config => {
    console.log(config);
    // 1.比如config中的一些配置信息不符合服务器要求
    // 2.比如每次发送网络请求时,都希望在页面中显示一个请求的图标
    // 3.某些网络请求(比如登陆(token)), 需要携带一些特殊的信息

    return config
  }, err => {
    // 断网的时候(发不出去)
    console.log(err);
  });

  // 2.2响应拦截的作用
  instance.interceptors.response.use(res => {
    console.log(res);
    return res.data;
  }, err => {
    console.log(err);
  });

  // 3.发送真正的网络请求
  return instance(config);
}