文章目录
《vue基础学习-组件》提到组件传递数据方式:
1. props/$emit
- 父传子:子组件通过
props显式声明 自定义 属性,接收父组件的传值。 - 子传父:子组件通过
$emit()显式声明 自定义 事件,父组件调用自定义事件接收子组件返回的参数。
2. $ref / $parent
- 父传子:父组件的方法中通过
this.$refs访问子组件的引用。 - 子传父:子组件中通过
this.$parent.$refs访问父组件的引用。
本节将主要介绍组件调用中涉及的生命周期钩子。
1. <componet :is=“组件名”>
在 Vue.js 中,你可以使用 <component> 元素结合 :is 属性来动态地切换组件。这种方式非常灵活,可以根据数据的变化来渲染不同的组件。
<template>
<div>
<button @click="currentComponent = 'ComponentA'">Show Component A</button>
<button @click="currentComponent = 'ComponentB'">Show Component B</button>
<component :is="currentComponent"></component>
</div>
</template>
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentComponent: 'ComponentA'
};
}
};
</script>
<component :is="currentComponent"></component>:这里使用了<component>元素,并通过:is绑定一个变量currentComponent。currentComponent的值决定了要渲染哪个组件。currentComponent:这是一个响应式的数据属性,初始值为'ComponentA'。当点击按钮时,这个值会被更新,从而触发组件的切换。
📊 假设你有两个组件 ComponentA.vue 和 ComponentB.vue:
ComponentA.vue
<template>
<div>
<h1>Component A</h1>
<p>This is Component A</p>
</div>
</template>
<script>
export default {
name: 'ComponentA'
};
</script>
ComponentB.vue
<template>
<div>
<h1>Component B</h1>
<p>This is Component B</p>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
name: 'ComponentB',
data() {
return {
count: 0
};
},
computed: {
doubleCount() {
return this.count * 2;
}
},
methods: {
increment() {
this.count++;
}
}
};
</script>
点击 “Show Component A”,加载组件 ComponentA:

点击 “Show Component B”,加载组件 ComponentB :

点击 “increment”,数值改变:

但如果点击 “Show Component A” 后,再点击 “Show Component B”,组件 ComponentB 状态没有保存:

如果你希望在切换组件时保留组件的状态,可以使用 <keep-alive> 包裹 <component>。
2. <keep-alive>
在 Vue.js 中,<keep-alive> 是一个内置组件,用于缓存组件实例,以避免重复渲染和销毁。
<template>
<div>
<button @click="currentComponent = 'ComponentA'">Show Component A</button>
<button @click="currentComponent = 'ComponentB'">Show Component B</button>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentComponent: 'ComponentA'
};
}
};
</script>
这样,即使组件被切换,它们的状态也会被保留。
点击 “Show Component A” 后,再点击 “Show Component B”,组件 ComponentB 状态不变:

总结:
- 使用
<component :is="组件名"></component>可以动态地切换组件。 - 结合
<keep-alive>可以保留组件的状态。 - 通过改变
:is绑定的变量值来控制显示哪个组件。
2.1 <keep-alive>包裹的组件怎么去除状态保留
如果你希望在某些情况下不保留组件的状态,可以通过以下几种方法来实现:
2.1.1 使用 include 和 exclude 属性
<keep-alive> 组件提供了 include 和 exclude 属性,可以用来控制哪些组件会被缓存。你可以根据组件的名称或组件本身来决定是否缓存。
<template>
<div>
<button @click="currentComponent = 'ComponentA'">Show Component A</button>
<button @click="currentComponent = 'ComponentB'">Show Component B</button>
<keep-alive :include="['ComponentA']" :exclude="['ComponentB']">
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentComponent: 'ComponentA'
};
}
};
</script>
2.1.2 动态控制 <keep-alive>
可以通过条件渲染来动态控制是否使用 <keep-alive>。
<template>
<div>
<button @click="toggleComponent">Toggle Component</button>
<keep-alive v-if="useKeepAlive">
<component :is="currentComponent"></component>
</keep-alive>
<component v-else :is="currentComponent"></component>
</div>
</template>
<script>
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';
export default {
components: {
ComponentA,
ComponentB
},
data() {
return {
currentComponent: 'ComponentA',
useKeepAlive: false
};
},
methods: {
toggleComponent() {
if (this.currentComponent === 'ComponentA') {
this.currentComponent = 'ComponentB';
this.useKeepAlive = true;
} else {
this.currentComponent = 'ComponentA';
this.useKeepAlive = false;
}
}
}
};
</script>
但运行后,发现虽然组件 ComponentB 的方法 activated、deactivated 都执行了,但是状态并没有保留。o(╯□╰)o
查阅资料 关于动态使用keepAlive不生效的问题 发现:
通过
v-if来判断是否生成<keep-alive>,当列表页面符合条件时,内存缓存了组件状态。当跳转到详情页时,不符合条件,由于v-if是挂载到<keep-alive>标签上,会把之前<keep-alive>的列表页面进行销毁,再次进入到列表会重新创建。
✔️ 正确的使用方法:
<template>
<div>
<button @click="toggleComponent">Toggle Component</button>
<keep-alive>
<component v-if="useKeepAlive" :is="currentComponent"></component>
</keep-alive>
<component v-if="!useKeepAlive" :is="currentComponent"></component>
</div>
</template>
☝️ ⚠️ ✨注:实际项目中,<keep-alive> 需要配合 vue-router 共同使用,通过增加 router.meta 属性,判定组件是否缓存。
const routes = [
{
path: '/',
name: 'home',
component: () => import('../views/Home.vue'),
meta: {
keepAlive: true // 需要被缓存
}
},
{
path: '/',
name: 'edit',
component: () => import('../views/edit.vue'),
meta: {
keepAlive: false // 不需要被缓存
}
}
]
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 这里是会被缓存的视图组件,比如 Home! -->
</router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
<!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>
2.1.3 使用 activated 和 deactivated 生命周期钩子在组件内部控制状态
可以在组件内部使用 activated 和 deactivated 生命周期钩子来手动管理组件的状态。这些钩子在组件被激活和停用时调用。
例如,不想组件 ComponentB 状态被保留:
<template>
<div>
<h1>Component B</h1>
<p>This is Component B</p>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
name: 'ComponentB',
data() {
return {
count: 0
};
},
computed: {
doubleCount() {
return this.count * 2;
}
},
methods: {
increment() {
this.count++;
}
},
activated() {
console.log('Component activated');
// 在这里可以恢复一些状态
},
deactivated() {
console.log('Component deactivated');
// 在这里可以清理一些状态
}
};
</script>
3. activated()
在 Vue.js 中,activated 和 deactivated 是 Vue 组件的 生命周期钩子,主要用于 <keep-alive> 包裹的组件。
activated:当组件被 激活 时调用。这通常发生在组件从缓存中恢复并重新显示时。deactivated:当组件被 停用 时调用。这通常发生在组件被隐藏并放入缓存时。
ComponentB.vue
<template>
<div>
<h1>Component B</h1>
<p>This is Component B</p>
<p>Count: {{ count }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
name: 'ComponentB',
data() {
return {
count: 0
};
},
computed: {
doubleCount() {
return this.count * 2;
}
},
methods: {
increment() {
this.count++;
}
},
activated() {
console.log('Component activated');
},
deactivated() {
console.log('Component deactivated');
}
};
</script>
点击 “Show Component B”,加载组件 ComponentB ,打印 Component activated:

点击 “Show Component A”,加载组件 ComponentA,打印 Component deactivated:

再次点击 “Show Component B”,加载组件 ComponentB ,打印 Component activated:

注意:
- 生命周期钩子
activated和deactivated必须和<keep-alive>结合使用才生效。
4. 生命周期钩子
在 Vue.js 中,生命周期钩子(Lifecycle Hooks)是一些特定的函数,你可以在这些函数中执行自定义逻辑。Vue 组件从创建到销毁的过程中会经历一系列的阶段,每个阶段都有相应的钩子函数可以让你插入自定义代码。
Vue 2 和 Vue 3 的生命周期钩子有一些差异。Vue 3 引入了一些新的生命周期钩子,并对一些旧的钩子进行了重命名。
- Vue 2 生命周期钩子
- 创建阶段:
beforeCreate:在实例初始化之后,数据、事件配置之前被调用。created:在实例创建完成后被调用。此时实例已完成数据、事件配置。但是挂载阶段还没开始,$el属性目前不可见。
- 挂载阶段:
beforeMount:在挂载开始之前被调用。相关的render函数首次被调用。mounted:在实例挂载到 DOM 之后被调用。
- 更新阶段:
beforeUpdate:在更新data数据之后,view视图重新渲染之前触发。所以,beforeUpdate和updated针对视图层的。updated:view视图渲染完成后触发。- ⚠️注1:只有
view上面的数据变化才会触发beforeUpdate和updated,仅属于data中的数据改变是并不能触发。 - ⚠️注2:发起数据请求不能在
beforeUpdate和updated中操作,会导致无限循环。
- 销毁阶段:
beforeDestroy:在实例销毁之前调用。在这一步,实例仍然完全可用。destroyed:在实例销毁后调用。此时所有的事件监听器都被移除,所有的子实例也都被销毁。
- 其他钩子:
activated:在keep-alive组件激活时调用。deactivated:在keep-alive组件停用时调用。errorCaptured:捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
- 创建阶段:
- Vue 3 生命周期钩子
- 创建阶段:
setup():在 Vue 3 中,beforeCreate和created钩子被setup函数取代。
- 挂载阶段:
beforeMount:在挂载开始之前被调用。mounted:在实例挂载到 DOM 之后被调用。
- 更新阶段:
beforeUpdate:在数据更新时调用,发生在虚拟 DOM 打补丁之前。updated:在数据更新后调用,此时 DOM 已经更新。
- 销毁阶段:
beforeUnmount:代替beforeDestroy。unmounted:代替destroyed。
- 其他钩子:
onActivated:代替activated。onDeactivated:代替deactivated。onErrorCaptured:代替errorCaptured。
- 创建阶段:
5. 常用生命周期钩子及使用场景
5.1 created
created 钩子在实例创建完成后被调用。此时实例已完成数据、事件配置。但是挂载阶段还没开始,$el 属性目前不可见。
典型用例:
- 初始化数据。
- 发起网络请求获取初始数据。
- 设置事件监听器。
export default {
created() {
console.log('Component is created');
this.fetchData();
},
methods: {
fetchData() {
// 发起网络请求,获取初始数据。
}
}
};
5.2 mounted
mounted 钩子在实例挂载到 DOM 之后被调用。
典型用例:
- 操作 DOM,一般结合
this.$nextTick(),确保子组件 DOM 已经被更新。 - 初始化第三方库(如 jQuery 插件)。
- 发送网络请求
- 启动定时器或动画。
export default {
mounted() {
console.log('Component is mounted');
this.initThirdPartyLibrary();
},
methods: {
initThirdPartyLibrary() {
// 初始化第三方库
}
}
};
⚠️注1:created 钩子在组件实例被创建后调用,此时组件的 data 和 methods 已经初始化,但 DOM 还未挂载。如果你的网络请求不需要操作 DOM,优先放在 created 中,这样可以尽早获取数据,减少用户等待时间。如果请求的结果需要操作 DOM(例如初始化图表、地图等),则放在 mounted 中。
⚠️注2:如果请求依赖于某些 动态数据(如路由参数),可以使用 watch 监听数据变化并重新发起请求。
示例:根据路由参数动态请求数据
export default {
data() {
return {
post: {}
};
},
created() {
// 在 created 中发起请求
this.fetchPost(this.$route.params.id);
},
watch: {
// 监听路由参数变化,重新请求数据
'$route.params.id': function(newId) {
this.fetchPost(newId);
}
},
methods: {
async fetchPost(id) {
try {
const response = await axios.get(`https://jsonplaceholder.typicode.com/posts/${id}`);
this.post = response.data;
} catch (error) {
console.error('请求失败:', error);
}
}
}
};
5.3 beforeUpdate
典型用例:
- 在数据更新前保存当前状态。
- 清理无效的数据或状态。
- 如果一个组件的数据更新会影响到其他组件的状态,可以在
beforeUpdate中发送事件通知其他组件进行相应的处理。
5.4 updated
典型用例:
- 操作更新后的 DOM。
- 基于更新后的 DOM 的操作,比如调整布局、更新样式等。
- 结合 beforeUpdate 记录时间戳,计算视图渲染时间,进行性能测试,以便后续优化。
- 如果组件之间需要在数据更新后进行交互,可以在
updated钩子中发送事件或调用其他组件的方法。
5.5 beforeDestroy、beforeUnmount
典型用例:
- 清理定时器。
- 取消网络请求。
- 移除事件监听器。
5.6 destroyed、unmounted
典型用例:
- 最终清理工作。
- 记录日志。
完整示例 Lifecycle.vue:
<template>
<div>
<h1 ref="count">{{ count }}</h1>
<button @click="changeMessage">ChangeMessage</button>
<button @click="increment">Increment</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'vue message', // 该数据不在视图中展示
count: 0
}
},
methods: {
changeMessage() {
// message 没有在视图中展示,所以,修改 message 并不会触发 beforeUpdate、updated
this.message = 'change message';
console.log(this.message);
},
increment() {
this.count++;
}
},
created() {
console.log('+++ Component is created +++');
console.log(this.count);
},
mounted() {
console.log('+++ Component is mounted +++');
console.log(this.count);
},
beforeUpdate() {
// 视图更新前保存当前状态
// console.log('Before update, DOM:', document.getElementsByTagName("h1")[0].textContent);
console.log('Before update, DOM:', this.$refs.count.innerText);
console.log('Before update, count:', this.count);
console.log('+++ beforeUpdate called +++');
},
updated() {
// 视图更新后的操作
console.log('After update, DOM:', this.$refs.count.innerText);
console.log('After update, count:', this.count);
console.log('+++ updated called +++');
},
beforeDestroy() {
// 清理资源
console.log('+++ beforeDestroy called +++');
},
destroyed() {
// 最终清理
console.log('+++ destroyed called +++');
}
};
</script>
<style scoped>
/* 添加一些样式 */
h1 {
color: blue;
}
</style>
组件加载,触发 created、mounted

点击 “changeMessage”,因为message 没有在视图中展示,不会触发 beforeUpdate、updated。

点击“increment”,触发 beforeUpdate、updated。
beforeUpdate 视图渲染前,获取 DOM 视图中 count 为更新前数据,数据 data 中的 count 已经被修改,但未渲染更新到 DOM 视图中。(可以 debugger 断点调试)
updated 视图渲染完成,DOM 视图中 count 和 数据 data 中的 count 均被修改。

再次点击“increment”,,触发 beforeUpdate、updated。

6. Vue事件循环机制
本来准备介绍 this.$nextTick(),在这之前先介绍下Vue 事件循环机制,Vue 事件循环机制是基于 JavaScript 事件循环(Event Loop) 和 异步更新队列 实现的。Vue 利用这些机制来高效地管理 DOM 更新和响应式数据的变化。
JavaScript 事件循环可以参考之前的文章 📖vue进阶-es6语法:10.JavaScript 执行机制,这里大体介绍下:
6.1 JavaScript 事件循环
- 事件循环的核心
调用栈(Call Stack):用于执行同步代码。宏任务队列(MacroTask Queue):用于存放异步任务(如 setTimeout、Promise 等)。微任务队列(MicroTask Queue):用于存放微任务(如 Promise.then、MutationObserver等)。
- 事件循环的执行顺序
- 执行同步代码(调用栈)。
- 执行微任务队列中的所有任务。
- 依次执行宏任务队列中的任务。
- 重复上述过程。
6.2 Vue 的异步更新队列
Vue 利用 JavaScript 的事件循环机制来实现高效的 DOM 更新。具体来说,Vue 会将数据变化引起的 DOM 更新推迟到下一个事件循环中执行,而不是立即更新。
- 异步更新的优势
- 批量更新:将多次数据变化合并为一次 DOM 更新,减少不必要的渲染。
- 性能优化:避免频繁的 DOM 操作,提高性能。
- 更新流程
- 当数据发生变化时,Vue 会触发依赖该数据的组件的重新渲染。
- Vue 不会立即更新 DOM,而是将更新任务推入一个 异步更新队列。
- 在当前事件循环的同步代码执行完成后,Vue 会执行
微任务队列中的更新任务,批量更新 DOM。
6.3 this.$nextTick()
this.$nextTick() 是 Vue 提供的一个方法,用于在 DOM 更新完成后执行回调函数。
- 使用场景
- 当你修改了数据后,需要操作更新后的 DOM 元素。
- 确保某些逻辑在 DOM 更新后执行。
- 实现原理
- Vue 会将
this.$nextTick()的回调函数推入微任务队列。 - 在当前事件循环的同步代码执行完成后,Vue 会先执行 DOM 更新任务,然后执行
this.$nextTick()的回调。
- Vue 会将
示例:
this.message = '更新后的消息';
this.$nextTick(() => {
console.log('DOM 已更新:', this.$refs.message.textContent);
});
6.4 Vue 事件循环的具体流程
以下是 Vue 事件循环的具体流程:
- 数据变化:
- 当你修改了 Vue 实例的响应式数据时,Vue 会标记依赖该数据的组件为“需要更新”。
- 推入更新队列:
- Vue 会将需要更新的组件推入一个异步更新队列。
- 同步代码执行:
- 继续执行当前的同步代码。
- 微任务阶段:
- 在当前事件循环的同步代码执行完成后,Vue 会执行微任务队列中的任务。
- Vue 会遍历更新队列,批量更新 DOM。
- this.$nextTick() 回调:
- 在 DOM 更新完成后,执行 this.$nextTick() 中的回调函数。
- 宏任务阶段:
- 如果有宏任务(如 setTimeout),会在下一个事件循环中执行。
示例代码:
<template>
<div>
<p ref="message">{{ message }}</p>
<button @click="updateMessage">更新消息</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
};
},
methods: {
updateMessage() {
// 修改数据
this.message = '消息已更新!';
// 同步代码
console.log('同步代码执行');
// 使用 $nextTick
this.$nextTick(() => {
console.log('DOM 已更新:', this.$refs.message.textContent);
});
// 微任务
Promise.resolve().then(() => {
console.log('微任务执行');
});
// 宏任务
setTimeout(() => {
console.log('宏任务执行');
}, 0);
}
}
};
</script>
输出顺序:
同步代码执行
微任务执行
DOM 已更新: 消息已更新!
宏任务执行
6.5 小结
- Vue 的事件循环机制基于 JavaScript 的事件循环,利用异步更新队列(微任务队列)来批量更新 DOM。
this.$nextTick()是 Vue 提供的方法,用于在 DOM 更新完成后执行回调。
7. this.$nextTick()
this.$nextTick() 是 Vue.js 提供的一个方法,用于在 DOM 更新完成后 执行回调函数。
Vue 是异步更新 DOM 的,当你修改了数据后,DOM 不会立即更新,而是会等到下一个“tick”(即下一次事件循环)才会更新。this.$nextTick() 可以确保你在 DOM 更新完成后执行某些操作,确保操作到最新的 DOM。
Children.vue:
<template>
<div> {{ msg }} </div>
</template>
<script>
export default {
props: ['msg']
};
</script>
NextTick.vue:
<template>
<div>
<Children ref="children" :msg="message"></Children>
<button @click="updateMessage">updateMessage</button>
</div>
</template>
<script>
import Children from "./Children.vue";
export default {
components: {
Children
},
data() {
return {
message: "Hello",
};
},
methods: {
updateMessage() {
this.message = "Hello, World";
console.log("111");
console.log(this.$refs.children.$el.textContent); // Hello
this.$nextTick(() => {
console.log("222");
console.log(this.$refs.children.$el.textContent); // Hello, World
});
console.log("333");
},
},
};
</script>

结果可见,this.$nextTick() 内回调函数是异步执行的,所以先打印 “333”, 再打印 “222”。而且,等子组件视图更新结束之后,才执行 this.$nextTick() 内回调函数,保证操作到最新的 DOM。
⚠️ 注意:虽然 this.$nextTick() 方法可以解决异步更新导致的问题,但如果过度使用该方法会导致性能问题。因此,在实际开发中,只有在必要的情况下才应该使用 $nextTick() 方法。
在 Vue 2.2.0+ 中,this.$nextTick() 返回一个 Promise,因此你可以用 async/await 语法:
async updateMessage() {
this.message = '消息已更新!';
await this.$nextTick();
console.log('DOM 已更新:', this.$refs.message.textContent);
}
7.1 常见应用场景
7.1.1 获取更新后的 DOM 内容
当你修改了数据后,Vue 会异步更新 DOM。如果你需要操作更新后的 DOM 元素,可以使用 this.$nextTick()。
<template>
<div>
<p ref="message">{{ message }}</p>
<button @click="updateMessage">更新消息</button>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
};
},
methods: {
updateMessage() {
this.message = '消息已更新!';
this.$nextTick(() => {
// 确保 DOM 已更新
console.log('更新后的内容:', this.$refs.message.textContent); // 输出: 消息已更新!
});
}
}
};
</script>
7.1.2 初始化第三方库
某些第三方库(如图表库、地图库等)需要在 DOM 渲染完成后初始化。使用 this.$nextTick() 可以确保 DOM 已经准备好。
<template>
<div ref="chart" style="width: 100%; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts';
export default {
mounted() {
this.$nextTick(() => {
// 确保 DOM 已渲染
const chart = echarts.init(this.$refs.chart);
chart.setOption({
title: {
text: '示例图表'
},
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 200, 150, 80, 70, 110, 130],
type: 'bar'
}
]
});
});
}
};
</script>
7.1.3 表单验证或焦点管理
在表单验证或焦点管理中,可能需要等待 DOM 更新完成后才能进行操作。
<template>
<div>
<input ref="input" v-model="inputValue" />
<button @click="validateAndFocus">验证并聚焦</button>
<p v-if="error" style="color: red;">{{ error }}</p>
</div>
</template>
<script>
export default {
data() {
return {
inputValue: '',
error: ''
};
},
methods: {
validateAndFocus() {
if (!this.inputValue) {
this.error = '输入不能为空';
this.$nextTick(() => {
// 确保错误信息已显示,然后聚焦输入框
this.$refs.input.focus();
});
} else {
this.error = '';
}
}
}
};
</script>
7.1.4 动态组件或路由切换
在动态组件或路由切换时,可能需要等待新组件渲染完成后再执行某些操作。
<template>
<div>
<router-view ref="routerView"></router-view>
</div>
</template>
<script>
export default {
watch: {
'$route'() {
this.$nextTick(() => {
// 确保新路由的组件已渲染
this.$refs.routerView.$el.scrollIntoView();
});
}
}
};
</script>
7.1.5 与 v-if 或 v-show 结合使用
当使用 v-if 或 v-show 控制元素的显示时,可能需要等待元素渲染完成后再执行操作。
<template>
<div>
<button @click="toggle">切换显示</button>
<div v-if="isVisible" ref="content">
这是动态显示的内容
</div>
</div>
</template>
<script>
export default {
data() {
return {
isVisible: false
};
},
methods: {
toggle() {
this.isVisible = !this.isVisible;
this.$nextTick(() => {
// 确保 DOM 已更新
if (this.isVisible) {
this.$refs.content.style.color = 'red';
}
});
}
}
};
</script>
总之,合理使用 this.$nextTick(),可以确保在 DOM 更新完成后执行逻辑,避免因 DOM 未更新而导致的问题。
7.2 与 updated 区别
this.$nextTick:在当前 DOM 更新周期结束后执行回调函数。适用于需要在数据变化后立即访问更新后的 DOM 的情况。updated生命周期钩子:在组件因为数据变化而重新渲染后调用。适用于在组件更新后执行某些操作的情况。
选择哪种方式取决于你的具体需求:
- 如果你需要在特定的数据变化后立即执行某些操作,使用
this.$nextTick。 - 如果你需要在组件每次更新后执行某些操作,使用
updated生命周期钩子。
7.3 与 process.nextTick 区别
process.nextTick 是 Node.js 中的一个方法,用于将回调函数推迟到 当前事件循环的末尾 执行。
使用场景:
- 延迟执行:在当前事件循环结束后立即执行某些操作。
- 确保异步顺序:在某些情况下,确保某些操作在当前事件循环的其他操作之后执行。
console.log('开始');
process.nextTick(() => {
console.log('nextTick 回调');
});
console.log('结束');
// 输出顺序:
// 开始
// 结束
// nextTick 回调
this.$nextTick() 用于 Vue.js 中,确保在 DOM 更新后执行某些操作。process.nextTick 用于 Node.js 中,将回调函数推迟到当前事件循环的末尾执行。
7.4 应用
ajax 获取了左侧菜单的列表树,在 ajax 的 success 方法中更新菜单数的数据源 menuTreeListData,更新数据源后,希望能 高亮 id=5 的菜单。
如果这样写:
success: (resp) => {
this.menuTreeListData = resp.data
this.hightlightNode(5)
}
这样不一定能达到你要的效果,因为高亮操作的时候,数据源虽然更新了,但是 DOM 有可能还没渲染完成,这时候你操作高亮 DOM 是找不到的。
这时,就需要用 this.nextTick()。
success: (resp) => {
this.menuTreeListData = resp.data;
let _this = this;
this.nextTick(function(){
_this.hightlightNode(5);
});
}
1985

被折叠的 条评论
为什么被折叠?



