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中的属性
- style后面跟的是一个对象类型
- 数组语法:
v-bind:style="[baseStyles, overridingStyles]"
- style后面跟的是一个数组类型
多个值以, 分割即可
- 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
原理
- 本质包含两个操作
v-bind
绑定一个value
属性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
在子组件中添加
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
- 当验证类型为对象或数组时,默认值必须是一个函数
通过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应用的静态模块打包工具
安装
- 安装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
配置打包的文件和输出文件的简单指令
npm init
:初始化node环境,会在根目录生成package.json
文件npm install
:根据package.json
文件中的依赖安装相关内容根目录下新建
webpack.config.js
文件const path = require('path') module.exports = { //需要进行打包的js入口文件 entry: './src/main.js', output: { //动态获取输出文件目录绝对路径 path: path.resolve(__dirname, 'dist'), filename: 'bundle.js' }, }
配置好后直接执行
webpack
指令就能进行打包(可选)安装局部webpack:
npm install webpack@3.6.0 --save-dev
编辑
package.json
文件…… "scripts": { …… "build": "webpack" } ……
- 将
webpack
命令映射成npm run build
- 终端中直接执行
webpack
时会使用全局的webpack,而使用映射的命令会优先使用局部的webpack
- 将
loader
打包时用来转化js以外的文件
文档https://www.webpackjs.com/loaders
使用步骤
- 通过npm安装需要使用的loader
- 在webpack.config.js中的modules关键字下进行配置
css文件处理
在js入口文件中依赖css文件:require('./css/normal.css')
- 需要同时安装
css-loader
和style-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
npm安装
npm install --save vue
在js中导入Vue并使用
import Vue from 'vue'
重新打包,运行程序
默认导入的是
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
- 通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
- 在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框架,可以实现浏览器自动刷新显示修改后的结果
安装 `npm install --save-dev webpack-dev-server@2.9.1
devserver是webpack的一个选项,有如下属性可以配置- contentBase:为哪个文件夹提供本地服务,默认根文件夹,这里填写
./dist
- port:端口号
- inline:页面实时刷新
- historyApiFallback:在SPA页面中,依赖HTML5的history模式
- contentBase:为哪个文件夹提供本地服务,默认根文件夹,这里填写
webpack.config.js文件配置修改
derServer: { contentBase: './dist', inline: true },
配置scripts,使用安装了本地服务器的局部webpack
"dev": "webpack-dev-server --open"
--open
参数表示直接打开浏览器
直接运行npm run dev
即可
Vue CLI 脚手架
官方网站 https://cli.vuejs.org/zh/
准备工作
安装NodeJS
检测安装的版本
默认情况下自动安装Node和NPM
node -v npm -v
淘宝npm镜像cnpm安装
npm install -g cnpm --registry=https://registry.npm.taobao.org
然后使用cnpm命令来安装模块
cnpm install [name]
Webpack的全局安装
npm install webpack -g
安装Vue脚手架
npm install -g @vue/cli
查看版本
vue --version
安装的是Vue CLI3的版本,如果要按照Vue CLI2的方式初始化项目是不可以的,这时需要拉取2.x的模板
npm install @vue/cli-init -g
初始化项目
- Vue CLI2:
vue init webpack my-project
- Vue CLI3:
vue create my-project
- Vue CLI2:
修改配置: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/
安装
- 安装vue-router `
npm install vue-router --save
- 在模块化工程中使用(
vue-router
是一个插件,通过Vue.use()
来安装)导入路由对象,并且调用`Vue.use(VueRouter)(router/index.js)
import VueRouter from 'vue-router' import Vue from 'vue' Vue.use(VueRouter)
创建路由实例,并且传入路由映射配置(./router/index.js)
const routes = [ ] const router = new VueRouter({ routes }) export default router
在Vue实例中挂载创建的路由实例(./main.js)
//导入的位置是一个目录时自动寻找index文件,可以省略不写 import router from './router' new Vue({ …… router, })
基本使用
- 创建路由组件 Home.vue
配置路由映射:组件和路径映射关系(./router/index.js)
import Home from '../components/Home' const routes = [ { path: '/home', component: Home }, ]
使用路由:通过
<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' })
router-link 属性
- 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')//不能使用返回 } } }
动态路由
路径映射配置
path: '/user/:id', component: User
组件模板
<router-link :to="'/user/' + id">用户</router-link>
目标组件获取动态传入的参数
computed: { userId() { return this.$route.params.id } }
路由懒加载写法
const routes = [ { path: '/home', component: () => import('../components/Home') }, ]
嵌套路由
步骤
- 创建对应的子组件,并且在路由映射中配置对应的子路由
- 在组件内部使用
<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
的区别
$router
为VueRouter
实例,想要导航到不同URL,则使用$router.push
方法$route
为当前router
跳转对象,里面可以获取name
、path
、query
、params
等
导航守卫
类似Spring的拦截器
官方文档https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
keep-alive
- Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
- 有两个非常重要的属性
- include:字符串或正则表达式,只有匹配的组件会被缓存
- exclude:字符串或正则表达式,任何匹配的组件都不会被缓存
- router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
Vuex
浏览器插件 Vue.js devtools
基本使用
- 安装
npm install vuex --save
创建入口文件
./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
挂载
import store from './store' new Vue({ el: '#app', store, reder: h => h(App) })
使用,通过
$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
基本使用
- 安装
npm install axios --save
- 导入
import axios from 'axios
使用(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 })