Vue笔记

萝らか妹 提交于 2019-12-04 12:14:19

ES6 常用语法

关键字

  • let/var

    let为作用域严格的var
    ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,都必须借助于function的作用域来解决应用外面变量的问题(闭包)

  • const

    定义常量,在定义时就必须赋值,若常量指向的是对象,则可以对对象的内部属性进行修改

对象增强写法

  • 对象属性简写

      let name = 'xiaoming'
      // ES6之前
      let obj1 = {
          name: name
      }
      // ES6之后
      let obj2 = {
          name
      }
  • 对象方法简写

      // ES6之前
      let obj1 = {
          test: function () {}
      }
      // ES6之后
      let obj2 = {
          test () {}
      }

循环遍历

普通的for循环

for (let i = 0; i < arrs.length; i++) {
    console.log(arrs[i]);
}

ES6 的for循环

for (let i in arrs) {
    console.log(arrs[i]);
}

for (let arr of arrs) {
    console.log(arr)
}

字符串定义方式

  • ES6之前
    • + 连接
    • 换行时末尾加 \
  • ES6之后
    使用 `` 定义字符串可以直接换行

箭头函数

没有参数

const a = () => {

}

一个参数,可以省略参数的括号

const b = num => {
    return num * num
}

多个参数

const c = (num1, num2) => {
    return num1 + num2
}

方法体只有一行代码

const d = (num1, num2) => num1 * num2

Promise

异步编程的一种解决方案

三种状态

  • pending:等待状态
  • fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
  • reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()

示例

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('Hello World')
        reject('error message')
    }, 1000)
}).then((data) => {
    console.log(data);
}, (err) => {
    console.log(err);
})

Promise链式调用

  • Promise.resolve():将数据包装成Promise对象,并且在内部回调resolve()函数
  • Promise.reject():将数据包装成Promise对象,并且在内部回调reject()函数

Promise.all()

参数中所有的Promise完成后执行

Promise.all([
    new Promise(……)
]).then(results => {
    
})

解构

对象的解构

const obj = {
    name: 'xiaoming', 
    age: 18, 
    sex: 'nan'
}

const {name, age} = obj;

数组的解构

const names = ['zhangsan', 'lisi']

const [name1, name2] = names;

JavaScript 高阶函数

filter 函数的使用

过滤数组中满足条件的元素返回成新数组

let newNums = nums.filter(function (n) {
    return n < 100;
});

filter中的回调函数必须返回一个Boolean值

  • 返回true:函数内部会将这次回调的参数加入到新的数组中
  • 返回false:过滤掉这次的参数

map 函数的使用

依次对数组所有元素进行操作返回操作后的数组

let newNums = nums.map(function (n) {
    return n * 2;
});

reduce 函数的使用

对数组中所有的内容进行汇总

let total = newNums.reduce(function (preValue, n) {
    return preValue + n;
}, 0);

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

参数说明

  • function(total,currentValue, index,arr):必需。用于执行每个数组元素的函数。
    • 函数参数:
      • total:必需。初始值, 或者计算结束后的返回值。
      • currentValue:必需。当前元素
      • currentIndex:可选。当前元素的索引
      • arr:可选。当前元素所属的数组对象。
  • initialValue:可选。传递给函数的初始值

基本语法

官方文档https://cn.vuejs.org/v2/guide

插值操作

  • Mustache:{{}}双大括号插值
  • v-once:该指令后面不需要跟任何表达式,只渲染一次
  • v-html:以html格式渲染数据
  • v-text:以文本格式渲染数据
  • v-pre:不进行解析渲染,直接显示标签内文本
  • v-cloak:给标签设定这个属性后css设置[v-cloak]{display:none;},可以防止渲染过慢导致用户看到原本的内容。原理:当解析完成后,会去掉这个属性

属性绑定 v-bind

动态绑定属性,缩写 ,例子: v-bind:属性名="变量名"

  • v-bind动态绑定class
    • 对象语法
      • 直接通过{}绑定一个类:v-bind:class="{'active': isActive, 'line': isLine}"
      • 和普通的类同时存在,并不冲突:class="title" v-bind:class="{'active': isActive, 'line': isLine}"
      • 放在一个methods或者computed中:class="title" v-bind:class="classes"
    • 数组语法
      • 直接通过{}绑定一个类:v-bind:class="['active', 'line']"
      • 和普通的类同时存在,并不冲突:class="title" v-bind:class="['active', 'line'}"
      • 放在一个methods或者computed中:class="title" v-bind:class="classes"
  • v-bind动态绑定style
    • 对象语法:v-bind:style="{color: currentColor, fontSize: fontSize + 'px'}"
      • style后面跟的是一个对象类型
        对象的key是css属性名称
        对象的value是具体赋的值,值可以来自于data中的属性
    • 数组语法:v-bind:style="[baseStyles, overridingStyles]"
      • style后面跟的是一个数组类型
        多个值以, 分割即可

计算属性 computed

  • 基本使用

      data: {firstName: '', lastName: ''},
      computed: {
          fullName: function () {
              return this.firstName + '' + this.lastName
          }
      }
  • 完整写法(本质)

      data: {firstName: '', lastName: ''},
      computed: {
          fullName: {
              set: function(newValue) {
                  const names = newValue.split(' ');
                  this.firstName = names[0];
                  this.lastName = names[1];
              }, 
              get: function () {
                  return this.firstName + '' + this.lastName
              }
          }
      }
  • computed比methods好的地方:有缓存,调用多次只会计算一次

事件监听 v-on

绑定事件监听器,缩写:@,例子: v-on:"xxx"

参数问题

  • 如果该方法不需要额外参数,那么方法后的()可以不添加,当方法本身有一个参数,那么会默认将原生事件event参数传递进去
  • 如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件

修饰符

  • .stop:调用event.stopPropagation()——停止冒泡(嵌套的外层标签的事件不触发)
  • .prevent:调用event.preventDefault()——阻止默认事件(阻止表单提交)
  • .{keyCode|keyAlias}:只当事件是从特定键触发时才触发回调
  • .native:监听组件根元素的原生事件
  • .once:只触发一次回调

条件判断 v-if、v-else-if、v-else

<p v-if="score>=90">优秀</p>
<p v-else-if="score>=80">良好</p>
<p v-else-if="score>=60">及格</p>
<p v-else>不及格</p>

输入框时虚拟DOM导致的复用问题,标签加上key属性,赋值不一样则不会复用

决定元素是否渲染 v-if和v-show对比

  • v-if:当条件为false时,包含v-if指令的元素,根本就不会存在DOM中
  • v-show:当条件为false时,v-show只是给我们的元素添加一个行内样式:display: none;

循环遍历 v-for

遍历数组

  • 没有使用索引值:v-for="item in items"
  • 获取索引值:v-for="(item, index) in items"

遍历对象

  • 只获取一个值,获取value:v-for="item in info"
  • 获取key和value:v-for="(value, key) in info"
  • 获取key和value和index:v-for="(value, key, index) in info"

注意点:组件的key属性,在使用v-for时,给对应的元素或者组件添加上一个:key属性,可以高效的更新虚拟DOM,要注意:key值的唯一性

过滤器 filters

定义:

filters: {
    showPrice(price) {
        return '¥' + price.toFixed(2)
    }
}

使用:{{变量名 | 过滤器方法名}}

响应式修改数组

响应式的数组的方法

  • .push():在数组最后面添加元素
  • .pop():删除数组中的最后一个元素
  • .shift():删除数组中的第一个元素
  • .unshift():在数组最前面添加元素
  • .splice():三个参数,从参数一开始,删除长度为参数二的元素,添加参数二后面的所有参数
  • .sort():排序
  • .reverse():反转
  • Vue.set(要修改的对象,索引值,修改后的值):修改

直接通过索引修改元素不是响应式的

表单双向绑定 v-model

原理

  • 本质包含两个操作
    1. v-bind绑定一个value属性
    2. v-on指令给当前元素绑定input事件
  • 下面两行代码等效

      <input type="text" v-model="message">
      <input type="text" v-bind:value="message" v-on:input="message = $event.target.value">

修饰符

  • .lazy:默认是同步更新,lazy修饰符可以让数据在失去焦点或者回车时才会更新
  • .number:输入框默认会将输入内容当作字符串,number修饰符可以让输入框输入的内容自动转成数字类型
  • .trim:去掉左右两边的空格

组件化开发

基本概念

组件的使用分成三个步骤

  • 创建组件构造器:调用Vue.extend()方法
  • 注册组件:调用Vue.component()方法
  • 使用组件:在Vue实例的作用范围内使用组件

基本示例

<div id="app">
    <!-- 3.使用组件 -->
    <my-cpn></my-cpn>
</div>
<script>
    //1.创建组件构造器对象
    const cpnC = Vue.extend({
        template: `
            <div>
                <h1>我是标题</h1>
            </div>
        `
    })
    //2.注册组件
    Vue.component('my-cpn', cpnC)

</script>

组件作用域

<script>
    const cpnC = Vue.extend({
        template: `
            <div>
                <h1>我是标题</h1>
            </div>
        `
    })
    //全局组件,可以在多个Vue的实例下使用
    Vue.component('cpn1', cpnC)
    const app = new Vue({
        el: '#app', 
        components: {
            //局部组件,只能在当前Vue实例下使用
            //cpn2代表使用组件的标签名
            //cpnC代表组件名
            cpn2: cpnC
        }
    })
</script>

父子组件

<script>
    //组件1(子组件)
    const cpnC1 = Vue.extend({
        template: `
            <div>
                <h1>我是标题</h1>
            </div>
        `
    })
    //组件2,在组件2中注册组件1(父组件)
    const cpnC2 = Vue.extend({
        template: `
            <div>
                <h1>我是标题</h1>
            </div>
        `, 
        components: {
            cpn1: cpnC1
        }
    })

    const app = new Vue({
        el: '#app', 
        components: {
            cpn2: cpnC2
        }
    })
</script>

子组件只能在父组件中使用,不能在父组件的父组件中使用

注册组件语法糖写法

省去了调用Vue.extend()的步骤,而是可以直接使用一个对象来代替

<script>
    //注册全局组件
    Vue.component('cpn1', {
        template: `
            <div>
                <h1>我是标题</h1>
            </div>
        `
    })

    const app = new Vue({
        el: '#app', 
        components: {
            //注册局部组件
            cpn2: {
                template: `
                    <div>
                        <h1>我是标题</h1>
                    </div>
                `
            }
        }
    })
</script>

组件模板的分离写法

script标签,类型必须是text/x-template

<script type="text/x-template" id="cpn">
    <div>
        <h1>我是标题</h1>
    </div>
</script>

<script>
    Vue.component('cpn', {
        template: '#cpn'
    })
</script>

template标签

<template id="cpn">
    <div>
        <h1>我是标题</h1>
    </div>
</template>

<script>
    Vue.component('cpn', {
        template: '#cpn'
    })
</script>

组件中的数据

data不能写成属性,要写成函数返回值

<script>
    Vue.component('cpn', {
        template: '#cpn', 
        data() {
            return {
                ……
            }
        }
    })
</script>

父子组件的通信

  • 通过props子组件传递数据
  • 通过事件向父组件发送消息

父组件向子组件传递:props

  1. 在子组件中添加props选项

     props: ['变量1', '变量2']

    同时可以进行数据验证

     Vue.component('cpn', {
         props: {
             //基础的类型检查('null'匹配任何类型)
             propA: Number, 
             //多个可能的类型
             propB: [String, Number], 
             //必填的字符串
             propC: {
                 type: String, 
                 required: true
             }, 
             //带有默认值的数字
             propD: {
                 type: Number, 
                 default: 100
             }, 
             //带有默认值的对象
             propE: {
                 type: Object, 
                 default: function () {
                     return {message: 'hello'}
                 }
             }, 
             //自定义验证函数
             propF: {
                 validator: function (value) {
                     return ['success', 'warning', 'danger'].indexOf(value) !== -1
                 }
             }
         }
     })
    • 验证支持的数据类型:String, Number, Boolean, Array, Object, Date, Function, Symbol
    • 当验证类型为对象或数组时,默认值必须是一个函数
  2. 通过v-bind绑定父组件中的变量

    当变量名是驼峰命名时,v-bind:cInfo="info" 需要写成 v-bind:c-info="info"

子组件向父组件传递:自定义事件$emit

自定义事件的流程

  • 在子组件中,通过$emit()来触发事件
  • 在父组件中,通过v-on来监听子组件事件

代码演示

<!-- 父组件模板 -->
<div id="app">
    <!-- 3.监听自定义事件meth的触发,调用父组件中的方法cpnClick,不传参数原生事件默认传event,自定义事件会将参数自动传过去 -->
    <cpn @meth="cpnClick"></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
    <!-- 1.调用子组件中的方法 -->
    <button @click="btnClick(para)"></button>
</template>

<script>
    //子组件
    const cpn = {
        template: '#cpn', 
        methods: {
            btnClick(para) {
                //2.发射事件,自定义meth事件
                this.$emit('meth', para)
            }
        }
    }

    //父组件
    const app = new Vue({
        el: '#app', 
        components: {
            cpn
        }, 
        methods: {
            //4.接收数据,处理事件
            cpnClick(para) {
                console.log(para)
            }
        }
    })
</script>

父子组件的访问方式

  • 父组件访问子组件:使用$children$refs
  • 子组件访问父组件:使用$parent

父组件访问子组件

$children

this.$children是一个数组类型,包含所有子组件对象

$refs 常用

给子组件的标签中添加 ref="xxx" 属性,this.$refs是一个数组类型,this.$refs.xxx是具体某个子组件

子组件访问父组件

  • $parent:访问父组件
  • $root:访问根组件

插槽 slot

基本使用

  • 插槽的基本使用 <slot></slot>
  • 插槽的默认值 <slot>button</slot>
  • 如果有多个值,同时放入到组件进行替换时,一起作为替换元素
  • 定义插槽时包含的标签为默认值

具名插槽

给每个插槽name属性,替换插槽时增加一个slot="name"属性

<div id="app">
    <cpn><span slot="center">标题</span></cpn>
</div>

<template id="cpn">
    <div>
        <slot name="left"><span>左边</span></slot>
        <slot name="center"><span>中间</span></slot>
        <slot name="right"><span>右边</span></slot>
    </div>
</template>

作用域插槽

父组件替换插槽的标签,但是数据由子组件提供

<div id="app">
    <cpn>
        <template slot-scope="slot">
            <span v-for="item in slot.abc">{{item}}</span>
        </template>
    </cpn>
</div>

<template id="cpn">
    <div>
        <slot :abc="arrs">
            <span v-for="item in arrs">{{item}}</span>
        </slot>
    </div>
</template>

模块化

CommonJS

导出

module.exports = {
    变量名, 函数名
}

导入

const {变量名, 函数名} = required('./xxx.js')

ES6

引入js文件时,类型需设置为module

<script src="xxx.js" type="module"></script>

导出

导入时名称需与导出文件里一致

export 变量名, 函数名

default导出,导入时可以自定义命名,每个模块只能有一个default导出

export default 变量名, 函数名

导入

//导入指定信息
import {变量名, 函数名} from "./xxx.js"

//导入时自定义名称
import 自定义变量名 from "./xxx.js"

//导入所有信息
import * as info from "./xxx.js"

Webpack

从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具

官方网站https://webpack.js.org

中文网站https://www.webpackjs.com

安装

  • 安装webpack首先需要安装Node.js,Node.js自带了软件包管理工具npm
  • 查看自己的node版本:node -v
  • 全局安装webpack(这里指定版本号3.6.0,因为vue cli2依赖该版本):npm install webpack@3.6.0 -g
  • 局部安装webpack
    • --save-dev是开发时依赖,项目打包后不需要继续使用的:npm install webpack@3.6.0 --save-dev
    • 在终端直接执行webpack命令,使用的全局安装的webpack
    • 当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack

项目结构

- dist:用于存放之后打包的文件
- src:用于存放我们写的源文件
  - main.js:一个js入口文件
- index.html:浏览器打开展示的首页html
- package.json:通过npm init生成的,npm包管理的文件

相关配置

打包指令:webpack src/main.js dist/bundle.js

配置打包的文件和输出文件的简单指令

  1. npm init:初始化node环境,会在根目录生成package.json文件
  2. npm install:根据package.json文件中的依赖安装相关内容

  3. 根目录下新建webpack.config.js文件

     const path = require('path')
    
     module.exports = {
         //需要进行打包的js入口文件
         entry: './src/main.js', 
         output: {
             //动态获取输出文件目录绝对路径
             path: path.resolve(__dirname, 'dist'), 
             filename: 'bundle.js'
         }, 
     }

    配置好后直接执行webpack指令就能进行打包

  4. (可选)安装局部webpack:npm install webpack@3.6.0 --save-dev

  5. 编辑package.json文件

     ……
     "scripts": {
         ……
         "build": "webpack"
     }
     ……
    • webpack命令映射成npm run build
    • 终端中直接执行webpack时会使用全局的webpack,而使用映射的命令会优先使用局部的webpack

loader

打包时用来转化js以外的文件

文档https://www.webpackjs.com/loaders

使用步骤

  1. 通过npm安装需要使用的loader
  2. 在webpack.config.js中的modules关键字下进行配置

css文件处理

在js入口文件中依赖css文件:require('./css/normal.css')

  • 需要同时安装css-loaderstyle-loader
  • css-loader负责将css文件进行加载
  • style-loader负责将样式添加到DOM中
  • 配置文件中use的顺序是从右往左:['style-loader', 'css-loader']

图片文件处理

使用url-loader配置

  • limit配置了文件大小
  • 小于limit时,对图片进行base64编码
  • 大于limit时,需要使用file-loader,会将文件复制到dist文件夹下并哈希值重命名

图片命名配置,在options中添加如下选项

  • img:文件要打包到的文件夹
  • name:获取图片原来的名字,放在该位置
  • hash:8:为了防止图片名称冲突,依然使用hash,但是只保留8位
  • ext:使用图片原来的扩展名

图片路径问题

  • 默认,webpack会将生成的路径直接返回给使用者
  • 但是,整个程序是打包在dist文件夹下的,所以需要在路径下再添加一个dist/,配置publicPath: "dist/"

配置

use: [
    {
        loader: 'url-loader', 
        options: {
            limit: 8196, 
            name: 'img/[name].[hash:8].[ext]'
        }, 
    }
]

ES6语法处理

在webpack中,使用babel将ES6语法转成ES5

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

配置webpack.config.js文件

{
    test: /\.m?js$/, 
    exclude: /(node_modules|bower_components)/, 
    use: {
        loader: 'babel-loader', 
        options: {
            presets: ['es2015']
        }
    }
}

使用Vue

安装 Vue

  1. npm安装

     npm install --save vue
  2. 在js中导入Vue并使用

     import Vue from 'vue'
  3. 重新打包,运行程序

    默认导入的是runtime-only,其中没有编译template的东西,需要导入runtime-compiler

    修改webpack的配置文件webpack.config.js

     module.exports = {
         ……
         resolve: {
             alias: {
                 'vue$': 'vue/dist/vue.esm.js'
             }
         }   
     }

.vue文件封装处理

安装vue-loader和vue-template-compiler

npm install vue-loader vue-template-compiler --save-dev

修改webpack.config.js的配置文件

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

注意:vue14版本以上需要一个插件,或者降版本13.0.0

plugin

  1. 通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
  2. 在webpack.config.js中的plugins中配置插件

打包html的plugin - HtmlWebpackPlugin

自动生成一个index.html文件(可以指定模板来生成)并将打包的js文件,自动通过script标签插入到body中

安装 npm install html-webpack-plugin --save-dev

使用,修改webpack.config.js文件中的plugins部分

const HtmlWebpackPlugin = require('html-webpack-plugin')
……
plugins: [
    new HtmlWebpackPlugin({
        template: 'index.html'
    }), 
]
  • template表示根据什么模板来生成index.html
  • 需要删除之前在output中添加的publicPath属性
  • 否则插入的script标签中的src可能会有问题

js压缩的plugin - uglifyjs-webpack-plugin

安装 npm install uglifyjs-webpack-plugin@1.1.1 --save-dev

修改webpack.config.js文件,使用插件

const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
……
plugins: [
    new UglifyjsWebpackPlugin()
]

搭建本地服务器

基于node.js搭建,内部使用express框架,可以实现浏览器自动刷新显示修改后的结果

  1. 安装 `npm install --save-dev webpack-dev-server@2.9.1

    devserver是webpack的一个选项,有如下属性可以配置
    • contentBase:为哪个文件夹提供本地服务,默认根文件夹,这里填写./dist
    • port:端口号
    • inline:页面实时刷新
    • historyApiFallback:在SPA页面中,依赖HTML5的history模式
  2. webpack.config.js文件配置修改

     derServer: {
         contentBase: './dist', 
         inline: true
     }, 
  3. 配置scripts,使用安装了本地服务器的局部webpack

     "dev": "webpack-dev-server --open"

    --open参数表示直接打开浏览器

直接运行npm run dev即可

Vue CLI 脚手架

官方网站 https://cli.vuejs.org/zh/

准备工作

  1. 安装NodeJS

    官方网站 http:nodejs.cn/download/

  2. 检测安装的版本

    默认情况下自动安装Node和NPM

     node -v
     npm -v
  3. 淘宝npm镜像cnpm安装

     npm install -g cnpm --registry=https://registry.npm.taobao.org

    然后使用cnpm命令来安装模块

     cnpm install [name]
  4. Webpack的全局安装

     npm install webpack -g
  5. 安装Vue脚手架

     npm install -g @vue/cli

    查看版本 vue --version

    安装的是Vue CLI3的版本,如果要按照Vue CLI2的方式初始化项目是不可以的,这时需要拉取2.x的模板

     npm install @vue/cli-init -g
  6. 初始化项目

    • Vue CLI2:vue init webpack my-project
    • Vue CLI3:vue create my-project
  7. 修改配置:webpack.base.conf.js起别名

     resolve: {
         extensions: ['.js', '.vue', '.json'], 
         alias: {
             '@': resolve('src'), 
             'pages': resolve('src/pages'), 
             'common': resolve('src/common'), 
             'components': resolve('src/components'), 
             'network': resolve('src/network')
         }
     }

Vue CLI3修改默认配置

在根目录下新建配置文件vue.config.js

module.exports = {
    ……
}

路由 vue-router

官方文档https://router.vuejs.org/zh/

安装

  1. 安装vue-router `npm install vue-router --save
  2. 在模块化工程中使用(vue-router是一个插件,通过Vue.use()来安装)
    1. 导入路由对象,并且调用`Vue.use(VueRouter)(router/index.js)

        import VueRouter from 'vue-router'
        import Vue from 'vue'
        Vue.use(VueRouter)
    2. 创建路由实例,并且传入路由映射配置(./router/index.js)

        const routes = [
      
        ]
        const router = new VueRouter({
            routes
        })
      
        export default router
    3. 在Vue实例中挂载创建的路由实例(./main.js)

        //导入的位置是一个目录时自动寻找index文件,可以省略不写
        import router from './router'
      
        new Vue({
            ……
            router, 
        })

基本使用

  1. 创建路由组件 Home.vue
  2. 配置路由映射:组件和路径映射关系(./router/index.js)

     import Home from '../components/Home'
    
     const routes = [
         {
             path: '/home', 
             component: Home
         }, 
     ]
  3. 使用路由:通过<router-link><router-view>

     <router-link to="/home">首页</router-link>
     <!-- <router-view>决定渲染位置 -->
     <router-view></router-view>
    • <router-link>会被渲染成一个<a>标签
    • <router-view>会根据当前的路径,动态渲染处不同的组件
    • 路由切换时,切换的是<router-view>挂载的组件,其他内容不会发生改变

重定向配置默认路径

const routes = [
    {
        path: '', 
        redirect: '/home'
    }, 
    {
        path: '/home', 
        component: Home
    }, 
]

改变路由模式hash为history(改变后路径上不会有#)

const router = new VueRouter({
    routes, 
    mode: 'history'
})
  • to:用于指定跳转的路径
  • tag:指定渲染成什么组件,比如<router-link to='/home' tag='li'>会被渲染成一个<li>元素
  • replace:添加replace属性后不会留下history记录,浏览器无法使用后退键返回到上一个页面
  • active-class:当<router-link>对应的路由匹配成功时,会自动给当前元素设置一个router-link-active的class,在./router/index.js中设置linkActiveClass可以修改默认的名称

路由代码跳转

通过js代码来跳转,template部分

<button @click="linkToHome">首页</button>

script部分

export default {
    name: 'App', 
    methods: {
        linkToHome() {
            this.$router.push('/home')//可以使用返回
            this.$router.replace('/home')//不能使用返回
        }
    }
}

动态路由

  1. 路径映射配置

     path: '/user/:id', 
     component: User
  2. 组件模板

     <router-link :to="'/user/' + id">用户</router-link>
  3. 目标组件获取动态传入的参数

     computed: {
         userId() {
             return this.$route.params.id
         }
     }

路由懒加载写法

const routes = [
    {
        path: '/home', 
        component: () => import('../components/Home')
    }, 
]

嵌套路由

步骤

  1. 创建对应的子组件,并且在路由映射中配置对应的子路由
  2. 在组件内部使用<router-view>标签

实现

const routes = [
    {
        path: '/home', 
        component: Home, 
        children: [
            {
                path: 'message', 
                component: Message
            }, 
        ]
    }, 
]

传递参数

params类型

  • 配置路由格式:/router/:id
  • 传递的方式:在path后面跟上对应的值
  • 传递后形成的路径:/router/123, /router/abc

query类型

  • 配置路由格式:/router,也就是普通配置
  • 传递的方式:对象中使用query的key作为传递方式
  • 传递后形成的路径:/router?id=123, /router?id=abc

组件模板部分

<router-link :to="{path: '/profile', query: {name: 'xiaoming', age: 18}}>档案</router-link>

目标组件获取query对象

$route.query

获取参数

通过$route对象获取,在使用vue-router的应用中,路由对象会被注入每个组件中,赋值为this.$route,并且当路由切换时,路由对象会被更新

$route$router的区别

  • $routerVueRouter实例,想要导航到不同URL,则使用$router.push方法
  • $route为当前router跳转对象,里面可以获取namepathqueryparams

导航守卫

类似Spring的拦截器

官方文档https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

keep-alive

  • Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
    • 有两个非常重要的属性
    • include:字符串或正则表达式,只有匹配的组件会被缓存
    • exclude:字符串或正则表达式,任何匹配的组件都不会被缓存
  • router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存

Vuex

浏览器插件 Vue.js devtools

基本使用

  1. 安装 npm install vuex --save
  2. 创建入口文件./store/index.js

     import Vue from 'vue'
     import Vuex from 'vuex'
    
     //1.安装插件
     Vue.use(Vuex)
    
     //2.创建对象
     const store = new Vuex.Store({
         state: {
             //共享的状态变量
         }, 
         mutations: {
             //修改状态
         }, 
         actions: {
             //异步修改状态
         }, 
         getters: {
             //状态的“计算属性”
         }, 
         modules: {
    
         }
     })
    
     //3.导出store对象
     export default store
  3. 挂载

     import store from './store'
    
     new Vue({
         el: '#app', 
         store, 
         reder: h => h(App)
     })
  4. 使用,通过$store.state取出共享的状态变量

mutations

使用

  • 提取一个公共的store对象,用于保存在多个组件中共享的状态
  • 将store对象放置在new Vue对象中,这样可以保证在所有组件中都可以使用到
  • 在其他组件中使用store对象中保存的状态即可
    • 通过this.$store.state.属性的方式来访问状态
    • 通过this.$store.commit('mutation中方法')来修改状态
  • 通过提交mutation的方式,而非直接改变store.state.count,因为Vuex可以更明确地追踪状态的变化,所以不要直接改变store.state.count的值

代码示例

./store/index.js

const store = new Vuex.Store({
    state: {
        count: 0
    }, 
    mutations: {
        increment(state) {
            state.count++
        }, 
        decrement(state) {
            state.count--
        }
    }, 
    actions: {

    }, 
    getters: {

    }, 
    modules: {

    }
})

组件中

<button @click="add">+1</button>
<button @click="sub">-1</button>

……
computed: {
    count: function() {
        return this.$store.state.count
    }
}, 
methods: {
    add: function() {
        this.$store.commit('increment')
    }, 
    sub: function() {
        this.$store.commit('decrement')
    }
}

传递参数

  • 组件中methods中commit时传入第二个参数
  • mutations中增加第二个参数

提交风格

this.$store.commit({
    type: 'changeCount', 
    count: 100
})

count变成一个对象的属性

changeCount(state, payload) {
    state.count = payload.count
}

Getters

类似计算属性,获取一些state变化后的状态

getters作为参数

getters: {
    greaterAgesStus: state => {
        return state.students.filter(s => s.age >= 20)
    }, 
    greaterAgesCount: (state, getters) => {
        return getters.greaterAgesStus.length
    }
}

getters传递参数

getters: {
    styById: state => {
        return id => {
            return state.students.find(s => s.id ===id)
        }
    }
}

axios

基本使用

  1. 安装 npm install axios --save
  2. 导入 import axios from 'axios
  3. 使用(Promise方式)

     axios({
         url: xxx
         //针对get请求的参数拼接
         params: {
             type: 'pop'
             page: 1
         }
     }).then(res => {
         //返回结果在res.data里
         console.log(res)
     })

发送并发请求

  • 使用axios.all,可以放入多个请求的数组
  • axios.all([])返回的结果是一个数组,使用axios.spread可将数组[res1, res2]展开为res1, res2

代码示例

axios.all([
    axios.get('url'), 
    axios.get('url',
        {
            params: {
                type: 'sell'
            }
        })
]).then(axios.spread((res1, res2) => {
    console.log(res1)
    console.log(res2)
}))

全局配置

代码示例

axios.defaults.baseURL = 'xxx'

axios({
    url: '/home/data'
})

常见的配置选项

  • 请求地址:url: '/user'
  • 请求类型:method: 'get'
  • 请求根路径:baseURL: 'http://www.mt.com/api'
  • 请求前的数据处理:transformRequest: [function(data){}]
  • 请求后的数据梳理:transformResponse: [function(data){}]
  • 自定义请求头:headers: {'x-Requested-With': 'XMLHttpRequest'}
  • URL查询对象:params: {id: 2}
  • 查询对象序列化函数:paramsSerializer: function(params){}
  • request body:data: {key: 'aa'}
  • 超时时间:timeout: 1000
  • 跨域是否带Token:withCredentials: false
  • 自定义请求处理:adapter: function(resolve, reject, config){}
  • 身份验证信息:auth: {uname: '', pwd:''}
  • 响应的数据格式json/blob/document/arraybuffer/text/stream:responseType: 'json'

实例

  • 从axios模块中导入对象时,使用的实例是默认的实例
  • 给该实例设置一些默认配置时,这些配置就被固定下来了
  • 但是后续开发中,某些配置可能会不太一样
  • 比如某些请求需要使用特定的baseURL或者timeout
  • 这时,可以创建新的实例,并且传入属于该实例的配置信息

代码示例

const instance1 = axios.create({
    baseURL: 'xxx'
})

instance1({
    url: '/data'
}).then(res => {
    console.log(res)
})

拦截器

instance.interceptors.request.use(config => {
    console.log('来到了request拦截success中');
    return config
}, err => {
    console.log('来到了request拦截failure中');
    return err
})

instance.interceptors.response.use(response => {
    console.log('来到了response拦截success中');
    return response.data
}, err => {
    console.log('来到了response拦截failure中');
    return err
})
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!