Vue笔记
Vue简介
- 框架类型
- 动态构建用户界面的 渐进式JavaScript 框架
- 使用模式
- 遵循 MVVM模式
- 与其他JS框架特点
- 借鉴 Angular 的 模板 和 数据绑定 技术
- 借鉴 React 的 组件化 和 虚拟DOM 技术
基础语法
安装
- <script>引入
- 本地引入
- CDN加速网络引入
- npm引入
npm install vue
语法前提
使用Vue语法前需要满足的条件和需要了解的知识点
Vue容器 & Vue实例
- 创建 Vue容器
1
2
3
4
5<body>
<div id="root">
Vue容器
</div>
</body> - 创建 Vue实例
1
2
3
4
5<script>
const v = new Vue({
el:"#root" //el用于指定当前Vue实例为哪个容器服务,通常值为css选择器字符串
})
</script>
工作流程
- 执行 Vue实例 时,会将 Vue容器 拿来进行解析
- 发现 Vue容器 有Vue特定语法,将 Vue实例 中的数据与 Vue容器 对应位置数据进行替换
- 生成新的 Vue容器
- 然后使用新的 Vue容器 替换掉旧的 Vue容器
规则特性
- 一个 Vue实例 对应一个 Vue容器
- 【多个 Vue容器】——【一个 Vue实例】 :只绑定第一个 Vue容器
- 【一个 Vue容器】——【多个 Vue实例】 :只绑定第一个 Vue实例,并且控制台报错
- Vue实例 中data的数据发生改变,页面中 Vue容器 中对应位置数据也会自动更新
Vue模板
- Vue容器 中的代码称为 Vue模板
- Vue实例
- le 指定的元素,
<div id='root'>...</div>标签和标签内所有内容一起称为模板
- le 指定的元素,
- Vue组件
- Vue实例 template 定义的元素(不包含 el 指定元素),称为模板
模板语法
Vue模板 中使用的 Vue语法 ,就称为 模板语法
插值语法
解析标签内容Vue模板 中使用
{{ }}用于将数据插入模板,就称为 插值语法
语法值为 js表达式 、 Vue实例属性
1 | |
1 | |
输出结果:
指令语法
解析标签本身使用 v- 开头的指令的 Vue语法 ,就称为 指令语法
语法值为 js表达式、 Vue实例属性
数据绑定
通过 数据绑定指令 给元素属性绑定 Vue实例 数据
单向绑定
- 渲染的数据只能根据 Vue实例 中的数据进行改变
- v-bind 声明的属性,其值为表达式
- 如果绑定的值为布尔值,则动态决定标签中是否添加此属性
常规:v-bind:xxx = “ttt”
简写::xxx = “ttt”
- xxx:标签属性名
- ttt:标签属性值
1 | |
绑定样式
绑定 class属性
- class属性 和 v-bind:class 可以同时存在
- class属性 :用来定义不变的 class类名
- v-bind:class :用来定义动态改变的 class类名
1 | |
- v-bind:class 的值可以是不同数据类型(字符串、对象、数组)
- 字符串
- 绑定的 类名 不确定,需要动态 修改类名
1
2
3
4
5
6
7
8
9
10
11
12<div id="root">
<p class="ys1" :class="ys_name">这是内容</p>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
ys_name:"ys2"
}
})
</script>
- 绑定的 类名 不确定,需要动态 修改类名
- 数组
- 绑定的 类名 ,类个数 都不确定,需要动态 修改类名 或 增减类名
- 数组元素: class类名的字符串
1
2
3
4
5
6
7
8
9
10
11
12<div id="root">
<p class="ys1" :class="arr_ys">这是内容</p>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
arr_ys:["ys1","ys4"]
}
})
</script>
- 对象
- 绑定的 类名 , 类个数 都确定,但是需要动态 启用或关闭样式
- 对象属性名: class类名
- 对象属性值:布尔值(设置是否启用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<div id="root">
<p class="ys1" :class="obj_ys">这是内容</p>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
obj_ys:{
ys1:true,
ys2:true,
ys3:false
}
}
})
</script>
- 字符串
绑定 style属性
style属性 和 v-bind:style 可以同时存在
- style属性 :用来定义不变的 css样式
- v-bind:style :用来定义动态改变的 css样式
v-bind:style 的值的数据类型为 对象 和 数组
- 对象
- 对象属性:css样式属性(短横线链接的css属性,需要使用驼峰写法)
- 对象属性值:css样式属性值 字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14<div id='root'>
<p style="color:red;" v-bind:style="bc">内容</p>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
bc:{
backgroundColor:"red"
}
}
})
</script>
- 数组
- 动态 增减 或 修改 同一类css属性样式(也可以不是一类),使用数组形式,方便修改
- 数组元素:v-bind 绑定css样式的对象形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<div id='root'>
<p style="color:red;" v-bind:style="arr_ys">内容</p>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
arr_ys:[
{
borderColor:"red",
borderStyle:"solid"
},
{
color:"red"
}
]
}
})
</script>
- 对象
双向绑定
既能根据 Vue实例 中的数据渲染页面,也能通过页面输入数据修改 Vue实例 中的数据
只要在表单元素输入数据, Vue实例 中的数据立即发生改变
只能应用在 表单类元素 的 vule属性 上
常规:v-model:value = “xxx”
简写:v-model = “xxx”
xxx:输入框的内容
1 | |
绑定表单
- 绑定 text 文本输入框
- v-model 收集的是 value 中的数据
- 通用或简写方式也是将 value 和 Vue实例数据 进行绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!-- 将输入框输入的内容(value的值),保存到Vue实例的name1,name2属性中 -->
<div id="root">
<input type="text" v-model="name1"/>
<input type="text" v-model:value="name2"/>
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
name1:"xxxx",
name2:"yyyy"
}
})
</script>
- 绑定 radio 单选框
- 正常情况标签必须添加 value属性 和 值
- 正常情况Vue实例数据为 字符串
- v-model 简写,接收数据到 Vue实例属性
- 标签有value属性:v-model 收集的是 value 的值
- 标签无value属性:v-model 收集的是 null
1 | |
- 绑定 checkbox 多选框
- 正常情况标签必须添加 value属性 和 值
- 正常情况Vue实例数据为 数组
- 绑定的data数据 为 非数组
- 初始化渲染:根据数据转换的布尔值(Vue实例中数据没有实际转换),决定初始化渲染是否选中标签
- 点击多选框:修改实例数据为checked布尔值(根据是否勾选,修改vue实例数据值为布尔值)
- 绑定的data数据 为 数组
- 标签有value属性:选中标签的value值作为数组元素
- 标签无value属性:数组添加一个null元素,并全选所有标签
1 | |
双向绑定修饰符
.lazy
<input type="text" v-model.lazy="datas" />失去焦点再接收数据。默认输入数据立即改变vue实例中的数据。
.number
<input type="number" v-model.number="datas" />接收的数据转换为数值类型,等同于调用 parseInt 方法
.trim
<input type="text" v-model.trim="datas" />接收的数据清除首位空格
事件绑定
事件声明
常规:v-on:xxx = “fff”
简写:@xxx = “fff”
- xxx:事件名称
- fff:事件处理函数
1 | |
事件处理的特点
- 声明位置:事件处理函数设置在 methods对象 中
- 调用方式:事件处理函数会配置在 Vue实例 上,由 Vue实例 直接调用
- this关键字:this 指向 Vue实例 。箭头函数指向 window
参数传递
- 无参
- 元素—绑定事件
- 不需要用小括号 ( )
- 实例—定义事件
- 获取 事件对象 ,需要定义形参,第一个参数为 事件对象
- 元素—绑定事件
- 有参
- 元素—绑定事件
- 获取事件对象,需要传入关键字 $event
- 实例—定义事件
- 根据参数位置接收参数
- 元素—绑定事件
事件修饰符
使用 .xxx 修饰符,对事件进行额外功能的配置
@click.prevent="ff"
事件修饰符可以连续书写,根据顺序执行相关额外操作@keydown.stop.prevent="ff"
- prevent:阻止默认事件
- stop:阻止事件冒泡
- once:事件只触发一次
- capture:设置事件捕获模式
- self:只有 event.target 是当前元素才触发事件。(非因冒泡或捕获触发的事件)
- passive:事件的 默认行为立即执行,无需等待事件回调执行完毕
键盘事件
按下键盘任意键,触发事件
按下:keydown @keydown='ff'
弹起:keyup @keyup='ff'
按下指定键,触发事件
按键别名作为修饰符,即可指定按键触发事件 @keyup.enter="ff"
键名的注意事项
- Vue未提供别名的按键,使用按键原始名,多个单词用短横线链接
- 使用 keycode(键码) 也可以绑定指定按钮触发事件,但是使用 keycode 不建议使用
- 指定键名:Vue.config.keyCodes.自定义键名 = 键码(keycode)
Vue预定义的键名
- 回车 => enter
- 删除 => delete (删除/退格)
- 退出 => esc
- 空格 => space
- 换行 => tab (只对 keydown 键有用)
- 上 => up
- 下 => down
- 左 => left
- 右 => right
- 字母 => 字母
系统组合键,触发事件 ( ctrl、alt、shift、meta(window键) )
配置系统键和指定按键同时作为修饰符,即可设置指定组合触发事件
- keyup
- 按下系统键,并且按下其他键,然后释放其他键,事件才会触发
@keyup.alt="ff"@keyup.alt.enter="ff"
- keydown
- 按下系统键,并且按下其他键,事件就会触发
@keydown.alt="ff"@keydown.alt.enter="ff"
标签渲染
用来控制标签元素的显示方式的指令语法
条件渲染
根据指令语法值 true/false 控制元素的 显示和隐藏
v-show
根据指令值,决定元素是否进行显示
- true:显示 / false:隐藏
- 指令值会自动进行类型转换(转为 Boolean)
- 元素不被移除,只是进行隐藏,隐藏时DOM结构中也有元素,可以通过js获取到元素(等同设置css样式:display: none)
- 适合频繁操作
1 | |
v-if
根据指令值,决定元素是否进行显示
- true:显示 / false:隐藏
- 指令值会自动进行类型转换(转为 Boolean)
- 元素会被移除和添加,移除时DOM结构中没有元素,不可以通过js获取到元素
- 适合切换不频繁场合
1 | |
v-if、v-else-if、v-else
- 结构不可以被打断。(具有这些指令的元素之间不可以插入其他元素)
- 前面指令值为true,后面元素的指令将不再执行
1 | |
列表渲染 v-for
使用
v-for="(item,index) in objarr"指令语法遍历(对象、数组、字符串、数字),并根据遍历次数创建相应个数绑定元素,并接收遍历元素的相关数据
- 遍历数组
- 元素的参数
- 参数1:数组元素(只有一个参数时:数组元素)
- 参数2:数组下标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<div id="root">
<p v-for="(item,index) in name_arr" :key="index">{{item,name}}:{{item.age}}</p> <!---获取元素两个参数-->
<p v-for="item in name_arr">{{item,name}}</p> <!--获取元素单个参数-->
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
name_arr:[
{
name:"小明",
age:"19"
},
{
name:"小红",
age:"20"
}
]
}
})
</script>
- 元素的参数
- 遍历对象
- 元素的参数
- 参数1:对象属性值(只有一个参数时:对象属性值)
- 参数2:对象属性名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<div id="root">
<p v-for="(obj_value,obj_key) in name_obj" :key="obj_key">{{obj_key}}:{{obj_value}}</p> <!--获取元素两个参数-->
<p v-for="value in name_arr">{{value}}</p> <!--获取元素单个参数-->
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
name_obj:{
name1:"小明",
name2:"小红",
name3:"小兰"
}
}
})
</script>
- 元素的参数
- 遍历字符串
- 元素的参数
- 参数1:单个字符(只有一个参数时:单个字符)
- 参数2:字符下标
1
2
3
4
5
6
7
8
9
10
11
12
13<div id="root">
<p v-for="(str,index) in name_string" :key="index">{{str}}:{{index}}</p> <!--获取元素两个参数-->
<p v-for="str in name_arr">{{str}}</p> <!--获取元素单个参数-->
</div>
<script>
var vm = new Vue({
el:"#root",
data:{
name_string:"abcde"
}
})
</script>
- 元素的参数
- 遍历数字
- 元素的参数
- 参数1:从1开始的数值(只有一个参数时:从1开始的数值)
- 参数2:从0开始的下标
1
2
3
4
5
6
7
8
9
10
11<div id="root">
<p v-for="(num,index) in 5" :key="index">{{num}}:{{index}}</p> <!--获取元素两个参数-->
<p v-for="num in name_arr">{{num}}</p> <!--获取元素单个参数-->
</div>
<script>
var vm = new Vue({
el:"#root",
data:{}
})
</script>
- 元素的参数
:key属性
:key="xx"给循环遍历数据创建的节点指定一个唯一标识
只用于 Vue 内部使用,DOM结构不生成 key 属性
列表渲染的流程
- 根据key属性, 对比虚拟DOM
- 根据对比结果,决定是使用 旧真实DOM元素 ,还是 新生成DOM元素
- 根据数据生成 虚拟DOM,虚拟DOM包含 key属性
- 根据 虚拟DOM 直接生成 真实DOM
- 修改数据 之后,生成新的 虚拟DOM
- 新旧 虚拟DOM 根据 key属性 进行匹配元素
- 元素匹配上之后对比 虚拟DOM的元素的内容
- 不同的 虚拟DOM元素的内容 ,使用 新虚拟DOM 生成 新内容。 相同 虚拟DOM元素内容 ,则使用 旧的真实DOM元素的内容(虚拟DOM元素内容,可以部分生成,部分引用旧的)
- 新旧 虚拟DOM 没有匹配到具有相同 key属性 的 虚拟DOM元素 ,则使用 新虚拟DOM 生成 新真实DOM元素
不使用key属性出现的问题
- 新生成的虚拟DOM,其key属性使用的是数据下标
- 如果插入新数据,新虚拟DOM下标依旧从0开始,但是内容与旧虚拟DOM不同,因此会使用新虚拟DOM重新生成真实DOM元素
- 会使得效率低下
- 如果旧的真实DOM元素更改了内容,新真实元素部分内容引用的是旧真实元素内容,部分内容使用的是新数据内容,则对应关系发生混乱
开发中如何选择 key
- 每条数据人为设置唯一标识数据
- 如果只是显示数据,不修改数据顺序,并且不修改DOM元素内容,则没有影响
其他内置指令
内置指令,Vue预定义的指令都是内置指令
v-text
绑定数据以文本方式替换掉所在元素的内容
- 不支持结构解析:将绑定数据作为 文本内容,渲染到元素中(不会将html标签转换为DOM节点)
- 替换元素内容:会替换掉元素本来的内容
1 | |
v-html
绑定数据以html结构方式替换掉所在元素的内容
- 支持结构解析:会将具有html结构的文本数据作为 html结构,渲染到元素中(会将html标签转换为DOM节点)
- 替换元素内容:会替换掉元素本来的内容
- 安全问题
- 容易导致 XSS 攻击
- 如果是将带有html节点的文本直接渲染到页面,可以通过上传具有发送请求功能的文本标签,Vue会将此文本渲染到页面,其他用户点击此html标签,会进行跳转并获取当前页面的cookie
1 | |
v-cloak(没有值)
- 元素会添加一个 v-cloak 属性
- Vue实例创建完成并接管容器后,会删除元素上的 v-cloak 属性
配合 css属性选择器 可以在 Vue实例 接管 Vue容器 之前,隐藏显示出来的 { { xxx } } 插值语法
1 | |
v-once(没有值)
节点在初次动态渲染后,就视为静态内容,以后数据的改变不会渲染到具有 v-once 指令的元素
1 | |
v-pre(没有值)
跳过Vue对节点的编译,将节点直接渲染到页面
代码书写成什么样,就渲染成什么样,具有Vue语法也直接作为元素内容显示,不对Vue语法进行编译处理
1 | |
实例结构
el:绑定
- 实例化Vue对象时,指定参数el值
- 参数:css选择器、元素js对象
- 通过Vue实例调用 $mount() 方法,将实例与容器进行绑定
- 参数:css选择器、元素js对象
1 | |
template:模板
流程图- Vue实例解析模板流程
- 先检查是否有 “el” 配置项,没有的话调用 “vm.$mount(el)”
- 然后检查是否有 “template” 配置项
- 如果有 “template” 配置项
- “template” 配置项内容编译为渲染函数
- 使用此渲染函数生成虚拟DOM
- 如果们没有 “template” 配置项
- 使用 “el” 配置项或 “vm.$mount(el)” 的 outerHTML 生成虚拟 DOM
- 如果有 “template” 配置项
data:数据结构
- 对象
1
2
3
4
5
6var v = new Vue({
el:"#root",
data:{
...
}
}) - 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var v = new Vue({
el:"#root",
data:function(){
return {
....
}
}
/*
data()=>{
return {
...
}
}
*/
})
- 函数式data特点
- data函数式数据结构,必须 return 返回结果
- data函数式数据结构,普通函数this指向Vue实例,箭头函数this指向window
- 组件中的data数据,必须使用函数式数据结构
methods:函数
- methods 属性是个对象,用于给 Vue 实例定义方法
- methods 中定义的方法,this 指向 Vue 实例
1 | |
computed:计算属性
通过计算生成的属性。即通过 Object.defineProperty() 函数实现的 Vue实例 中的 get()/set() 属性
通用写法
1 | |
简写方式
1 | |
与函数优势
- 函数
- 只要data数据更改,就会重新解析模板,重新解析模板就会重新执行模板中使用的函数。效率低
- 计算属性
- 内部有缓存机制(复用),效率更高,只有相关操作才会触发计算属性重新执行
计算属性触发条件
- get()
- 初次读取计算属性时调用
- 依赖数据发生改变时调用
- set()
- 给计算属性赋值时调用
计算属性的特点
- vm._data 中没有计算属性,vm._data 中只有 data 中的属性,计算属性 直接添加在 Vue实例 上的,可以直接使用
- 计算属性 get()/set() 中的 this 指向 Vue实例。即可通过 this 直接获取 data 中数据
watch:监视属性
用于监视属性是否发生改变,属性发生改变时触发 handler() 监视处理函数
监视属性特点
- 也可以监视 计算属性
- this 指向 Vue实例
- computed 能完成的 watch 都能完成,但是 watch 能完成的 computed 不一定能完成
watch 对象中 配置 需要监视的属性的相关参数
- watch 配置项的值是对象
- 属性名:需要监视的数据名
- 属性值:对象。配置监视数据方式
- immediate 参数:初始就执行一次监视处理函数
- handler 参数:监视处理函数,监视属性发生改变触发此函数
- deep 参数:watch 默认 false 不监测对象属性内部数据的变化。即监视属性是对象,其属性值(对象属性的属性的属性的…)的改变不触发监视处理函数。参数设置为 true 即可监视对象属性内部数据的改变
通用写法
初始化配置
1 | |
Vue实例配置
1 | |
简写方式
初始化配置
1 | |
Vue实例配置
1 | |
filters:过滤器
过滤器 是一个预定义的函数,模板中使用 管道符 | 配置过滤器,对模板中使用的数据进行简单的处理,渲染处理后的数据
v-model 双向绑定,不能使用过滤器
- 至少设置一个形参 :形参1,固定传入需要处理的数据
- 可以不用小括号,表示不传入其他参数,默认只传入处理的数据
- 使用小括号传入其他实参,第二个形参开始指向第一个实参
- 必须有返回值 :返回值为需要渲染的数据
- 并没有改变原始数据 ,是产生新的数据
1 | |
过滤器传参
- 第二个形参指向调用处第一个实参,以此类推
- 第一个形参固定默认为需要处理的数据
1 | |
连续使用过滤器
- 连续使用 管道符 | 调用多个过滤器处理数据
- 后一个过滤器处理的数据,是前一个过滤器的返回值,以此类推
1 | |
局部过滤器和全局过滤器
- 局部过滤器:当前Vue实例中定义的过滤器,只能针对当前Vue实例的数据进行处理
- 全局过滤器:使用 Vue类函数 filter() 定义的过滤器,所有Vue实例都可以调用
1 | |
directives:自定义指令
- 自定义的指令,定义时不需要带 v-,调用时需要带 v-
- 定义指令的函数(钩子函数) this ,指向 window
- 调用时指令绑定的数据,自定义指令时由第二个形参提供
- 指令名是多个单词,定义时不能使用 驼峰式 ,必须使用 短横线
- 操作属性值,需要绑定元素属性如:
<input v-xxx:value="data">
函数形式定义
两个形参
- 形参1:指向绑定元素的DOM
- 形参2:绑定数据
自定义指令触发条件,等于同时定义 bind、update 钩子函数
- 指令与模板绑定时(内存中)
- 当Vue模板重新解析时
1 | |
对象形式定义
需要实现预定的钩子函数,在指定情况下触发相关函数
- bind:指令与元素成功绑定时(一上来)
- inserted:指令所在元素插入页面时
- update:指令所在模板重新解析时
钩子函数两个形参
- 形参1:指向绑定元素的DOM
- 形参2:绑定数据
1 | |
全局定义
Vue的类函数 directives 进行定义
1 | |
1 | |
实现原理
MVVM模型
- MVVM模型
- M 模型(Model):对应data中的数据
- V 视图(View):模板
- VM 视图模型(ViewModel):Vue实例对象
flowchart LR
A(V 视图) --> B(VM 视图模型) --> C(M 模型)
C(M 模型) --> B(VM 视图模型) --> A(V 视图)
生命周期-函数
生命周期:又名生命周期回调函数,生命周期函数,生命周期钩子
作用:Vue在特殊时刻调用的的特殊名称的函数
this:生命周期函数的 this 指向 Vue实例 或 组件实例对象
1 | |
生命周期函数分类
- 初始化
- 生命周期、事件:beforeCreate()
- 初始化Vue实例之后就打算执行(无法调用data中数据)
- 数据监测、数据代理:created()
- 初始化Vue实例之后就打算执行(可以调用data中数据)
- 生命周期、事件:beforeCreate()
- 初始化页面
- 虚拟DOM:beforeMount()
- 模板生成虚拟DOM之后就打算执行
- 渲染页面:mounted()
- 将虚拟DOM转真实DOM渲染到页面就打算执行
- 虚拟DOM:beforeMount()
- 修改数据
- 更新数据:beforeUpdate()
- 数据更新为新数据,但页面还没渲染上新数据时调用
- 渲染页面:update()
- 比较虚拟DOM,页面渲染了修改的新数据后调用
- 更新数据:beforeUpdate()
- 销毁Vue实例
- 准备销毁:beforeDestroy()
- 调用销毁Vue实例函数,但是还没有实际销毁Vue实例
- 销毁完成:destroyed()
- 实际销毁Vue实例之后调用
- 准备销毁:beforeDestroy()
可用数据
模板语法的值
- JS表达式
- Vue实例 对象中的所有属性和方法(包括 $ _ )
- 模板语法中直接使用Vue实例中的属性和方法,不需要使用Vue实例调用
Vue实例数据结构
- $ 开头的属性和函数都是给开发人员使用的数据和函数
- _ 开头的属性和函数是Vue内部使用的数据和函数,开发人员可以用但是不建议
- 实例化Vue时,传入的data数据中的所有属性,都出现在Vue实例对象上
Vue直接调用data数据原理
通过数据代理方式,Vue实现了对data数据的调用
数据代理
使用
Object.defineProperty( )函数实现数据代理
1 | |
Vue实现数据代理
- Vue实例中 _data 属性,就是实例化Vue时传入的 data 数据, _data 指向了 data
vm._data === data- 虽然
vm._data === data,但是在将 data 的值传递给 _data 之前进行了 数据劫持 , 将 data 中的数据通过 get()/set() 实现,然后将加工后的数据传递给 _data ,使得修改数据时能够进行监听,从而实时展示模板中的数据
- 虽然
- 使用 Object.defineProperty()函数 ,将 _data 数据中的每个属性通过 get()/set() 代理到 Vue实例 上
- 至此, Vue实例 就可以直接使用 data ( _data ) 中的数据,修改 Vue数据 就是修改 data ( _data ) 中的数据
1 | |
Vue监测数据改变原理
将 data 数据赋值给 _data(根数据对象) 之前,先将 data 数据中的属性都加工成了 get/set属性
因此修改数据时会调用set方法,就可以执行相关操作,监控数据的改变
不会触发数据监控的数据
即:Vue不会改造为get/set属性的数据
初始化渲染时,会将所有data中数据渲染到模板。但是因为部分类型数据没有被监视,所以后续对数据的修改,部分数据不能实时渲染到模板上
1. 不是在 data 中预定义的对象属性,而是在代码中通过Vue实例动态给 对象数据 新增的 属性(实例添加的对象属性)
1 | |
2. 数组 的 元素(数组元素本身)
- 数组元素修改不能被监测。元素不是 get/set 数据
- 数组的元素是对象,其属性修改可以被监测。对象元素内属性是 get/set 数据
1 | |
解决方法
总结:
- 数组的元素,永远不能是 get/set 形式,无法被监控(只针对数组元素本身,不针对元素的属性)
- 数组元素的添加修改,可以使用 set() 或 数组方法
- 想通过 Vue 实例添加对象属性,使用 set() 添加,此属性可以被监测
方法1:
Vue.set( )或this.$set( )(vm.$set( )),添加( 对象数据 的 属性 )或添加修改( 数组 的 元素 )Vue.delete( )或this.$delete( )(vm.$delete( )),删除 ( 对象数据 的 属性 )
不能添加修改 Vue实例上的属性数据,只能添加修改 Vue实例 的 对象/数组属性 的 属性或元素
- 对象
- 使用 set() 方法,可以添加 get/set 形式的对象数据属性 ,可以被Vue 数据监视
- 如果添加的 属性值是数组 ,则此 数组本身 是 get/set 属性,但是 数组的元素 依旧不是 get/set ,不能被数据监控
- 总结
- 通过 set() 添加的对象属性,修改时都会被监测到
- 通过 set() 添加的对象属性是数组,修改其元素不会被监测到,修改属性指向新数据可以被检测到
- 数组
- 使用 set() 方法,添加/修改元素,并不会将 数组元素 设置为 get/set,而是直接更改(添加/修改) 数组元素,并且主动执行Vue的监视和渲染功能
- 如果修改或添加的 元素是对象 , 此对象元素 不是 get/set , 依旧无法被监控,但是对象内部属性是 get/set 属性,可以被数据监控
- 不使用 set() 方法,而使用 赋值方式 修改数组的对象数据类型元素,其属性依旧不能被Vue数据监控
Vue.set()Vue.set(vm.obj,"name","小明")Vue.set(vm.arr,2,"小明")- Vue类函数
- 参数
- Vue实例的对象/数组数据
- 此对象添加的 属性名
- 此对象添加的 属性值
vm.$set()vm.$set(vm.obj,"name","小明")vm.$set(vm.arr,2,"小明")- Vue实例方法
- 参数
- Vue实例的对象/数组数据
- 此对象添加的 属性名
- 此对象添加的 属性值
方法2:使用数组方法,添加/修改 数组 的 元素
数组的方法 被重定义,调用相关方法操作数组有额外操作进行监视和渲染模板
- push
- 数组的末尾添加一个或多个元素
- 参数:一个或多个,添加到数组的元素
- 返回值:新的长度
- pop
- 删除数组的最后一个元素
- 参数:无
- 返回值:删除的元素
- shift
- 数组的第一个元素从其中删除
- 参数:无
- 返回值:移除的元素
- unshift
- 开头添加一个或更多元素
- 参数:一个或多个,添加到数组的元素
- 返回值:新的长度
- splice
- 添加或删除数组中的元素
- 参数
- 开始下标
- 删除元素个数
- 3,4,5…要添加的一个或多个元素
- 返回值
- 删除的元素的数组
- sort
- 对数组的元素进行排序
- 参数:方法
- 返回值:对数组的引用,在原数组上进行排序,不生成副本
- reverse
- 颠倒数组中元素的顺序
- 参数:无
- 返回值:对数组的引用,在原数组上进行排序,不生成副本
组件编程
组件定义:实现应用中 局部 功能 代码 和 资源 的 集合
Vue脚手架
vue脚手架即 Vue CLI(命令行接口工具)
初始化
- 全局安装
npm i @vue/cli -g
- 创建项目
- 进入创建项目的目录
vue create xxx
- 启动项目
npm run serve
项目结构
- .gitignore 文件
- git忽略文件,配置不想进行git管理的文件或目录
- babel.config.js 文件
- babel配置文件 ES6转ES5
- package-lock.json 文件
- 包版本控制文件,记录使用包的版本等信息
- package.json 文件
- 包配置文件
- README.md 文件
- 项目描述文件
- src 目录
- main.js 文件
- 项目入口文件,运行指令
npm run serve就执行此文件 
- 项目入口文件,运行指令
- app.vue 文件
- 汇总所有组件。所有组件的父组件
- assets 目录
- 存放静态资源
- component 目录
- 存放组件
- main.js 文件
- public 目录
- index.html 文件
- 主页面

- favicon.ico 文件
- 页面图标
- index.html 文件
render函数(模板解析器)
模板解析器 ,用于生成模板
- 添加Vue实例的配置项 render
- render 配置项是函数
- Vue内部调用 render配置函数,并传入一个回调函数用于 创建节点
- render配置函数 的函数体中 调用回调函数 生成 VNode对象(vue节点对象)
- render配置函数 return 返回 VNode对象(vue节点对象)
1 | |
Vue脚手架引入的Vue版本,是精简版本,此版本不包含 模板解析器,为了打包的项目精简
vue.js 和 vue.runtime.xxx.js 的区别
- vue.js是完整版的Vue,包含:核心功能+模板解析器
- vue.runtime.xxx.js 是运行版的Vue。只包含核心功能;没有模板解析器
修改默认配置
- 基于 webpack 的 vue 配置
- 查看配置:使用命令
vue inspect > output.js,根目录下会生成一个 output.js 文件,此文件就是默认配置。只能观看,修改无用 - 修改配置:根目录新建文件 vue.config.js,然后在此文件中可以对脚手架进行个性化配置。详情:https://cli.vuejs.org/zh/config/
编程方式
编程流程
- 拆分静态组件
- 组件要按功能拆分
- 命名不要与html元素冲突
- 实现动态组件
- 数据存放位置
- 一个组件用:放在组件自身
- 多个组件用:放在他们共同父组件上(状态提升)
- 数据存放位置
添加css文件
- 方法一
- css文件放入 assets 文件夹中(可定义子文件夹)
- App.vue (或个别组件)文件中用 import 引入
import "./assets/css/xxx.css"
- 方法二
- public 文件夹中放入css文件(可定义子文件夹)
- index.html 文件中用 link 标签引入css样式
<link rel="stylesheet" href="<%= BASE_URL %>css/xxx.css">
组件的原理
组件本质是一个构造函数
VueComponent()构造函数
组件流程
- 组件的本质是一个 VueComponent()构造函数
- VueComponent()构造函数 是定义组件时由 Vue.extend() 类函数 创建并返回 的
Vue.extend = function(){ return function VueComponent (){...} } - Vue解析 组件标签 时(如
<app></app>), 就会调用 VueComponent()构造函数 实例化 VueComponent实例对象new VueComponent(options) - 定义组件简写方式的流程
每次调用 Vue.extend(options),返回的都是新的 VueComponent()构造函数
this指向
- 组件配置中
- data函数结构、methods中函数、watch中函数、computed中函数 this均是 【VueComponent实例对象】
- new Vue(options) 配置中
- data函数结构、methods中函数、watch中函数、computed中函数 this均是 【Vue实例对象】
组件实例对象简称
VueComponent 组件实例对象 简称 vc。Vue实例对象 简称 vm
vm / vc 原型链
VueComponent.prototype.__proto__ === Vue.prototype
为了组件实例对象(vc)可以访问 Vue原型上的属性、方法
基础介绍
- 显示原型对象
fn.prototype- 函数 通过属性 prototype 指向的对象。因为此属性是留给程序员进行操作的,所以称为 显示原型对象
- 隐式原型对象
obj.__proto__- 对象 通过属性 proto 指向的对象。因为此属性是留给javascript底层自行查找调用的,所以称为 隐式原型对象。虽然程序员可以访问,但是不建议操作
组件的类型
非单文件组件
一个文件中有多个组件。.html 文件
组件使用步骤
- 定义组件(创建组件)
- 注册组件
- 使用组件(使用组件标签)
定义组件
组件使用 Vue.extend(options) 创建,返回的是 VueComponent()构造函数 (组件原理说明)
options 和 new Vue(options) 中的 options 有区别
- 组件定义时,不能写 el 配置项
- 所有组件都经过一个vm实例管理,由vm中的 el 配置项决定服务哪个容器
- data 必须使用函数式数据结构
- 避免组件复用时,数据被共享
- 使用 template 配置组件结构
- 组件模板只能有一个根元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26var zj = Vue.extend({
template:`
<div>
<p>{{name}}</p>
</div>
`,
data(){
return {
name:"小明"
}
}
})
//定义组件的简写形式
var zj2 = {
template:`
<div>
<p>{{name}}</p>
</div>
`,
data(){
return {
name:"小明"
}
}
}
注册组件
- 组件需要在父组件或vm实例中注册
- 注册前需要先引入组件
- 注册的是VueComponent()构造函数
(组件原理说明)
- 局部注册
new Vue({ components:{组件1:vc构造函数, 组件2:vc构造函数} })1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var zj = Vue.extend({
template:`
<div>
<p>组件内容</p>
</div>
`
})
new Vue({
el:"#root",
//局部注册
components:{
com1:zj
}
})
- 全局注册
Vue.component("组件名",vc构造函数)- 同页面多Vue实例都可以使用此组件
1
2
3
4
5
6
7
8
9
10var zj = Vue.extend({
template:`
<div>
<p>组件内容</p>
</div>
`
})
// 全局注册
Vue.component("com2",zj)
使用组件
<组件名></组件名>
1 | |
注意事项
组件命名
- 一个单词
- 首字母小写:school
- 首字母大写:School
- 多个单词
- kebab-case命名:my-school
- CamelCase命名:MySchool(需要Vue脚手架支持)
- 组件名应避免HTML已有元素名
组件标签-调用
<school></school><school/>
不使用脚手架时,<school/> 会导致后续组件不能渲染
定义组件-简写
var school = Vue.extend(options) 可以简写为 var school = options
即使简写,Vue解析 组件标签 时(如<app></app>),依旧会调用 Vue.extend() 返回 VueComponent()构造函数 并进行组件的注册,并实例化 VueComponent对象
1 | |
组件嵌套
组件中可以嵌套注册其他组件
1 | |
单文件组件
一个文件中只有一个组件。.vue 文件
单文件组件结构
<template>- 用来定义组件模板
<template>标签不参与解析
<script>- 生成VueComponent构造函数(生成组件构造函数)
- 暴露VueComponent构造函数(暴露组件构造函数)
- 生成、暴露语法可以简写
<style>- 定义组件样式
1 | |
单文件组件简写
1 | |
插槽
父组件调用子组件标签,动态给子组件模板指定的位置插入 HTML结构
<slot>插槽中可以定义 默认值 ,当没有给插入内容,则页面显示默认值<slot>插槽中可以插入 多个 HTML结构,作用域插槽 除外- 父组件插入的html结构,可以使用
<template>标签组织结构,配置具名插槽可以使用 v-slot: 替换 slot属性<template v-slot:name值> html结构 </template>
默认插槽
父组件调用子组件标签,定义子组件标签内容,内容插入到子组件模板
<slot>标签中
- 定义插槽
- 子组件模板中定义 插槽标签
<slot></slot>- 父组件将HTML结构插入到子组件的位置
- 子组件模板中定义 插槽标签
- 插入结构
- 父组件中调用 子组件标签
- 子组件标签 内容定义 html结构
1 | |
具名插槽
父组件插入的HTML结构,到子组件 name属性 指定的
<slot>标签中
- 定义插槽
- 子组件模板中定义 插槽标签
<slot></slot>- 父组件将HTML结构插入到子组件的位置
<slot>标签定义 name属性
- 子组件模板中定义 插槽标签
- 插入结构
- 父组件中调用 子组件标签
- 子组件标签 内容定义 html结构
- html结构 添加属性 slot,属性值为
<slot>标签name值
1 | |
作用域插槽
子组件中的数据交给父组件,父组件根据获取到的子组件数据 动态生成html结构
- 定义插槽
- 子组件模板中定义 插槽标签
<slot></slot>- 父组件将HTML结构插入到子组件的位置
<slot>标签添加 自定义属性- 自定义属性 用 v-bind 绑定,可用于传递不同类型数据
- 可以传递多个数据
- 可以定义 name属性
- 子组件模板中定义 插槽标签
- 插入结构
- 父组件中调用 子组件标签
- 子组件标签 内容必须定义
<template>标签 <template>标签添加属性 scope,属性值为 随意定义标识符- scope属性值 为自定义名称,数据类型为对象,此对象属性为子组件
<slot>标签上 v-bind 绑定的的所有属性 键值对 - scope属性值 可以使用 解构赋值
- slot-scope属性 等同于 scope属性,是最新语法
- slot-scope属性 可以应用在 普通html标签 上接收数据
- scope属性 只能应用在
<template>标签上接收数据
- scope属性值 为自定义名称,数据类型为对象,此对象属性为子组件
- html结构 可以直接使用 scope属性值,生成 html结构 插入子组件模板
- 同一个 子组件标签 中定义多个html结构内容,只有最后一个生效
- 获取子组件数据的html结构和普通html结构并存,则获取子组件数据的html结构插入模板
1 | |
属性-配置项
标签属性
ref:标签属性
用来给元素或子组件注册引用信息(id的替代者)
通过 Vue或父组件实例 的 $refs属性 ,可以直接获取 DOM元素 或者 子组件实例
<zi ref="xxx">子组件标签</zi>this[vm].$refs.xxx
- 应用在html标签上,获取的是真实DOM元素
- 应用在组件标签上,获取的组件实例对象(vc)
1 | |
style标签属性
scoped
让样式在局部生效,防止冲突
声明 scoped属性 后,style标签 中定义的样式只应用在当前组件的模板
样式也应用不到 子组件 上
如果<script>标签中没有定义 scoped 属性,多个组件引入到同一组件中,相同的样式的定义会发生冲突,最后引入的组件样式生效
1 | |
lang
用来定义声明样式的语言,可以是 css,也可以是预编译语言 less 等
声明了 lang 属性,必须指定值。否则不要声明 lang 属性,默认为 css 声明样式
1 | |
Vue-类函数
mixin:混入
多个组件共享同一配置项的内容
- 组件配置项和混合配置项相同,以组件配置项为准
- 生命周期函数冲突,组件配置和混合配置的生命周期共存,先执行混合配置生命周期再执行组件配置生命周期
流程
- 定义混合
- 创建一个js文件
- 定义配置项
- 暴露配置项对象
1
2
3
4export const hunru = {
data(){...},
methods:{...}
}
- 使用混合
- 全局混入:
Vue.mixin(xxx)- 打开 main.js
- 引入混合js模块
- 调用 Vue.mixin() 函数
1
2
3
4
5import {hunru} from "../mixinhr.js" //引入混合模块
import {hunru2} from "../mixinhr.js" //引入混合模块
Vue.mixin(hunru) //配置混入
Vue.mixin(hunru2) //配置混入
- 局部混入:
mixins:["xxx"]- 打开需要混入的组件
- 引入混合js模块
- 配置项添加 mixins 属性
1
2
3
4
5
6import {hunru} from "../mixinhr.js" //引入混合模块
Vue.extend({
template:`<div></div>`,
mixins:[hunru] //配置混入
})
- 全局混入:
use:插件
作用(用于增强Vue功能)
- 通过调用
Vue.use( )函数,给Vue添加额外的功能
特性
- Vue.use 会自动阻止多次注册相同插件
- 需要在调用 new Vue() 启动应用之前完成
- 参数为 Object 或 Function
- Object:必需要定义一个 install 方法
- Function:这个函数就被当做 install 方法
用法
Vue.use()参数- 参数1:对象 ,用来设置功能
- 此对象必须定义 install : function(){…} 函数
- 参数2-n:传入设置功能需要的参数,由 install 函数 2-n 形参接收
- 参数1:对象 ,用来设置功能
- install函数有两个参数
- 参数1:Vue构造函数
- 参数2-n:调用 Vue.use() 2-n 实参传入的参数
- 常用于在 main.js 文件中 实例化Vue 之前进行一些预处理,或增加一些功能
- 可以定义js模块
- 暴露 对象参数
- 在 main.js 引入
- 在 new Vue() 前执行 Vue.use()
1 | |
实例-配置项
props:组件接收数据
用于让组件接收外部传入的数据
- props 是只读的(可以被修改但是会报错,修改对象值不会监测到报错)
- props配置项 接收的数据绑定在 vc实例 上
接收数据
- 只接收数据
1
props:["name","age"] - 限制接收数据 类型
1
2
3
4props:{
name:String, //显示类型
age:Number //显示类型
} - 限制接收数据 类型 + 默认值 + 必须传入(可以不用全部配置)
1
2
3
4
5
6
7props:{
name:{
type:String, //类型
required:true, //必须传入
default:'小红' //默认值
}
}
传入数据
- 通过定义 组件 标签属性 传入数据
- 默认传入的数据都是 字符串
- 通过 v-bind 绑定属性,使属性值为表达式,可以传入任意类型的数据
1 | |
修改传入数据
- props接收的数据,优先于data中的数据
- props接收的数据 不能直接修改
- 需要复制props数据到data中,然后修改data中数据
- 接收的数据是对象,修改对象值不会被监测到所以不报错,但是依旧不建议修改
1 | |
name:组件别名
- 定义组件时配置项 name属性 ,用来修改浏览器中vue开发者工具呈现的组件名称
- 路由跳转时,组件别名 name,作为
<keep-alive>标签的 include属性 的值,用来指定需要缓存的组件 - 组件中需要调用自身,递归组件
1 | |
activated:激活
- 特有生命周期函数
- 路由跳转的组件,所特有的实例配置项
- 当组件通过路由展示出来,则触发此特别生命周期函数
1 | |
deactivated:失活
- 特有生命周期函数
- 路由跳转的组件,所特有的实例配置项
- 当组件因为路由跳转被缓存不显示,则触发此特别生命周期函数
1 | |
实例-属性(方法)
$on:绑定自定义事件
用于给 组件实例 绑定自定义事件
(跳转详细介绍)
$emit:触发自定义事件
用于触发 组件实例 上绑定的自定义事件
(跳转详细介绍)
$nextTick:执行时机
- 特有生命周期函数
- 用于修改数据渲染页面之前,修改DOM节点
问题原因
Vue不是在数据进行改变就立即解析模板,而是在虚拟DOM渲染到页面后才执行 update() 生命周期函数 (生命周期) ,所以在此之前需要对最新DOM节点的修改并不会奏效
用法
Vue实例的 $nextTick(回调函数) 方法,是在 下一次DOM更新之后执行指定回调函数
1 | |
数据传递
父子
父子间数据传递
父 -> 子
- 父组件中调用子组件标签
- 子组件标签添加自定义属性
- v-bind 绑定属性,可以传递任意类型数据,否则只能传递字符串
- 子组件中通过 props 属性接收数据
1 | |
子 -> 父
props传递函数
- 父组件中调用子组件标签
- 子组件标签添加数据属性
- 父组件数据属性通过 v-bind 绑定(作用是为了可以传递任意类型数据)
- 父组件数据属性值为 mathods 定义的 函数(接收参数,通过this将参数赋值给data定义的数据)
- 子组件中通过 props 属性接收函数
- 子组件中调用 接收函数 ,修改父组件数据
1 | |
自定义事件
自定义事件是应用在组件上的,适用于 子组件 —> 父组件 传递数据
组件绑定事件,即使绑定内置事件,Vue也默认为绑定的是 自定义事件
绑定
使用方式
- 父组件代码中:
- 父组件代码中给 子组件实例 绑定 自定义事件
- 使用 v-on 为 子组件标签 绑定 自定义名称的事件(通过标签绑定自定义事件)
- 使用 $on 为 子组件实例 绑定 自定义名称的事件(通过代码绑定自定义事件)
- 赋值一个 事件处理函数,用于接收数据
- 事件处理函数不用带括号
- 必须定义形参,用于接收数据
- 父组件代码中给 子组件实例 绑定 自定义事件
- 子组件代码中:
- 子组件实例 调用
vc.$emit()触发 自定义事件,用于发送数据,并 执行事件处理函数
- 子组件实例 调用
使用原理
- 获取 子组件实例
- 子组件实例 上绑定 自定义事件
- 子组件实例 调用 $emit() 函数,触发事件
特点
- 绑定自定事件,是为子组件实例 vc 身上绑定自定义事件
- 组件绑定事件,即使绑定内置事件,Vue也默认为绑定的是 自定义事件
- 想要使用原生事件:绑定事件添加 .native 事件修饰符
- 触发事件:
vc.$emit()- 触发绑定到组件实例 vc 身上的事件
- 参数
- 参数1:声明的自定义事件(String)
- 参数2-n:传递给事件处理函数的多个参数
- 绑定方式:
- v-on 在 组件标签 上进行绑定
- 组件实例vm 绑定
- 依旧需要先调用 子组件标签
- 子组件标签绑定 ref 属性
vm.$refs.xxx获取到子组件实例 vm- 调用
$on()方法绑定事件- 参数1:自定义的事件名称
- 参数2:声明的事件处理函数
- 只触发一次
v-on:组件标签添加 .once 修饰符$once:使用$once()方法替换$on()
- 事件处理函数:
- 绑定时传入的事件处理函数,不需要加括号( ),触发自定义事件时,事件处理函数形参依旧可以接收参数
- this
- 如果使用
$on绑定- 第二个参数定义为 匿名函数,则 this 指向 子组件实例对象
$on回调函数的 this 由调用处决定(由子组件调用)
- 第二个参数定义为 methods 中定义的函数,this 指向 父组件实例对象
- methods 中定义的函数,this 指向 当前组件实例
- 第二个参数定义为 匿名函数,则 this 指向 子组件实例对象
- 如果使用
1 | |
解绑
子组件中调用
vc.$off,即可解除 子组件实例 vc 上绑定的自定义事件
- 解绑 一个 自定义事件
vc.$off("自定义事件1")
- 解绑 多个 自定义事件
vc.$off([ "自定义事件1", "自定义事件2" ])
- 解绑 所有 自定义事件
vc.$off()
兄弟
任意传递
全局事件总线
使用 自定义事件 方式给一个 公用组件 绑定事件进行数据的传递
实现逻辑
- 打开main.js文件
- 创建共享vc实例
- 调用
Vue.extend()函数返回的是 VueComponent构造函数,需要 new 返回值,获取 vc实例
- 调用
- vm 生命周期函数 beforeCreate ,给 Vue 原型对象上绑定属性,属性为此 vc 实例
- 接收数据组件:获取共享 vc 实例,调用
$on函数,绑定自定义事件 - 传递数据组件:获取共享 vc 实例,调用
$emit函数,触发自定义事件
注意事项
- 创建共享vc实例
- 可以省略创建共享vc实例,将Vue实例 vm 绑定到 Vue原型对象 作为其属性,供所有组件调用
- 依据 vc / vm 原型链规则
- 最好在 beforeDestroy 生命周期函数中,用 $off 解绑当前组件绑定的 自定义事件
- 全局事件总线属性名,常定义为 $bus
创建全局事件总线
1 | |
使用全局事件总线
1 | |
消息订阅与发布(其他库)
使用第三方库实现数据的任意传递,其逻辑与 全局事件总线 相似,只是不是用的 共享组件
pubsub-js 第三方库
- 安装第三方库
npm i pubsub-js -S - 引入第三方库
import pubsub from "pubsub-js" - 接收数据(订阅消息)
- 使用
pubsub.subscribe()订阅消息 - 接收数据的回调函数
- 参数
- 参数1:订阅的消息名(xxx)
- 参数2-n:传递的多个数据
- this
- 自定义匿名函数:this 为 undefined
- methods 定义函数:this 为 组件实例vc
- 箭头函数:this 为 组件实例vc
1
2
3
4
5
6
7methods:{
dame(date){...} //接收数据
}
......
mounted(){
this.pid = pubsub.subscribe("xxx",this.demo) //订阅消息
}
- 参数
- 使用
- 发送数据
1
pubsub.publish("xxx",数据) //发送数据 - 取消订阅
- 最好在 deforeDestroy 生命周期函数中,用
pubsub.unsubscribe(pid)取消订阅 - pid 为订阅消息时的返回值,此值可以绑定在 vc实例 上,方便在钩子函数中接收
1
pubsub.unsubscribe(this.pid)
- 最好在 deforeDestroy 生命周期函数中,用
过渡-动画
在插入、更新、移除 DOM元素时,Vue 自动 给元素添加样式类名
原理
- Vue预定义标签:
<transition></transition> - Vue预定义类名:.v-enter、.v-enter-active、.v-enter-to、.v-eave、.v-leave-active、.v-leave-to
- 在Vue预定义的标签和类名中添加元素和样式,即可自动给元素在必要时添加移除类名
用法
- 过渡
- v-enter-active、v-leave-active 预定义类中,用于设置过渡效果
- 动画
- 只需要配置 v-enter-active、v-leave-active 预定义类的样式即可
<transition>说明
- 只能过度一个元素(只能在
<transition>中定义一个子元素) - name 属性
- 用于和样式类名关联
- 预定义类名前的 v- 改为name属性值 value-
- appear 属性
- 用于初始化页面触发过渡或动画
- 直接添加属性即可,不用赋值
<transition-group>说明
- 可以过渡多个元素(
<transition-group>中可以定义多个子元素)
类名说明
- 元素进入的样式:
- v-enter:进入的起点
- v-enter-active:进入过程中
- v-enter-to:进入的终点
- 元素离开的样式:
- v-leave:离开的起点
- v-leave-active:离开过程中
- v-leave-to:离开的终点
第三方动画库
- animate.css
- 安装
- 引入
<transition>标签中的 name 属性值设置为样式库的 类名animate__animated animate__bounce<transition>标签中添加 进入属性 enter-active-class,值为所选进入样式的 类名<transition>标签中添加 离开属性 leave-active-class,值为所选离开样式的 类名
1 | |
ajax请求
前端跨域请求,请求数据已经发送到了服务器,服务器也接收到了请求,并返回了数据,但是因为同源策略,浏览器不返回结果
发送请求的方式
- xhr
- javascript原生
new XMLHttpRequest()
- javascript原生
- jQuery
- 封装了 xhr
- Vue中不推荐用
- axios
- 封装了 xhr
- promise 风格
- 体积小
- Vue中推荐使用
- vue-resource
- 详细介绍
- Vue中的插件库
- 官方已经不再维护
- fetch
- 独立的请求方式,不依赖 xhr
- 返回数据包了两层 promise
- 兼容不好IE不适用
- Vue中不推荐使用
跨域请求的方式
- cors
- 服务端修改相应数据的响应头,使浏览器支持跨域请求
- jsonp
- script标签src属性引入外部文件不受同源策略限制
- 只能解决 get 请求
- 代理服务器
- 服务器和服务器之间的请求,不受同源策略限制
- 创建同域代理服务器
- 浏览器向代理服务器发送请求(同域请求不跨域)
- 代理服务器向目标服务器发送请求
- 代理服务器接收响应,并返回给浏览器
vue-resource
封装了ajax xhr代码,功能与 axios 相同
Vue 1.0版本使用的多,现官方已不再维护,不推荐使用
此为Vue插件库,需要通过 Vue.use() 添加此插件
添加此插件后 vm / vc 实例上就有了一个 $http 属性,用于实现ajax请求功能
- 安装vue-resource包
npm i vue-resource -S
- 打开main.js文件
- 引入 vue-resource
import vr from "vue-resource"
- 添加插件
Vue.use(vr)
- 调用请求
this.$http.get(...)this.$http.post(...)- 使用方法与 axios 相同
代理服务器
- 服务器和服务器之间的请求,不受同源策略限制
- 创建同域代理服务器
- 浏览器向代理服务器发送请求(同域请求不跨域)
- 代理服务器向目标服务器发送请求
- 代理服务器接收响应,并返回给浏览器
开启代理服务器方式
- nginx
- Vue-cli
- 开启代理服务器
- 配置目标服务器 域名、IP-端口
- ajax向代理服务器 域名、IP-端口 发送 请求地址
Vue配置方式一
配置方式
- 打开根目录下 vue.config.js 配置文件(没有的话创建)
- 添加 devServer 配置项
- 配置目标服务器 域名、IP-端口
- 重启服务器
npm run serve - ajax 请求地址的 域名、IP-端口,改为项目所在服务器 域名、IP-端口
注意事项
- 代理服务器和目标服务器有相同响应处理,则优先执行代理服务器中的响应,不再向目标服务器发送请求
- 只能添加一个代理,不能添加多个代理
1 | |
1 | |
Vue配置方式二
配置方式
- 打开根目录下 vue.config.js 配置文件(没有的话创建)
- 添加 devServer 配置项
- 配置目标服务器 域名、IP-端口
- 重启服务器
npm run serve - ajax 请求地址的 域名、IP-端口,改为项目所在服务器 域名、IP-端口(同域代理服务器)
- 需要添加 请求前缀
注意事项
- 可以定义多个代理
- 代理需配置请求前缀,匹配以请求前缀开头相同的请求路径
- ajax请求路径也需要配置请求前缀,请求前缀紧跟在端口号后,后面路径保持不变
- 需要添加 pathRewrite 配置项,修改代理服务器请求目标服务器时请求路径
1 | |
1 | |
vuex
- Vue中实现集中式状态(数据)管理的一个 Vue插件
- 对Vue应用中多个组件的共享状态 (数据) 进行 集中式的管理(读/写)
- 也是组件间的通信方式,且适合任意 组件间通信
github地址:https://github.com/vuejs/vuex
新的存储库使用pinia:https://pinia.web3doc.top/
配置方式
vue2,只能用vuex3版本
vue3,只能用vuex4版本(不写版本默认为vue3专用)
- 创建store模块
- 安装vuex
npm i vuex@3 -S
- 根目录新建 store目录
- store目录创建 index.js文件
- 暴露store实例
- 打开 store 模块
- 引入 vue 模块
import Vue from 'vue'
- 引入 vuex 模块
import Vuex from 'vuex'
- 给 Vue 添加 vuex 插件
Vue.use(Vuex)
- 配置并实例化 store 对象
- 配置:
actions:{ } - 配置:
mutations:{ } - 配置:
state:{ } - 配置:
getters:{ }
- 配置:
- 暴露 store 实例
1
2
3
4
5
6export default new Vuex.Store({
actions:{...},
mutations:{...},
state:{...},
getters:{...}
})
- Vue实例配置store属性
- 打开 main.js 文件
- 引入 store 模块
- Vue实例 配置 store属性
1
2
3
4
5
6import store from './store'
new Vue({
...
store //配置store实例
})
运行流程
修改数据有两种流程
- 组件 ——> 数据处理函数 ——> 数据修改函数
- 组件 ——> 数据修改函数
1 | |
1 | |
1 | |
基础实现
store 对象
store 对象由来
Vue中添加了Vuex插件,并配置了store配置项,则Vue实例(vm)和组件实例(vc)中都将添加一个新属性 $store,指向 store 实例对象
store 对象作用
对数据的修改和读取,都基于 store 对象,需要调用 store 中对应方法和属性
store 对象 的属性如下:
dispatch : 方法
作用
调用 actions 中定义的函数(数据处理函数),修改数据前对数据进行额外操作
案例
1 | |
用法
- 调用者
- store对象
- 参数
- 1:数据处理函数名(actions 中定义的函数名)
- 2-n:数据
commit : 方法
作用
调用 mutations 中定义的函数(数据修改函数),对 state 保存的数据进行修改
案例
1 | |
用法
- 调用者
- store对象
- 参数
- 1:数据修改函数名(mutations 中定义的函数名)
- 2-n:数据
getters : 对象
作用
调用 getters 中定义的 getter(数据加工函数),获取对 state 进行加功处理的数据
案例
1 | |
strict : 布尔值
state : 对象
作用:
- 用于获取数据
- 用于修改数据(建议在数据修改函数中修改)
本质
进行了数据劫持的 state配置项 ,属性是 getter/setter
获取数据
1 | |
修改数据
- 在 数据修改函数 的函数体中修改
- 组件实例直接调用 state属性 修改数据
- Vue开发者工具将无法获取到操作步骤
- 无法添加公用数据相关处理
1 | |
store 配置
actions
作用
定义 数据处理函数
数据处理函数
数据修改前进行额外操作
- 参数
参数1:简化的 store对象
参数2-n:调用 数据处理函数 时传入的数据 - 修改数据
函数体中调用 数据修改函数
函数体中,参数1 store对象 调用 commit方法
par1_mini_store.commit("数据修改函数名", 数据) - 增加处理功能
函数体中也可以调用其他 数据处理函数
函数体中,参数1 store对象 调用 dispatch方法
par1_mini_store.dispatch("数据处理函数名", 数据)
mutations
作用
定义 数据修改函数
数据修改函数
主要在函数体中进行数据的修改
- 参数
参数1:对 state配置项 进行了数据劫持的 state对象 ,此对象的属性都是 getter/setter
参数2-n:调用 数据修改函数 时传入的参数 - 数据变更
- 函数体变更
数据修改函数 的函数体中进行数据的修改
函数体中,参数1 state对象 直接调用数据进行修改
par1_state.xxx = yyy - 组件变更
组件实例通过 $store属性,调用 state属性,访问数据进行修改
vc.$store.state.xxx = yyy问题:
- Vue开发者工具将无法获取到操作步骤
- 无法添加公用数据相关处理
- 函数体变更
state
作用
定义 数据
getters
作用
定义 数据加工函数
数据加工函数
对 state 中定义的数据进行额外加工(等同于Vue的计算属性)
- 函数名
可以自定义任意名称
- 参数
参数1:对 state配置项 进行了数据劫持的 state对象 ,此对象的属性都是 getter/setter
- return
- 必须有返回值
- 返回值为加工了 state 中数据的返回值
1
2
3
4
5getters:{
chuli(state){
return state.xxx * 10
}
}
简化读取
调用vuex模块中暴露的相关方法,便捷的读取共享数据
mapState
作用
便捷读取 state 中定义的数据
用法
- 引入函数
import { mapState } from 'vuex'
- 组件 计算属性配置项 computed 中调用
- 调用并用ES6语法…展开
- 实参
- 对象参数
- 属性:组件中获取数据时调用的名称
- 值:需要获取 state 中的数据名
1
2
3computed : {
...mapState({ff1:"sum", ff2:"school"})
}
- 数组参数
- 元素:组件中获取数据时调用的名称 === 获取 state 中的数据名
1
2
3computed : {
...mapState(["sum", "school"])
}
- 对象参数
- 调用数据
- 组件中直接调用 对象属性名 或 数组元素值
1
2
3
4
5<zizujian>
{{ ff1 }} <!-- 属性 -->
{{ ff2 }} <!-- 属性 -->
{{ sum }} <!-- 元素 -->
</zizujian>
- 组件中直接调用 对象属性名 或 数组元素值
原理
- mapState函数 根据参数(对象属性/数组元素),生成多个函数
- 函数名
- 对象参数:属性名
- 数组参数:元素值
- 函数体
- 通过组件实例的 $store属性,获取 state,根据 属性值/元素值 获取数据,并 return 返回
1
2
3
4
5
6
7
8
9// 对象参数生成的函数
ff1(){
return this.$store.state.sum //sum 即为 【对象参数的属性值】
}
// 数组参数生成的函数
sum(){
return this.$store.state.sum //sum 即为 【数组参数的元素名】
}
- 函数名
- 生成的函数作为整体对象返回,在组件的 计算属性 配置项使用ES6语法展开,生成函数即可作为组件的计算属性直接调用
mapGetters
作用
便捷读取 getters 中定义的加工数据
用法
- 引入函数
import { mapGetters } from 'vuex'
- 组件 计算属性配置项 computed 中调用
- 调用并用ES6语法…展开
- 实参
- 对象参数
- 属性:组件中获取数据时调用的名称
- 值:需要获取 getters 中的数据名
1
2
3computed : {
...mapGetters({ff1:"sum", ff2:"school"})
}
- 数组参数
- 元素:组件中获取数据时调用的名称 === 获取 getters 中的数据名
1
2
3computed : {
...mapGetters(["sum", "school"])
}
- 对象参数
- 调用数据
- 组件中直接调用 对象属性名 或 数组元素值
1
2
3
4
5<zizujian>
{{ ff1 }} <!-- 属性 -->
{{ ff2 }} <!-- 属性 -->
{{ sum }} <!-- 元素 -->
</zizujian>
- 组件中直接调用 对象属性名 或 数组元素值
原理
- mapGetters函数 根据参数(对象属性/数组元素),生成多个函数
- 函数名
- 对象参数:属性名
- 数组参数:元素值
- 函数体
- 通过组件实例的 $store属性,获取 getters,根据 属性值/元素值 获取数据,并 return 返回
1
2
3
4
5
6
7
8
9// 对象参数生成的函数
ff1(){
return this.$store.getters.sum //sum 即为 【对象参数的属性值】
}
// 数组参数生成的函数
sum(){
return this.$store.getters.sum //sum 即为 【数组参数的元素名】
}
- 函数名
- 生成的函数作为整体对象返回,在组件的 计算属性 配置项使用ES6语法展开,生成函数即可作为组件的计算属性直接调用
简化修改
调用vuex模块中暴露的相关方法,便捷的修改共享数据
mapActions
作用
便捷调用 actions 中定义的函数(数据处理函数)
用法
- 引入函数
import { mapActions } from 'vuex'
- 组件 函数配置项 methods 中调用
- 调用并用ES6语法…展开
- 实参
- 对象参数
- 属性:组件中修改数据时调用的函数名
- 值:需要调用 actions 中定义的函数名
1
2
3methods : {
...mapActions({ff1:"jia", ff2:"jian"})
}
- 数组参数
- 元素:组件中修改数据时调用的函数名 === 调用 actions 中定义的函数名
1
2
3methods : {
...mapActions(["jia", "jian"])
}
- 对象参数
- 调用数据
- 组件中直接调用 对象属性名 或 数组元素值
- 调用生成函数,必须带小括号( ),并且传入需要修改的参数
1
2
3
4
5<zizujian>
{{ ff1(n) }} <!-- 属性 -->
{{ ff2(12) }} <!-- 属性 -->
{{ jia(n) }} <!-- 元素 -->
</zizujian>
原理
- mapActions函数 根据参数(对象属性/数组元素),生成多个函数
- 函数名
- 对象参数:属性名
- 数组参数:元素值
- 参数
- 形参1:传入需要修改的数据
- 只能定义一个形参
- 函数体
- 通过组件实例的 $store属性,调用 dispatch函数
- 参数1:根据 属性值/元素值 调用 actions 定义的相关函数
- 参数2:生成的函数的 形参1。即 actions 定义的相关函数,需要传入的数据
- 通过组件实例的 $store属性,调用 dispatch函数
1
2
3
4
5
6
7
8
9// 对象参数生成的函数
ff1(par){
return this.$store.dispatch("jia", par) //jia:【对象参数的属性值】—— par:【生成函数的形参】
}
// 数组参数生成的函数
jia(par){
return this.$store.dispatch("jia", par) //jia:【数组参数的元素名】—— par:【生成函数的形参】
}
- 函数名
- 生成的函数作为整体对象返回,在组件的 函数声明 配置项使用ES6语法展开,生成函数即可作为组件的自定义函数直接使用
mapMutations
作用
便捷调用 mutations 中定义的函数(数据修改函数)
用法
- 引入函数
import { mapMutations } from 'vuex'
- 组件 函数配置项 methods 中调用
- 调用并用ES6语法…展开
- 实参
- 对象参数
- 属性:组件中修改数据时调用的函数名
- 值:需要调用 mutations 中定义的函数名
1
2
3methods : {
...mapMutations({ff1:"JIA", ff2:"JIAN"})
}
- 数组参数
- 元素:组件中修改数据时调用的函数名 === 调用 mutations 中定义的函数名
1
2
3methods : {
...mapMutations(["JIA", "JIAN"])
}
- 对象参数
- 调用数据
- 组件中直接调用 对象属性名 或 数组元素值
- 调用生成函数,必须带小括号( ),并且传入需要修改的参数
1
2
3
4
5<zizujian>
{{ ff1(n) }} <!-- 属性 -->
{{ ff2(12) }} <!-- 属性 -->
{{ JIA(n) }} <!-- 元素 -->
</zizujian>
原理
- mapMutations函数 根据参数(对象属性/数组元素),生成多个函数
- 函数名
- 对象参数:属性名
- 数组参数:元素值
- 参数
- 形参1:传入需要修改的数据
- 只能定义一个形参
- 函数体
- 通过组件实例的 $store属性,调用 commit函数
- 参数1:根据 属性值/元素值 调用 mutations 定义的相关函数
- 参数2:生成的函数的 形参1。即 mutations 定义的相关函数,需要传入的数据
- 通过组件实例的 $store属性,调用 commit函数
1
2
3
4
5
6
7
8
9// 对象参数生成的函数
ff1(par){
return this.$store.dispatch("JIA", par) //JIA:【对象参数的属性值】—— par:【生成函数的形参】
}
// 数组参数生成的函数
JIA(par){
return this.$store.dispatch("JIA", par) //JIA:【数组参数的元素名】—— par:【生成函数的形参】
}
- 函数名
- 生成的函数作为整体对象返回,在组件的 函数声明 配置项使用ES6语法展开,生成函数即可作为组件的自定义函数直接使用
模块化+命名空间
作用
让代码更好维护,多种数据可以分类管理
说明
模块化:创建不同文件,各自配置 store实例 中需要的相关配置项,然后暴露出来
命名空间:store目录 的 index.js 文件引入各配置文件,并为其定义命名空间名称
配置文件
新建配置文件
- 新建独立js文件
- 暴露对象数据,即
new vuex.Store({})传入的配置对象 - 定义 namespaced:true 属性
1 | |
引入配置文件
- store目录 下的 index.js文件 中引入配置模块
new Vuex.Store({...})配置项添加 modules 对象属性- modules 中为配置数据定义命名空间
1 | |
调用
读取 state 数据
1 | |
读取 getters 数据
1 | |
使用 dispatch函数 调用 actions 定义的数据处理函数
1 | |
使用 commit函数 调用 mutations 定义的数据处理函数
1 | |
路由
路由说明
什么是路由
- 一个路由就是一组映射关系(key - value)
- key 为路径, value 可能是 function 或 componen
- 路由器:是对多个路由的管理
路由分类
- 前端路由:
- 理解:value 是 component,用于展示页面内容。
- 工作过程:当浏览器的路径改变时, 对应的组件就会显示。
- 后端路由:
- 理解:value 是 function, 用于处理客户端提交的请求。
- 工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据。
vue-router 说明
什么是 vue-router
vue 的一个插件库,专门用来实现 SPA 应用
什么是 SPA 应用
- 单页 Web 应用(single page web application,SPA)。
- 整个应用只有一个完整的页面(一个index.html页面)。
- 点击页面中的导航链接不会刷新页面,只会做页面的局部更新。
- 数据需要通过 ajax 请求获
配置方式
vue2,只能用vue-router3版本
vue3,只能用vue-router4版本(不写版本默认为vue3专用)
- 安装 vue-router 包
npm i vue-router@3 -S
- 新建 router 模块
- 根据目录新建 router 目录
- router 目录 中新建 index.js 文件
- 配置 router 模块
- 引入 vue-router
- 引入自定义组件
- 创建路由器
- 暴露路由器
- 配置路由规则
1 | |
- 配置 router 模块
- 打开 main.js 文件
- 引入 vue-router 库
- 引入 router 模块
- 应用 vue-router 插件
- 添加 Vue 实例配置项 router 属性为 router 模块
1 | |
基础实现
不需要引入组件
希望路由展示组件并进行切换,组件中不需要引入其他希望展示的组件,只需要使用 roter-link router-view 就可以实现
路由切换
使用 <router-link></router-link> 标签实现路由的切换
- to 属性:配置路由路径
- active-class 属性:配置class样式名,切换到的路由应用此配置的样式
1 | |
路由呈现
使用 <router-view></router-view> 标签实现路由切换时组件显示位置
1 | |
路由特点
- 路由组件通常放在 pages 目录加中,一般组件通常放在 components 目录中
- 通过切换,“隐藏”的路由组件,默认是被销毁掉的,“显示”的路由组件,是重新挂载的
- 每个组件都有 $route 属性,里面存储着自己的路由信息,每个组件都不同
- 每个组件都有 $router 属性,指向同一个对象
增强功能
初始化展示
将路由规则配置项中,path 属性值设置为 “/“,初始打开页面时, router-view 默认显示此路由规则中组件
1 | |
路由重定向
路由规则配置项中,添加 redirect 属性,值为需要重定向的规则的 path 字符串
1 | |
多级路由
- 路由对象中,添加 children 数组属性
- children 中添加多个路由对象,作为子级路由
- 子级路由路径,不可以加 /
- 路由切换时,to 属性值需要加上父级路由路径
1 | |
跳转方式
- 通过 路由路径字符串 进行跳转
<router-link>标签的 to 属性值,配置为 路由路径 字符串1
<router-link to="/about">跳转</router-link>
- 通过 路由路径对象 进行跳转
<router-link>标签的 to 属性值- 使用 v-bind 进行绑定
- 配置为 路由配置 对象
- 定义 path属性 为 路由路径 字符串
1
2
3
4
5
6
7<router-link
:to="{
path:'/home/school'
}"
>
跳转
</router-link>
命名路由
作用
- 简化路由跳转
<router-link :to=“{...}”>标签配置方式 - 定义路由守卫时,判断所选组件
用法
- 给定义的路由配置项添加 name 属性
- 方便
<route-link>to属性 通过 路由路径对象 方式的 name属性 进行跳转
1 | |
1 | |
传递参数
query 参数
格式
- 参数以 urlencoded 编码格式进行声明
?name=老刘&age=18
发送
- 路由路径字符串
<router-link>标签的 to 属性- 使用 路由路径 字符串
- 并添加 urlencoded 编码格式 参数
1
<router-link to="/home/school?id=66&name=小明">跳转</router-link>
- 路由路径对象
<router-link>标签的 to 属性- 使用 v-bind 绑定
- 使用 路由路径对象
- 使用 name属性 或 path属性 配置跳转
- 添加 query 对象,对象中属性 为传递的参数
1
2
3
4
5
6
7
8
9
10
11
12<router-link
:to="{
path: '/home/school',
//name: 'xiangqing'
query:{ //query 属性
id : 66,
name :'小明'
}
}"
>
跳转
</router-link>
接收
- 通过 组件实例 的 $route属性 的 query属性 获取数据
1
2
3mounted(){
console.log( this.$route.query.xxx )
} - 通过组件 props 配置项接收数据
- 路由配置对象 添加 props属性
- 属性值:对象
- 该对象中的所有属性,直接传递给组件的 props
- 只能传递静态数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:{id:111,name:"小明"} //对象
}
]
}
]
})
- 属性值:true
- 只能接收 params参数,即:通过 /xxx/yyy 传递的参数
- 将接收数据传递给组件的 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:true // true
}
]
}
]
})
- 属性值:函数
- 形参:组件的 $route 对象
- 必须定义对象返回值
- 可接收 query参数 和 params参数
- 返回对象的属性传递给组件 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:function(route){
return { // 接收 query 方式传递的数据
id:route.query.id,
name:route.query.name
}
/*
return { // 接收 params 方式传递的数据
id:route.params.id,
name:route.params.name
}
*/
}
}
]
}
]
})
- 属性值:对象
- 路由配置对象 添加 props属性
params 参数
格式
- 参数以 路由格式 方式进行传递参数
/老刘/18
配置
- 使用 路由路径对象 方式发送,路由配置项中,必须定义 name属性
- 路由配置项中 path属性 中,希望接收参数的地方使用 :xxx 占位符进行占位
1 | |
发送
- 路由路径字符串
<router-link>标签的 to 属性- 根据配置项中占位位置,给 路由路径 字符串后添加数据
- 添加动态数据
- v-bind 绑定 to属性
- ES6模板字符串,给 路由路径 字符串后添加数据
1
2
3
4
5<!-- 传递静态数据 -->
<route-link to="/home/school/66/小明">跳转</route-link>
<!-- 传递动态数据 -->
<route-link :to="`/home/school/${m.id}/${m.name}`">跳转</route-link>
- 路由路径对象
<router-link>标签的 to 属性- 使用 v-bind 绑定
- 使用 路由路径对象
- 只能使用 name属性 配置跳转
- 添加 params 对象,对象中属性 为传递的参数
1
2
3
4
5
6
7
8
9
10
11<router-link
:to="{
name: 'xiangqing', //只能使用name配置跳转
params:{ //params 属性
id : 66,
name :'小明'
}
}"
>
跳转
</router-link>
接收
- 通过 组件实例 的 $route属性 的 params属性 获取数据
1
2
3mounted(){
console.log( this.$route.params.xxx )
} - 通过组件 props 配置项接收数据
- 路由配置对象 添加 props属性
- 属性值:对象
- 该对象中的所有属性,直接传递给组件的 props
- 只能传递静态数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:{id:111,name:"小明"} //对象
}
]
}
]
})
- 属性值:true
- 只能接收 params参数,即:通过 /xxx/yyy 传递的参数
- 将接收数据传递给组件的 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:true // true
}
]
}
]
})
- 属性值:函数
- 形参:组件的 $route 对象
- 必须定义对象返回值
- 可接收 query参数 和 params参数
- 返回对象的属性传递给组件 props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28export default new VueRouter({
routes:[ // 配置路由规则
{
path:"/home", // 配置路由路径
component:Home, // 配置路由组件
children:[
{
path:"school",
component: School,
props:function(route){
return { // 接收 query 方式传递的数据
id:route.query.id,
name:route.query.name
}
/*
return { // 接收 params 方式传递的数据
id:route.params.id,
name:route.params.name
}
*/
}
}
]
}
]
})
- 属性值:对象
- 路由配置对象 添加 props属性
router-link 标签
使用 <router-link></router-link> 标签实现路由的切换
属性介绍:
- to
- 配置路由路径 字符串/对象
<router-link :to="...">跳转</router-link>
- active-class
- 配置class样式名,切换到的路由应用此配置的样式
<router-link active-class="classname">跳转</router-link>
- replace
- 配置路由跳转时,浏览器历史记录的模式
- push 模式
- 追加历史记录
- replace 模式
- 替换当前历史记录
- 标签的默认模式
- push 模式
<router-link replace>跳转</router-link>
- 配置路由跳转时,浏览器历史记录的模式
编程触发路由
不借助 <router-link> 实现路由跳转
实现方式
- 组件调用 $router 属性,即可调用相关方法进行路由跳转
- $router 即为路由器,所有组件共享同一路由器对象
相关方法
- push:方法
- 追加历史记录,进行路由跳转
- 参数:
<router-link>标签的 路由路径对象 配置方式一致 this.$router.push({ 路由路径对象 })
- replace:方法
- 替换当前历史记录,进行路由跳转
- 参数:
<router-link>标签的 路由路径对象 配置方式一致 this.$router.replace({ 路由路径对象 })
- back:方法
- 后退一个历史记录
this.$router.back()
- forward:方法
- 前进一个历史记录
this.$router.forward()
- go:方法
- 后退、前进 指定个数历史记录(数字正负决定前进、后退)
this.$router.go(-3)
缓存路由组件
作用
组件跳转会注销组件,使用 <keep-alive> 包裹显示组件 <router-view> ,就可以让组件保留在内存不被销毁,输入的内容也会暂存在内存
用法
- 在
<router-view>组件外层,包裹组件<keep-alive>- 缓存所有路由跳转的组件
<keep-alive>组件添加 include 属性- 指定需要缓存的组件,其他组件切换时依旧会销毁
- 属性值:
- 组件定义时的配置项 name属性
- 字符串:
- 缓存单个组件
- 单个组件别名字符串
- 正则表达式
- 数组:
- 缓存多个组件
- v-bind 绑定 include 属性
- 数组元素定义组件别名字符串
- 组件实例name配置项
<keep-alive>组件添加 exclude 属性- 指定的组件不会缓存,其他组件正常缓存
- 属性值:与 include 一样
1 | |
路由生命周期
路由组件所独有的两个钩子,用于捕获路由组件的激活状态,必须配合 keep-alive 组件使用,router-view 没有被 keep-alive 包裹,没有办法触发activated 和 deactivated 生命周期函数
- activated:路由组件被激活时触发 详细解释
- 通过路由第一次显示的组件:显示的组件的钩子函数触发顺序 created-> mounted-> activated
- 通过路由再次显示其他组件:显示的组件只触发 activated
- 不管组件是不是从缓存中显示
- deactivated:路由组件失活时触发 详细解释
- 通过路由组件被缓存不再显示时,当前组件 deactivated 触发
路由守卫
- 路由跳转前后
- 用于进行的相关处理
- 对路由权限进行控制
路由守卫执行顺序
- 全局前置路由守卫:最先执行的是 beforeEach 钩子,所有路由开始的时候最先执行
- 独享路由守卫:然后就是路由器中,路由规则 router 配置项中的 beforeEnter 方法
- 进入守卫:接下来就是 beforeRouteEnter,组件内定义的进入守卫
- 离开守卫:最后是 beforeRouteLeave,组件内定义的离开守卫
全局前置路由守卫
作用
- 路由跳转到目标路由之前
- 对跳转进行处理
- 对路由权限进行控制
触发条件:
- 初始化的时候
- 路由跳转到目标路由之前
用法
路由器对象 的 beforeEach 方法实现跳转前控制
- 路由器模块中实例化 路由器对象
- 路由器对象 调用 beforeEach 方法
- beforeEach 方法参数为 回调函数
- 回调函数的参数
- 参数1:to:
- 要 跳转到 的路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数2:from:
- 当前 路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数3:next:
- beforeEach 回调函数体中执行此函数
next(),则正常跳转 - 函数
- beforeEach 回调函数体中执行此函数
- 参数1:to:
1 | |
全局后置路由守卫
作用
- 路由跳转到目标路由之后
- 进行相关处理
- 对路由权限进行控制
触发条件:
- 初始化的时候
- 路由跳转到目标路由之后
用法
路由器对象 的 afterEach 方法实现跳转前控制
- 路由器模块中实例化 路由器对象
- 路由器对象 调用 afterEach 方法
- afterEach 方法参数为 回调函数
- 回调函数的参数
- 全局后置路由守卫,回调函数,没有第三个参数 next
- 参数1:to:
- 要 跳转到 的路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数2:from:
- 当前 路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
1 | |
独享路由守卫
- 对某个路由进行单独配置
- 此路由跳转前进行相关处理
- 对此路由进行权限控制,是否进行跳转
独享路由守卫可以和全局后置路由守卫一同使用
用法
路由配置项添加 beforeEnter函数 进行配置独享路由守卫
- 路由配置象中添加 beforeEnter函数
- beforeEnter函数 参数
- 参数1:to:
- 要 跳转到 的路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数2:from:
- 当前 路由组件的相关信息组成的对象
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数3:next:
- 函数体中执行此函数
next(),则正常跳转 - 函数
- 函数体中执行此函数
- 参数1:to:
1 | |
组件内路由守卫
组件实例配置项中进行配置
- 进入守卫
- beforeRouteEnter函数
- 通过路由规则,进入该组件时被调用
- 离开守卫
- beforeRouteLeave
- 通过路由规则,离开该组件时被调用
用法
组件实例配置项 中,定义 beforeRouteEnter (进入) 和 beforeRouteLeave (离开) 函数
参数:
- 参数1:to:
- 要 跳转到 的路由组件的相关信息组成的对象( beforeRouteEnter函数 表示当前组件)
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数2:from:
- 当前 路由组件的相关信息组成的对象( beforeRouteEnter函数 表示跳转来的组件)
- 对象
- name
- 组件路由别名
- path
- 组件路由路径
- meta
- 可以自定义的路由配置项验证数据
1
2
3
4
5
6
7
8
9
10
11
12
13new VueRouter({
routers:[
{
name:"xuexiao",
path:"/school",
component:School,
meta:{ // 自定义路由守卫可以验证的数据
yz:true,
sj:"123"
}
}
]
})
- 可以自定义的路由配置项验证数据
- name
- 参数3:next:
- 函数体中执行此函数
next(),则正常跳转 - 函数
- 函数体中执行此函数
1 | |
路由模式
用于设置页面跳转时,url的展示形式
页面中路由跳转时,并不向服务端重新请求页面,而是通过JS代码实现页面切换,因此 url 路径为 前端路由路径,与服务端无关
名词解释
| 名词 | 解释 |
|---|---|
| hash(哈希) | url路径 # 及之后的内容统称为 hash(哈希) http://localhost:8080/#/home/message |
| history | 标准的 url 路径 |
实现方式
- 路由器实例化时,添加 mode 配置项
- mode 配置项值为 hash 或 history 字符串
1 | |
模式区别
hash 模式
- hash 值,不会包含在HTTP请求中,即:hash 值不会发送给服务器
- 如果通过第三方手机APP分享,可能被标记不合法
- 兼容性好
history 模式
- 地址干净,美观
- 兼容性略差
- 应用部署上线时需要后端人员支持,解决页面刷新报404问题
- 在页面路由跳转时,并不向服务端重新请求页面,因此 url 路径只是用于 前端路由,当通过路由跳转后的页面再次刷新时会将当前 ulr 发送给服务端请求页面,因此报404错误(因为路由 url 展示形式是标准的 HTTP 请求路径,因此刷新会发送请求)
webStorage:数据存储
javascript原生存储方式,将数据存储在浏览器
- 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)
- 浏览器通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制
- 存储的数据只能是字符串
- 相关API(两者一样):
- 存储
xxxxxStorage.setItem("key","value")- 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应值
- 获取
xxxxxStorage.getItem("key")- 该方法接收一个键名作为参数,返回键名对应的值
- 找不到该数据,则返回 null
- 删除
xxxxxStorage.removeItem("key")- 该方法接受一个键名作为参数,并把该键名从存储中删除
- 清空
xxxxxStorage.clear()- 该方法会清空存储中的所有数据
- 存储
- 存储时长
- sessionStorage 存储的内容会随着浏览器窗口关闭而消失
- localStorage 存储的内容,需要手动清除才会消失
