自定义指令的钩子函数有bind
、inserted
、update
、componentUpdated
、unbind
。
可以跟组件的生命周期函数作类比:
bind
:只调用一次,指令第一次绑定到元素时调用。相当于beforeMount
,在自定义指令创建的时候触发,但是比组件的beforeMount
开始的晚。
inserted
:被绑定元素插入父节点时调用。相当于mounted
,元素被渲染时触发,比mounted
完成的早。
update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。
update
和componentUpdated
:相当于beforeUpdated
和updated
,但是update
晚于beforeUpdated
,componentUpdated
早于updated
。
unbind
:只调用一次,指令与元素解绑时调用。相当于destroyed
,比destroyed
完成的早。
比组件的声明周期函数早的是因为要先触发组件的生命周期函数才可以引发指令的钩子函数,晚的是因为指令所绑定的元素也是组件内容的一部分,只有内容全部完成了组件才算完成。
每次指令的更新都会引起根组件的beforeUpdate
,根组件的更新会引起子组件内部自定义指定的update
,子组件内部自定义指令的update
会引起子组件的beforeUpdate
。
写给自己:如果看不懂,代码一跑,啥都知道了。
<!DOCTYPE html>
<html lang="en">
<head>
<title>测试自动义指令</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
.test,
.test1 {
border: 1px solid black;
text-align: center;
width: 100px;
height: 100px;
line-height: 100px;
}
</style>
</head>
<body>
<div id="app">
<div v-move v-if="numberTestShow">Not:{{ numberTest }}</div>
<direct-test></direct-test>
<direct v-if="componentShow">
<div class="test" v-focus v-if="show">{{ num }}</div>
</direct>
<button @click="numberTestShow = !numberTestShow">不在组件内Toggle</button>
<button @click="numberTest++">不在组件内的更新</button>
<br />
<button @click="num++">更新</button>
<button @click="show = !show">Toggle</button>
<button @click="componentShow = !componentShow">子组件Toggle</button>
</div>
<script>
Vue.directive("focus", {
inserted: function(el) {
console.log("focus指令 insert", el.innerText);
el.focus();
},
bind: function(el) {
console.log("focus指令 bind", el.innerText);
},
update: function(el) {
console.log("focus指令 update", el.innerText);
},
componentUpdated: function(el) {
console.log("focus指令 componentUpdated", el.innerText);
},
unbind: function(el) {
console.log("focus指令 unbind", el.innerText);
}
});
Vue.directive("move", {
inserted: function(el) {
console.log("move指令 insert", el.innerText);
el.focus();
},
bind: function(el) {
console.log("move指令 bind", el.innerText);
},
update: function(el) {
console.log("move指令 update", el.innerText);
},
componentUpdated: function(el) {
console.log("move指令 componentUpdated", el.innerText);
},
unbind: function(el) {
console.log("move指令 unbind", el.innerText);
}
});
Vue.component("direct", {
template: `
<div><slot></slot></div>
`,
beforeCreate() {
console.log("子组件 beforeCreate");
},
created() {
console.log("子组件 created");
},
beforeMount: function() {
console.log("子组件 beforeMount");
},
mounted() {
console.log("子组件 mounted");
},
beforeUpdate() {
console.log("子组件 beforeUpdate");
},
updated() {
console.log("子组件 updated");
},
beforeDestroy() {
console.log("子组件 beforeDestroy");
},
destroyed() {
console.log("子组件 destroped");
}
});
Vue.component("direct-test", {
template: `
<div><slot></slot></div>
`,
beforeCreate() {
console.log("测试子组件 beforeCreate");
},
created() {
console.log("测试子组件 created");
},
beforeMount: function() {
console.log("测试子组件 beforeMount");
},
mounted() {
console.log("测试子组件 mounted");
},
beforeUpdate() {
console.log("测试子组件 beforeUpdate");
},
updated() {
console.log("测试子组件 updated");
},
beforeDestroy() {
console.log("测试子组件 beforeDestroy");
},
destroyed() {
console.log("测试子组件 destroped");
}
});
var vm = new Vue({
el: "#app",
data: {
num: 100,
numberTest: 100,
numberTestShow: true,
show: true,
componentShow: true
},
beforeCreate() {
console.log("根组件 beforeCreate");
},
created() {
console.log("根组件 created");
},
beforeMount: function() {
console.log("根组件 beforeMount");
},
mounted() {
console.log("根组件 mounted");
},
beforeUpdate() {
console.log("根组件 beforeUpdate");
},
updated() {
console.log("根组件 updated");
},
beforeDestroy() {
console.log("根组件 beforeDestroy");
},
destroyed() {
console.log("根组件 destroped");
}
});
</script>
</body>
</html>
可供参考: 父子组件生命周期执行顺序。