组件化-额外知识补充(上)
- 生命周期
- 认识生命周期
- 生命周期函数的演练
- refs引用
生命周期
认识生命周期
什么是生命周期呢?
- 生物学上,生物生命周期指得是一个生物体在生命开始到结束周而复始所历经的一系列变化过程;
- 每个组件都可能会经历从
创建、挂载、更新、卸载
等一系列的过程; - 在这个过程中的
某一个阶段
,我们可能会想要添加一些属于自己的代码逻辑
(比如组件创建完后就请求一些服务器数据); - 但是我们
如何可以知道目前组件正在哪一个过程
呢?Vue给我们操供了组件的生命周期函数
;
生命周期函数:
- 生命周期函数是
一些钩子函数(回调函数)
,在某个时间会被Vue源码内部进行回调
; - 通过对生命周期函数的回调,我们可以
知道目前组件正在经历什么阶段
; - 那么我们就可以在
该生命周期中编写属于自己的逻辑代码了
;
生命周期的流程图示(官网):
生命周期流程分析:
beforeCreate
:
创造组件实例之前。会回调beforeCreate函数
created
:
beforeCreate回调完成之后, 就会创建组件实例, 组件实例创建完成, 回调created函数;
此钩子的主要应用场景是发送网络请求,事件监听、this.$watch等设置。
beforeMount
:
created回调完成之后,未挂载到虚拟Dom之前被调用;
此时,Vue实例的DOM元素并未真正被替换挂载,但其组件实例的Vue.$el已经得到了内容渲染。
此钩子的主要应用场景是在DOM元素挂载之前进行一些异步操作,如数据异步处理等。
mounted
:
Vue实例DOM已经被渲染并挂载到页面的DOM元素上,挂载完成后,回调mounted函数。
此钩子的主要应用场景是完成一些必须在挂载后进行的异步操作,如元素初始化、事件绑定等,也可以在此获取Dom,操作Dom
beforeUpdate
:
挂载完成后,数据更新后,更改还没有重新渲染组件实例(即更新前的组件实例)之前被调用。
此钩子的主要场景是处理一些数据更新后的异步操作,如获取最新数据等。
updated
:
根据最新数据生成新的VNode, 重新渲染成新的虚拟DOM, 再根据新的虚拟DOM渲染成真实DOM后,此钩子将被调用。
此钩子的主要应用场景是完成DOM更新之后操作,如操作DOM后重新计算元素大小等。
beforeUnmount
:
在组件实例销毁之前被调用,即在组件实例的DOM元素被卸载之前,在组件的父组件或Vue实例销毁之前。
此钩子的主要应用场景包括与组件实例相关的清理操作,如删除定时器、取消事件监听等。
unmounted
:
在组件的DOM元素被卸载之后被调用,此时组件的实例已经被销毁,无法再操作组件实例。
此钩子的主要应用场景包括回收内存和解绑事件监听器等。
生命周期函数的演练
来做一个简单的演练,理解各个生命周期函数的执行顺序和应用场景:
(1)直接在App组件中使用除beforeUnmount和unmounted之外的各个生命函数:
<template>
<div id="app">
<h2>{{ message }}-{{ counter }}</h2>
<button @click="message='hello app'">修改message</button>
<button @click="counter++">+1</button>
</div>
<div>
<button @click="isShowHome=!isShowHome">显示home</button>
<Home v-if="isShowHome"></Home>
</div>
</template>
<script>
import Home from "./Home.vue";
export default {
components:{
Home
},
data(){
return{
message:"ada",
counter:0,
isShowHome:true
}
},
// 1.组件被创建之前
beforeCreate(){
console.log("beforecreate");
},
// 2.组件被创建完成(重点掌握)
created(){
console.log("created:组件被创建完成");
console.log("1.发送网络请求,请求数据");
console.log("2.监听eventbus事件");
console.log("3.监听watch数据");
},
// 3.组件中的template准备被挂载(了解)
beforeMount(){
console.log("beforemount");
},
// 4.组件template被挂载:虚拟dom-> 真实dom(重点掌握)
mounted(){
console.log("mounted");
console.log("1.获取虚拟Dom");
console.log("2.使用dom");
},
// 5.数据发生了改变
// 5.1准备更新
beforeUpdate(){
console.log("beforeupdate");
},
// 5.2更新dom
updated(){
console.log("updated");
},
// 6.准备卸载vnode->dom元素
// 6.1卸载之前
beforeUnmount(){
console.log("beforeunmount");
},
// 6.2dom元素被卸载完成
unmounted(){
console.log("unmounted");
}
}
</script>
(2)创建一个名为Home的 Vue 组件,包含 beforeUnmount和unmounted 两个生命周期函数。代码如下:
<template>
<h2>home</h2>
</template>
<script>
export default {
beforeUnmount() {
console.log("home的beforeunmount");
},
unmounted() {
console.log("home unmounted");
}
}
</script>
我们可以看到,在这个演示中,页面中有计数器且组件 Home可以通过一个切换按钮显示和隐藏。
运行这个代码,并打开浏览器控制台,我们可以看到下面的输出:
点击按钮+1修改计数器数字后,控制台新增输出:
点击按钮隐藏home组件,控制台新增输出:
从上面的演示中,可以清晰的感受到各个生命周期函数是什么时候执行的;其中非常重要的 created、mounted 和 unmounted
三个生命周期函数应用场景:
- 当组件被创建时,created 生命周期函数被调用。在这个函数中,我们可以初始化组件的数据和方法等等。
- 当组件被挂载到页面中,mounted 生命周期函数被调用。在这个函数中,我们可以进行一些必须在挂载后执行的异步操作,如向后端服务器发送请求获取数据等等。
- 当组件被销毁,unmounted 生命周期函数被调用。在这个函数中,我们应该立即移除组件中的定时器、事件监听器和其他非 Vue 实例的引用,以避免内存泄漏等问题。
refs引用
某些情况下,我们在组件中想要直接获取到元素对象或者子组件实例:
- 在Vue开发中我们是
不推荐进行原生DOM操作
的; - 这个时候,我们可以
给元素或者组件绑定一个ref的attribute属性
;
组件实例有一个$refs属性:
它一个对象Object,持有注册过ref attribute 的所有DOM元素和组件实例
。
当我们需要在 Vue 组件中操作 DOM 元素时,可以使用 ref(s) 这个特殊的属性来访问元素:
- ref 属性可以用在普通的 HTML 元素上,也可以用在子组件上;
- 通过 ref(s),我们可以获取到元素的真实 DOM 节点或者组件实例,从而进行一些操作,比如访问元素的属性、绑定事件、修改样式等等
具体来说, ref(s) 包含两种方式,字符串形式和函数形式:
(1)使用字符串:我们可以在元素上通过 v-model 或其他属性为元素指定一个名称,接着在组件的 $refs 对象中使用该名称访问元素,例如:
<template>
<div>
<button ref="myBtn" @click="clickHandler">Click me!</button>
</div>
</template>
<script>
export default {
methods: {
clickHandler () {
console.log(this.$refs.myBtn.value)
}
}
}
</script>
上面的例子中,我们在按钮上使用 ref 属性并将其命名为 myBtn
。在该组件的 methods 中,我们可以通过 this.$refs.myBtn 访问到该按钮
,从而获得 value 属性并打印到控制台上。
(2)使用函数:除了字符串形式,我们还可以通过一个函数返回值来动态地给 ref 赋值。这种方式可以用来在组件中引用其它组件的实例。例如:
<template>
<div>
<custom-widget ref="myWidget"></custom-widget>
</div>
</template>
<script>
import CustomWidget from './CustomWidget.vue'
export default {
components: {
CustomWidget
},
mounted () {
const widgetInstance = this.$refs.myWidget;
widgetInstance.doSomething();
// this.$refs.myWidget.doSomething();
}
}
</script>
在上面的代码中,我们使用 CustomWidget 组件添加 ref 属性。当这个组件渲染完成后,我们可以通过 $refs.myWidget 获取组件的实例并调用 doSomething 方法。
总结:
(1)需要注意的是,使用 $refs 可能需要在组件已经被挂载后才能正常访问到。
(2)另外,$refs 是一个非响应式的属性
,也就是说,如果使用 $refs 来访问某个组件实例或 DOM 元素,当它发生变化时是无法触发响应式更新的,这时候,就需要使用其他的数据传递方法。