Vue3 组件笔记
十二月 03, 2020
VUE组件
- 了解组件化
- 了解什么是组件
- vue是如何注册组件的
- vue组件的嵌套和组合如何实现
- v-is
- 通信
- 组件过渡动效
- 组件生命周期
注册
html部分
1 | <div id="app"> |
局部注册
1 | Vue.createApp({ |
全局注册
1 | Vue.createApp({}) |
vue2和vue3的不同点,
1. vue3中发现template中可以直接写多个元素 | vue2 中template下的直接子元素有且仅有一个
2. vue3中销毁阶段的钩子函数为beforeUnmount和Unmount | vue2中是beforeDestroy和destroyed
组件嵌套
组件嵌套就是将子组件以标签的形式放到父组件template中
html部分
1 | <div id="app"> |
组件嵌套-局部
1 | Vue.createApp({ |
组件嵌套-全局
1 | Vue.createApp({}) |
组件-组合-插槽
插槽的基本使用
1 | <div id="app"> |
具名插槽
- 在#app内的组件中创建template标签 并给它设置指令v-slot:nameVal
- 在下面template中内部插槽slot 中设置name=”nameVal”
- 具名插槽是一对一的 上方#app内的标签顺序颠倒都没事
1 | <div id="app"> |
作用域插槽
- 组件是一个独立的聚合体,那么组件的数据应该由自己来定义,组件内通过data来定义
- 单向数据绑定,将数据绑定给slot
- 设置v-slot:nameVal=”scoped” // scoped是自定义的
- 渲染数据
js部分
1 | Vue.createApp({}) |
html部分
1 | <div id="app"> |
组件的几个常用选项(案例:反向数据)
js部分
1 | Vue.createApp({}) |
html部分
1 | <div id="app"> |
v-is
组件v-is
- 组件不能违背html基本规则
- v-is=”‘’” (双引号里面接单引号)
表格案例
1 | <div id="app"> |
js部分
1 | Vue.createApp({}) |
v-is 案例
做一个用户密码或者手机号验证码的登陆页面
js部分
1 | Vue.createApp({ |
html部分
1 | <div id="app"> |
通信
过渡动效
- vue提供了一个内置组件: transition
- 属性mode 表示transition组件的过度的顺序 out-in(一般用这个)/in-out
- 属性enter-active-class 表示的是过度进入时的过渡效果
- 属性leave-active-class 表示的是过渡离开的过渡效果
1 | <transition |
生命周期
挂载阶段
虚拟DOM在created – beforeMount生成,真实DOM在mounted拿到
- beforeCreate()
- 该钩子函数表示组件创建前。
- 初始化事件和生命周期钩子函数
- created()
- 该钩子函数表示创建结束,
- 这里我们有了组件。初始化注入【option】并且数据响应式【数据改变,界面改变】处理
- beforeMount()
判断组件是否有template选项?- yes 使用render函数来编译 template 得到虚拟DOM对象模型
- no 使用el.innerHTML来代替模板
- mounted()
- 创建app.$el来代替el 渲染虚拟DOM为真实DOM
- mounted案例
1
2
3
4
5
6
7
8
9
10
11
12<div id="app">
<Hello></Hello>
</div>
<template id="hello">
<!-- 这里的标签我们称之为 jsx[javascript+xml] 是VDOM的一种简化型写法 -->
<!-- jsx是对js语法的一种扩展,有了他我们就可以在标签中书写js了 -->
<div>
hello
<p> 123 </p>
</div>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const app = Vue.createApp({})
app.component('Hello',{
template: '#hello',
beforeCreate () {
console.log('挂载-beforeCreate')
},
created () {
console.log('挂载-created')
},
beforeMount () {
console.log('挂载-beforeMount')
},
mounted () {
console.log('挂载-mounted')
document.querySelector('p').style.background = 'red'
}
})
app.mount('#app')
更新阶段
触发要求: 1. 数据要改变 2. 数据得使用 可以触发多次。updated可以做真实DOM操作
- beforeUpdate()
- 它表示组件更新前
- 任务: 用来监听数据改变的
- updated()
- 它表示组件更新结束了
- 任务:虚拟DOM渲染生成,并且通过diff算法比对新旧的虚拟DOM,得到一个patch补丁对象【虚拟DOM】,重新将patch补丁对象渲染到页面,也就是说我们又一次可以得到了真实DOM
- 案例
1
2
3
4
5
6
7
8
9<div id="app">
<Hello></Hello>
</div>
<template id="hello">
<div>
<button @click="add">add</button>
<p> {{ count }} </p>
</div>
</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
25Vue.createApp({})
.component('Hello', {
data() {
return {
count: 1
}
},
methods: {
add() {
this.count++
}
},
template: '#hello',
updated() {
// 上面写了一个方法
// 点击按钮就数据自增
// 每次数据改变时触发updated()钩子函数,发送请求
axios('http://59.110.226.77:3000/api/category')
.then(res => {
console.log('res', res);
})
.catch(error => Promise.reject(error))
}
})
.mount('#app')
销毁阶段
任选其一beforeUnmount或unmounted,他会自动删除组件的事件、指令、computed、watch,但需要手动删除计时器/定时器、window/document身上事件,清楚第三方实例,释放内存
- beforeUnmount()
- 它表示组件销毁前
- 自动销毁组件定义methods/指令/computed/watch
- 手动操作:
- 清除计时器和定时器
- 清除绑定在window/document身上的事件
- 清除第三方实例
- unmounted() 同上
- 案例
1
2
3
4
5
6
7
8
9<div id="app">
<button @click="setFlag">切换</button>
<Hello v-if="flag"></Hello>
</div>
<template id="hello">
<div>
<p>hello</p>
</div>
</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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43// 设置类
function People(name) {
this.name = name
}
Vue.createApp({
data() {
return {
flag: true // v-if可以来控制组件的销毁
}
},
methods: {
setFlag() {
this.flag = !this.flag
}
}
})
.component('Hello', {
template: '#hello',
mounted() {
// 在组件挂载后
// 设置第三方实例
// 设置计时器
// 设置window身上事件resize
this.people = new People('zhangsan')
this.timer = setInterval(() => {
console.log('计时器', this.people);
}, 1000);
window.onresize = function () {
console.log('监听浏览器可视窗口尺寸');
}
},
unmounted() {
// console.log('销毁');
// 销毁后不会清楚第三方实例,计时器,window身上事件
// 必须手动消除
delete this.people
clearInterval(this.timer)
window.onresize = null
}
})
.mount('#app')
缓存阶段
触发条件: keep-alive[缓存组件] 如果缓存时间过久,可以自动去清楚缓存在deactivated()中设置
- activated()
- 表示你正在前台显示
- deactivated()
- 表示你正在后台缓存
- 案例
等待补充…
错误处理阶段
任务: 父组件捕获子组件的错误,使用另外一个界面来代替错误的子组件,而这个界面我们称呼为 回退UI。 errorCaptured 写在父组件中
- errorCaptured(error, instance, info){}
- error 错误 instance 组件 info 具体信息
- 案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<div id="app">
<Father></Father>
</div>
<template id="father">
<div>
<div v-if="flag"> 回退UI -- 您的网络有延迟,请重试 </div>
<Son v-else></Son>
</div>
</template>
<template id="son">
<div>
son
</div>
</template>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24Vue.createApp({})
.component('Father', {
template: '#father',
data() {
return {
flag: false
}
},
errorCaptured(error, instance, info) {
// 写在父组件中
// 如果子组件抛出错误会触发
console.log('触发');
if (error) { // 如果错误存在的话
this.flag = true // 改变flag从而改变页面
}
}
})
.component('Son', {
template: '#son',
mounted() {
throw new Error('出错了') // 在挂载阶段仍出个自定义错误
}
})
.mount('#app')
虚拟DOM跟踪阶段
- renderTracked()
- 触发的操作是get
- 挂载的虚拟DOM和更新阶段虚拟DOM都会被追踪到
- renderTriggered()
- 触发的操作是set
- 更新阶段虚拟DOM都会被追踪到
- 案例
1
2
3
4
5
6
7
8
9
10<div id="app">
<Hello></Hello>
</div>
<template id="hello">
<div>
<button @click="add">+</button>
<p> {{ count }} </p>
</div>
</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
26
27Vue.createApp({})
.component('Hello', {
template: '#hello',
data() {
return {
count: 1,
list: null
}
},
methods: {
add() {
this.count++ // 这将导致renderTriggered调用
}
},
renderTracked({ key, target, type }) {
console.log('key', key);
console.log('target', target);
console.log('type', type);
// 当组件第一次渲染时,这将被记录下来
},
renderTriggered({ key, target, type }) {
console.log('key', key);
console.log('target', target);
console.log('type', type);
}
})
.mount('#app')
查看评论