开发应该理清的vue2的生命周期(二)
$nextTick在生命周期的触发时机
开始之前,请先认真阅读一下官网关于“nextTick”的内容:
- API — Vue.js——Vue.nextTick
- API — Vue.js——vm.$nextTick
- 深入响应式原理 — Vue.js
- API — mounted——注意
- API — updated——注意
Vue.nextTick(callback)
:回调函数callback将在 DOM 更新完成后被调用
本文章,将延续前篇文章[ 开发应该理清的vue2的生命周期(一) ]的测试代码的风格,看看“$nextTick在生命周期的触发时机”。
在本文章,本身组件的<template>标签的主要内容为“<h1 ref=“testRef”>{{ testData }}</h1>”。本组件在“created”和“mounted”生命周期改变了本组件的data值——testData,输出每次改变之前和之后的this.testData的值,同时输出this.$refs.testRef引用的<h1>Dom元素的textContent。且在“created”和“mounted”最后面,再通过使用$nextTick,再输出一遍。加入“beforeUpdate”和“updated”两个生命周期的触发输出。
测试代码
父组件:
// ParentComponent.vue
<template>
<div>
<!-- TestNextTickComponent -->
<TestNextTickComponent/>
</div>
</template>
<script>
import TestNextTickComponent from "./component/TestNextTickComponent.vue";
export default {
name: "ParentComponent",
components: { TestNextTickComponent }
}
</script>
本组件:
// TestNextTickComponent.vue
<template>
<div class="app-container">
<h1 ref="testRef">{{ testData }}</h1>
</div>
</template>
<script>
export default {
name: "TestNextTickComponent",
data() {
return {
testData: "testData",
};
},
created() {
console.log("testNextTickComponent created");
// 输出改变this.testData之前
console.log(`before created change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent
// 改变this.testData
this.testData = "testData change on testNextTickComponent created oneself";
// 输出改变this.testData之后
console.log(`after created change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
// 在created中,使用$nextTick
this.$nextTick(() => {
console.log(`on nextTick (created), this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
});
},
mounted() {
console.log("testNextTickComponent mounted");
// 输出改变this.testData之前
console.log(`before mounted change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent
// 改变this.testData
this.testData = "testData change on testNextTickComponent mounted oneself";
// 输出改变this.testData之后
console.log(`after mounted change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
// 在mounted中,使用$nextTick
this.$nextTick(() => {
console.log(`on nextTick (mounted), this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
});
},
beforeUpdate() {
console.log("testNextTickComponent beforeUpdate");
},
updated() {
console.log("testNextTickComponent updated");
},
methods: {
// 输出this.$refs.testRef引用的<h1>Dom元素的textContent
showTestRefDomTextContent() {
if (!this.$refs.testRef) {
console.log(`this.$refs.testRef is ${this.$refs.testRef}`);
} else {
console.log(`testRefDomTextContent is "${this.$refs.testRef.textContent}"`);
}
},
},
};
</script>
测试结果(添加上注释,便于和测试代码对应,实际输出结果没注释部分):
1. testNextTickComponent created
// 输出改变this.testData之前
before created change, this.testData is "testData"
this.$refs.testRef is undefined
// 输出改变this.testData之后
after created change, this.testData is "testData change on testNextTickComponent created oneself"
this.$refs.testRef is undefined
2. testNextTickComponent mounted
// 输出改变this.testData之前
before mounted change, this.testData is "testData change on testNextTickComponent created oneself"
testRefDomTextContent is "testData change on testNextTickComponent created oneself"
// 输出改变this.testData之后
after mounted change, this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent created oneself"
3. testNextTickComponent beforeUpdate
testNextTickComponent updated
4. // 在created中,使用$nextTick
on nextTick (created), this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
5. // 在mounted中,使用$nextTick
on nextTick (mounted), this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
测试结果分析
-
testNextTickComponent created // 输出改变this.testData之前 before created change, this.testData is "testData" this.$refs.testRef is undefined // 输出改变this.testData之后 after created change, this.testData is "testData change on testNextTickComponent created oneself" this.$refs.testRef is undefined
- 本组件的“created”生命周期。testData被赋值了 “testData change on testWatchComponent created oneself”。
- 由于在created,所以this.$refs.testRef 为 undefined,还不能访问真实Dom。
-
testNextTickComponent mounted // 输出改变this.testData之前 before mounted change, this.testData is "testData change on testNextTickComponent created oneself" testRefDomTextContent is "testData change on testNextTickComponent created oneself" // 输出改变this.testData之后 after mounted change, this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData change on testNextTickComponent created oneself"
-
现在到本组件的“mounted”生命周期。testData被赋值了 “testData change on testWatchComponent mounted oneself”。
-
由于已经在mounted,所以this.$refs.testRef 不为 undefined,可以访问真实Dom。在mounted里改变this.testData之前和之后,都访问到<h1>Dom元素的textContent为在created设置的新值——“testData change on testWatchComponent created oneself”。
-
这时你可能会问,“假如本组件在created函数中,没将testData赋值 "testData change on testWatchComponent created oneself"呢?”
更改如下:
created() { console.log("testNextTickComponent created"); // // 输出改变this.testData之前 // console.log(`before created change, this.testData is "${this.testData}"`); // this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent // // 改变this.testData // this.testData = "testData change on testNextTickComponent created oneself"; // // 输出改变this.testData之后 // console.log(`after created change, this.testData is "${this.testData}"`); // this.showTestRefDomTextContent(); // 在created中,使用$nextTick this.$nextTick(() => { console.log(`on nextTick (created), this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); }); }, mounted() { console.log("testNextTickComponent mounted"); // 输出改变this.testData之前 console.log(`before mounted change, this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent // 改变this.testData this.testData = "testData change on testNextTickComponent mounted oneself"; // 输出改变this.testData之后 console.log(`after mounted change, this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); // 在mounted中,使用$nextTick this.$nextTick(() => { console.log(`on nextTick (mounted), this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); }); },
通过测试,输出的结果如下。
1. testNextTickComponent created 2. testNextTickComponent mounted // 输出改变this.testData之前 before mounted change, this.testData is "testData" testRefDomTextContent is "testData" // 输出改变this.testData之后 after mounted change, this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData" 3. testNextTickComponent beforeUpdate testNextTickComponent updated 4. // 在created中,使用$nextTick on nextTick (created), this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData change on testNextTickComponent mounted oneself" 5. // 在mounted中,使用$nextTick on nextTick (mounted), this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
可以看到,重点为第2条发生了变化,在mounted里改变this.testData之前和之后,都访问到<h1>Dom元素的textContent为testData的默认值——“testData”。
-
-
testNextTickComponent beforeUpdate testNextTickComponent updated
-
由于在“mounted”生命周期,testData改变了,所以Dom 被更新——触发了“beforeUpdate”和“updated”
-
这时你可能会问,“假如本组件在mounted函数中,没将testData赋值 "testData change on testWatchComponent mounted oneself"呢?“beforeUpdate”和“updated”还会触发吗?”
更改如下:created() { console.log("testNextTickComponent created"); // 输出改变this.testData之前 console.log(`before created change, this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent // 改变this.testData this.testData = "testData change on testNextTickComponent created oneself"; // 输出改变this.testData之后 console.log(`after created change, this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); // 在created中,使用$nextTick this.$nextTick(() => { console.log(`on nextTick (created), this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); }); }, mounted() { console.log("testNextTickComponent mounted"); // 输出改变this.testData之前 // console.log(`before mounted change, this.testData is "${this.testData}"`); // this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent // // 改变this.testData // this.testData = "testData change on testNextTickComponent mounted oneself"; // // 输出改变this.testData之后 // console.log(`after mounted change, this.testData is "${this.testData}"`); // this.showTestRefDomTextContent(); // 在mounted中,使用$nextTick this.$nextTick(() => { console.log(`on nextTick (mounted), this.testData is "${this.testData}"`); this.showTestRefDomTextContent(); }); },
通过测试,输出的结果如下。
1. testNextTickComponent created // 输出改变this.testData之前 before created change, this.testData is "testData" this.$refs.testRef is undefined // 输出改变this.testData之后 after created change, this.testData is "testData change on testNextTickComponent created oneself" this.$refs.testRef is undefined 2. testNextTickComponent mounted 3. // 在created中,使用$nextTick on nextTick (created), this.testData is "testData change on testNextTickComponent created oneself" testRefDomTextContent is "testData change on testNextTickComponent created oneself" 4. // 在mounted中,使用$nextTick on nextTick (mounted), this.testData is "testData change on testNextTickComponent created oneself" testRefDomTextContent is "testData change on testNextTickComponent created oneself"
可以看到,假如本组件在mounted函数中,没将testData赋值 "testData change on testWatchComponent mounted oneself"时,“beforeUpdate”和“updated”没被触发。
在“mounted”之后,在created中和mounted中使用的$nextTick的回调函数依次被调用了
-
-
// 在created中,使用$nextTick on nextTick (created), this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
- 可以看到,在“updated”之后,在created中使用$nextTick的回调函数被调用了。
- 访问到<h1>Dom元素的textContent为在mounted设置的新值——“testData change on testNextTickComponent mounted oneself”。
-
// 在mounted中,使用$nextTick on nextTick (mounted), this.testData is "testData change on testNextTickComponent mounted oneself" testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
- 可以看出,同样在“updated”之后,在mounted中使用$nextTick的回调函数被调用了,结果和“在created中使用$nextTick的回调函数被调用”的一致。
进一步思考
现在,你可以将三种情况下的测试结果(①created和mounted都更改testData;②仅created更改testData;③仅mounted更改testData)再进行一次比较,你将会更清楚“$nextTick在生命周期的触发时机”
现在,假如在created上模拟一次请求,然后更改this.testData,created函数更改如下:
created() {
console.log("testNextTickComponent created");
// 输出改变this.testData之前
console.log(`before created change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent(); // 输出this.$refs.testRef引用的<h1>Dom元素的textContent
// 改变this.testData
this.testData = "testData change on testNextTickComponent created oneself";
// 输出改变this.testData之后
console.log(`after created change, this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
// 在created中,使用$nextTick
this.$nextTick(() => {
console.log(`on nextTick (created), this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
});
// 新添加
// 模拟请求,然后更改this.testData
setTimeout(() => {
this.testData = "testData change on setTimeout (created)";
// 输出模拟请求后,改变this.testData之后,但不在使用$nextTick中
console.log(`on setTimeout (created and setTimeout), this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
// 输出模拟请求后,改变this.testData之后,同时在使用$nextTick中
this.$nextTick(() => {
console.log(`on setTimeout (created 、setTimeout and nextTick), this.testData is "${this.testData}"`);
this.showTestRefDomTextContent();
});
}, 5000);
},
结果为:
先输出最开始的那个测试结果。
1. testNextTickComponent created
// 输出改变this.testData之前
before created change, this.testData is "testData"
this.$refs.testRef is undefined
// 输出改变this.testData之后
after created change, this.testData is "testData change on testNextTickComponent created oneself"
this.$refs.testRef is undefined
2. testNextTickComponent mounted
// 输出改变this.testData之前
before mounted change, this.testData is "testData change on testNextTickComponent created oneself"
testRefDomTextContent is "testData change on testNextTickComponent created oneself"
// 输出改变this.testData之后
after mounted change, this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent created oneself"
3. testNextTickComponent beforeUpdate
testNextTickComponent updated
4. // 在created中,使用$nextTick
on nextTick (created), this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
5. // 在mounted中,使用$nextTick
on nextTick (mounted), this.testData is "testData change on testNextTickComponent mounted oneself"
testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
然后,大概过个5秒左右,再输出以下结果
6. // 输出模拟请求后,改变this.testData之后,但不在使用$nextTick中
on setTimeout (created and setTimeout), this.testData is "testData change on setTimeout (created)"
testRefDomTextContent is "testData change on testNextTickComponent mounted oneself"
7. testNextTickComponent beforeUpdate
testNextTickComponent updated
8. // 输出模拟请求后,改变this.testData之后,同时在使用$nextTick中
on setTimeout (created 、setTimeout and nextTick), this.testData is "testData change on setTimeout (created)"
testRefDomTextContent is "testData change on setTimeout (created)"