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.jsmodule.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.jsimport 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
})