vue基础

v-bind : 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)

虚拟DOM和Diff算法复用DOM

DOM是浏览器把 HTML 页面解析成的对象结构

如果用原生js操作dom

浏览器会:

  1. 删除原 DOM
  2. 重新创建 DOM
  3. 重新渲染页面

操作 非常慢,因为涉及重新计算布局和重新绘制页面,所以频繁更新 DOM 性能很差。

然后就有了虚拟dom

用 JavaScript 对象来描述真实 DOM

Diff 算法就是:

比较两个虚拟 DOM 的差异

DOM复用意思是:

数据没变的DOM节点继续使用,不重新创建

Vue Diff 时会用 key

1
<li v-for="item in list" :key="item.id">

MVVM

MVVM 是 Vue 的核心架构模式,其中:

  • Model 表示数据模型(data)
  • View 表示视图(HTML页面)
  • ViewModel 表示视图模型(Vue实例)

ViewModel 作为 View 和 Model 的桥梁,实现:

  • 数据驱动视图
  • 双向数据绑定

当数据发生变化时,ViewModel 会自动更新视图;当用户操作视图时,数据也会同步更新,从而实现视图与数据的自动同步。

版本

目前主流是vue2和3

核心区别

响应式原理不同
Vue2 使用 Object.defineProperty 来监听数据变化,而 Vue3 使用 Proxy
Proxy 功能更强,可以监听对象新增属性和数组变化,因此 Vue3 的数据响应更完善。

API 写法不同
Vue2 主要使用 Options API(如 datamethodscomputed 等)。
Vue3 新增了 Composition API(如 setuprefreactive),代码结构更加灵活,更适合大型项目开发。

开发环境

使用火狐导入插件

image-20260309145217150

英文官网: https://vuejs.org/

中文官网: https://cn.vuejs.org/

Introduction — Vue.js

image-20260309145528132

引入

image-20260309145553020

简单例子

image-20260309153506086

比如这个

两部分把容器和实例建立连接 但此时这个是写死的

如果我们想方便的更改 引入data

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 准备好一个 Vue 要控制的容器区域 -->
<div id="app">
<h1>Hello World</h1>
<!-- 将数据放入页面中使用插值表达式即‘{{ 对应数据的key }}’ -->
<h1>Hello {{ name }}</h1>
</div>

<!-- 引入下载的 vue -->
<script src="./js/vue.js"></script>
<!-- 使用CDN引入 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> -->
<script>
// 设置为 false 以阻止 vue 在启动时生成生产提示。
Vue.config.productionTip = false

// 创建一个 Vue 实例对象
// Vue 构造函数中传入的参数为配置对象
const app = new Vue( {
// element -- el Vue实例对象要控制的容器
// el 的值为 css 选择器( id 选择器 / 类选择器 )
// 填入 js 的选择标签对象的方法也行
// el: document.getElementById('app')
// 一般写 css 选择器, 简单
el: '#app',
// data 用于存放页面的数据
// data 中的数据供 el 所指向的容器使用
// data 的值先写为对象(后面会写为函数, 后面会介绍)
data: {
// 数据为键值对
name: '张三'
}
} )
</script>
</body>
</html>

image-20260309153720493

Vue实例和容器是一 一对应的

image-20260309160049716

image-20260309160102291

1. Object.defineProperty()方法

该方法用于给对象添加属性

1
Object.defineProperty() 

需要传入三个参数:

  1. 需要进行属性添加的对象 2. 将要添加到对象的新属性名 3. 配置对象,在配置对象中可以指定新属性的值

使用Object.defineProperty()向对象中添加属性

1
2
3
4
5
6
7
8
9
10
11
12
<script>
let person = {
name: 'zs',
sex: 'male'
}
// 向person对象中新添加一个age属性
Object.defineProperty(person, 'age', {
value: 18
})
console.log(person)
</script>

默认情况下,使用Object.defineProperty()添加的属性的值是不可以修改的。

要使Object.defineProperty()添加的属性值可以修改,在添加属性时,配置对象的 writable 的值设置为 true,使用Object.defineProperty()添加的属性值可以修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
let person = {
name: 'zs',
sex: 'male'
}
// 向person对象中新添加一个age属性
Object.defineProperty(person, 'age', {
value: 18,
// enumerable 控制属性是否可以枚举,默认值为 false
enumerable: true,
// 控制属性值是否可以被修改,默认值为 false
writable: true
})

</script>

默认情况下,使用Object.defineProperty()添加的属性的值是不可以删除的。

要使Object.defineProperty()添加的属性值可以删除,在添加属性时,配置对象的 configurable 的值设置为 true,使用Object.defineProperty()添加的属性值可以删除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
let person = {
name: 'zs',
sex: 'male'
}
// 向person对象中新添加一个age属性
Object.defineProperty(person, 'age', {
value: 18,
// enumerable 控制属性是否可以枚举,默认值为 false
enumerable: true,
// 控制属性值是否可以被修改,默认值为 false
writable: true,
// 控制属性是否可以被删除,默认值为 false
configurable: true
})

</script>

向对象中新添加的属性赋值为另外定义的变量,当变量的值发生改变时,对象中的新属性值也会对应的发生变化。

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
28
29
30
31
32
33
34
 <script>
let number = 18
let person = {
name: 'zs',
sex: 'male'
}
// 向person对象中新添加一个age属性
Object.defineProperty(person, 'age', {
// value: 18,
// // enumerable 控制属性是否可以枚举,默认值为 false
// enumerable: true,
// // 控制属性值是否可以被修改,默认值为 false
// writable: true,
// // 控制属性是否可以被删除,默认值为 false
// configurable: true

// 当读取person的age属性的时候,get函数(getter)会被调用,且返回值就是age的值
// get: function() {
// console.log('读取age属性')
// return number
// }
// 简写
get() {
console.log('读取age属性')
return number
},

// 修改person的age属性的时候,set函数(setter)会被调用,且会收到修改的具体值
set(value) {
console.log('修改了age的属性值:', value)
}
})
</script>

Vue 2 的数据代理机制

Vue 2 核心就是 响应式系统,实现方式是:

  1. Vue 初始化时,会遍历 data 对象的每个属性。
  2. 对每个属性使用 Object.defineProperty() 定义 getter 和 setter。
  3. getter 用来依赖收集(知道哪些模板用到了这个属性)。
  4. setter 用来派发更新(属性变化时自动刷新 DOM)。

事件

vue 提供了v-on:事件绑定指令,用来辅助程序员为DOM元素绑定事件监听。

原生的DOM对象有onclickoninput等原生事件,在vue中可以使用v-on:clickv-on:input等来监听DOM元素的对应事件,并为其绑定相应的事件处理函数,其中事件处理函数需要在vue实例对象的methods节点中进行声明。

v-on: 简写为 @

基本的

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
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h1>Hello {{name}}!</h1>
<!-- 监听按钮的点击事件,同时为其绑定事件处理函数 show1 -->
<button v-on:click="show1">提示信息1</button>
<!-- 监听按钮的点击事件,同时为其绑定事件处理函数 show1 -->
<button @click="show2">提示信息2</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#root',
data: {
name: 'zs'
},
methods: {
show1() {
alert('你好!')
},
show2() {
alert('你好!!')
},
},
})
</script>
</body>
</html>

计算属性

插值语法实现

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
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 准备容器 -->
<div id="root">
姓:<input type="text" v-model="firstName"> <br><br>
名:<input type="text" v-model="lastName"> <br><br>
姓名:<span>{{firstName}}-{{lastName}}</span>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
el: '#root',
data: {
firstName: '张',
lastName:'三'
}
})
</script>
</body>
</html>

计算属性实现

计算属性,即使用原有的data 中的属性进行处理,处理后生成新的属性。

在vue 中,计算属性写在配置项computed中,配置项 computed需要书写成对象形式。

如果要使用计算属性,那么需要在计算属性中实现get()方法

多次使用计算属性,计算属性只会计算一次,因为计算属性会将计算的结果进行缓存。(前提计算属性所依赖的数据不发生变化,依赖的数据变化计算属性会重新进行计算)

相对于methods,计算属性的效率更高,因为methods不存在缓存,所以每次调用方法,方法都会重新执行一次,而计算属性只要依赖的数据不发生变化,计算属性的计算过程只有在第一次读取时执行。

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
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 准备容器 -->
<div id="root">
姓:<input type="text" v-model="firstName"> <br><br>
名:<input type="text" v-model="lastName"> <br><br>
姓名:<span>{{ fullName }}</span>
</div>
<!-- 引入vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#root',
data: {
firstName: '张',
lastName:'三'
},
computed: {
// 由于计算属性的处理可能很复杂,所以写成对象的形式
fullName: {
// 当计算属性被读取时,get函数会被调用,且返回值作为计算属性的值
get() {
console.log('get被调用')
return this.firstName + '-' + this.lastName
}
}
}
})
</script>
</body>
</html>

监视属性

handler()为属性侦听器的回调函数,当被监视的属性值变化时,回调函数会自动调用,进行相应的处理

1
2
3
4
5
6
7
8
9
watch: {
isHot: {
// 当被监视的属性值变化时,回调函数会自动调用,进行相应的处理
handler() {
console.log('isHot被修改了')
}
}
}

当被监视的属性值变化时,回调函数会自动调用,进行相应的处理,同时会向处理函数传入两个参数,第一个参数为改变后的值,第二个参数修改之前的值。

immediate 默认值为false

immediate的值设置为true,初始化数据元素时,立即调用属性侦听器的回调函数handler()。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h2>今天天气很{{info}}</h2>
<button @click="isHot = !isHot">切换天气</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#root',
data: {
// 标记天气是否炎热
isHot: true
},
computed: {
info() {
return this.isHot ? '炎热' : '凉爽'
}
}
})

// 使用vue实例监视属性必须保证vue实例已经创建完成
// 调用$watch()方法实现
// 第一个参数为需要进行监视的属性名
// 第二个参数为对应的配置项
vm.$watch('isHot', {
// 初始化时,立即调用handler()
immediate: true,
// 当被监视的属性值变化时,回调函数会自动调用,进行相应的处理
handler(newVal, oldVal) {
console.log('isHot被修改了', '新的值为:', newVal, '旧的值为:', oldVal)
}
})
</script>
</html>

深度监视

实现深度监视使用deep,默认值为false。vue提供的属性侦听器默认不能监视多级结构中某个属性的变化。

开启深度监视,能够监视多级结构中某个属性的变化。

vue自身可以监测对象内部值的改变,即vue能够监视多级结构中某个属性的变化,但是vue提供的watch默认不可以。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h2>a的值:{{num.a}}</h2>
<button @click="num.a++">点击使a加一</button>
<h2>b的值:{{num.b}}</h2>
<button @click="num.b++">点击使b加一</button>
<br><br>
<button @click="num = {a: 666, b: 888}">点击修改num的值</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#root',
data: {
isHot: true,
num: {
a: 1,
b: 2
}
},
watch: {
// 监视num,当num里面的值修改了也视为num改变
num: {
deep: true,
handler(newVal, oldVal) {
console.log('num被修改了')
}
}
}
})
</script>
</html>

computed和watch之间的区别:
computed能完成的功能,watch都可以完成
watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个重要的小原则:
所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vue实例对象或 组件实例对象
所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vue实例对象或 组件实例对象。

Vue监视数据的原理

vue会监视data中所有层次的数据。
如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
3.对于不会修改原数组的方法,如:filter()、concat() 和 slice(),它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组
特别注意:Vue.set() 和 vm.$set() 不能给 vm 或 vm的根数据对象 添加属性 ! ! !

收集表单数据

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>收集表单数据</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<!-- 阻止表的的默认事件 -->
<form @submit.prevent="demo">
<!-- v-model.trim 去除用户输入的两端的空白字符 -->
账号:<input type="text" v-model.trim="userInfo.account" /> <br /><br />
密码:<input type="password" v-model="userInfo.password" /> <br /><br />
<!-- type="number" 只允许输入数字, v-model.number 将输入的内容的数据类型转为数字类型 -->
年龄:<input type="number" v-model.number="userInfo.age" /> <br /><br />
性别: 男<input type="radio" name="sex" v-model="userInfo.sex" value="male" /> 女<input type="radio" name="sex" v-model="userInfo.sex" value="female" /> <br /><br />
爱好: 学习<input type="checkbox" v-model="userInfo.hobby" value="study" /> 打游戏<input type="checkbox" v-model="userInfo.hobby" value="game" /> 吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat" /> <br /><br />
所属校区
<select v-model="userInfo.city">
<option value="">请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
<option value="wuhan">武汉</option>
</select>
<br /><br />
其他信息:
<!-- v-model.lazy 在失去焦点时才进行数据的更新 -->
<textarea v-model.lazy="userInfo.other"></textarea> <br /><br />
<input type="checkbox" v-model="userInfo.agree" />阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
<button>提交</button>
</form>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false

new Vue({
el: '#root',
data: {
// 将用户信息写成对象形式
userInfo: {
account: '',
password: '',
age: 18,
sex: 'female',
hobby: [],
city: 'beijing',
other: '',
agree: '',
},
},
methods: {
demo() {
// 显示用户信息
console.log(JSON.stringify(this.userInfo))
},
},
})
</script>
</html>


若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤

过滤器

在 filters 节点中定义过滤器。

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
28
29
30
31
32
33
34
35
36
37
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset= "UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h1>时间戳转换</h1>
<h2>当前时间的时间戳:{{time}}</h2>
<!-- 通过管道符调用过滤器 -->
<h2>当前时间:{{time | getDateTime}}</h2>
</div>
</body>
<!-- 导入day.js -->
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
const vm = new Vue({
el: '#root',
data: {
// 当前时间的时间戳
time: Date.now()
},
filters: {
// 将时间戳转换指定格式的时间
getDateTime() {
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
}
})
</script>
</html>

定义全局过滤器

Vue.filter(‘过滤器名’, 对应的处理函数)

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset= "UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h1>时间戳转换</h1>
<h2>当前时间的时间戳:{{time}}</h2>
<!-- mySlice为全局过滤器 -->
<h2>当前时间:{{time | getDateTime('YYYY/MM/DD') | mySlice}}</h2>
</div>

<div id="root2">
<h1>时间戳转换</h1>
<h2>当前时间:{{time}}</h2>
<!-- mySlice为全局过滤器 -->
<h2>当前时间:{{time | mySlice}}</h2>
</div>
</body>
<!-- 导入day.js -->
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
// 定义全局过滤器
Vue.filter('mySlice', function(value) {
return value.slice(0, 4)
})

const vm = new Vue({
el: '#root',
data: {
time: Date.now()
},
filters: {
// 局部过滤器
// 属于vm
getDateTime(value, formatStr='YYYY-MM-DD HH:mm:ss') {
return dayjs(value).format(formatStr);
}
}
})

const vm2 = new Vue({
el: '#root2',
data: {
time: '2022/10/10'
}
})
</script>
</html>

在v-bind中使用过滤器

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset= "UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root">
<h1>时间戳转换</h1>
<h2>当前时间的时间戳:{{time}}</h2>
<h2>当前时间:{{time | getDateTime('YYYY/MM/DD') | mySlice}}</h2>
<p :x="time | getDateTime('YYYY/MM/DD') | mySlice"></p>
</div>
</body>
<!-- 导入day.js -->
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.11.5/dayjs.min.js"></script>
<!-- 导入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
// 定义全局过滤器
Vue.filter('mySlice', function(value) {
return value.slice(0, 4)
})

const vm = new Vue({
el: '#root',
data: {
time: Date.now()
},
filters: {
// 局部过滤器
// 属于vm
getDateTime(value, formatStr='YYYY-MM-DD HH:mm:ss') {
return dayjs(value).format(formatStr);
}
}
})
</script>
</html>

生命周期

生命周期,又名:生命周期回调函数 、生命周期函数、生命周期钩子。生命周期是Vue在关键时刻帮我们调用的一些特殊名称的函数。生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。生命周期函数中的this指向是vm 或 组件实例对象。

生命周期函数的书写位置与data、methods同级

1. 初始化阶段

此阶段 Vue 实例开始创建,但模板尚未解析,页面显示原始 HTML 结构。

image-20260310211405467

2. 模板编译阶段

此阶段涉及 DOM 的编译和挂载过程,区分了 outerHTMLinnerHTML 的解析策略。

image-20260310211440189

3. 数据更新阶段

响应式数据发生变化时触发更新流程,实现界面与数据的同步。

image-20260310211456498

4. 实例销毁阶段

通过调用 vm.$destroy() 手动触发实例销毁流程。

image-20260310211512389

脚手架

https://cli.vuejs.org/

image-20260311204334891

ref属性

使用 ref 属性标记 html 标签元素

ref 属性应用在 html 标签元素上,获取的是对应的真实 DOM 元素

使用 ref 属性标记子组件

ref 属性应用在组件标签上,获取的是对应组件实例对象

mixin(混入)

  1. 功能:可以把多个组件共用的配置提取成一个混入对象

  2. 使用方式:

    第一步定义混合:

    1
    2
    3
    4
    5
    {
    data(){....},
    methods:{....}
    ....
    }

    第二步使用混入:

    全局混入:Vue.mixin(xxx)

插件

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    对象.install = function (Vue, options) {
    // 1. 添加全局过滤器
    Vue.filter(....)

    // 2. 添加全局指令
    Vue.directive(....)

    // 3. 配置全局混入(合)
    Vue.mixin(....)

    // 4. 添加实例方法
    Vue.prototype.$myMethod = function () {...}
    Vue.prototype.$myProperty = xxxx
    }
  4. 使用插件:Vue.use()

组件的自定义事件

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:

    1. 第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>

    2. 第二种方式,在父组件中:

      1
      2
      3
      4
      5
      <Demo ref="demo"/>
      ......
      mounted(){
      this.$refs.xxx.$on('atguigu',this.test)
      }
    3. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  4. 触发自定义事件:this.$emit('atguigu',数据)

  5. 解绑自定义事件this.$off('atguigu')

  6. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  7. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

vue脚手架配置代理

3.1 方法一

在vue.config.js中添加如下配置:

1
2
3
devServer:{
proxy:"http://localhost:5000"
}

优点:配置简单,请求资源时直接发给前端(8080)即可。
缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

3.2 方法二

编写vue.config.js配置具体代理规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
devServer: {
proxy: {
'/api1': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api1': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/

说明:

优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
缺点:配置略微繁琐,请求资源时必须加前缀。

路由

  1. 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
  2. 前端路由:key是路径,value是组件。

1.基本使用

  1. 安装vue-router,命令:npm i vue-router

  2. 应用插件:Vue.use(VueRouter)

  3. 编写router配置项:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //引入VueRouter
    import VueRouter from 'vue-router'
    //引入Luyou 组件
    import About from '../components/About'
    import Home from '../components/Home'

    //创建router实例对象,去管理一组一组的路由规则
    const router = new VueRouter({
    routes:[
    {
    path:'/about',
    component:About
    },
    {
    path:'/home',
    component:Home
    }
    ]
    })

    //暴露router
    export default router
  4. 实现切换(active-class可配置高亮样式)

    1
    <router-link active-class="active" to="/about">About</router-link>
  5. 指定展示位置

    1
    <router-view></router-view>

2.几个注意点

  1. 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
  2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
  3. 每个组件都有自己的$route属性,里面存储着自己的路由信息。
  4. 整个应用只有一个router,可以通过组件的$router属性获取到。

路由器的两种工作模式

  1. 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
  2. hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
  3. hash模式:
    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:
    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。