Vue项目代码只执行一次:所有方案完整合集(Vue2+Vue3全覆盖)
在Vue开发中,让某段代码只执行一次是非常高频的需求。不管是初始化请求接口、全局配置、监听触发一次,还是执行初始化逻辑,核心诉求都是:确保指定代码在指定时机只会被执行一次,后续无论组件刷新、数据变化、页面重渲染都不会重复执行。
Vue中针对代码只执行一次有精准的、分场景的最优方案。下面按使用频率和优先级从高到低排序,覆盖99%的业务场景,区分Vue2和Vue3两种主流写法(选项式/组合式),代码可直接复制使用。
一、重要前提:先明确执行时机
所有方案的选择,只取决于一个问题:你希望这段只执行一次的代码,在什么时机执行?
Vue中只有3类核心执行时机,对应不同最优方案:
时机1:组件初始化完成后,永久只执行一次(99%的业务场景,最常用)
场景举例:组件加载后只请求一次初始化接口、只创建一次定时器或监听事件、只初始化一次第三方插件(echarts、地图)、只执行一次数据初始化逻辑
核心特点:组件从创建到销毁,这段代码只会执行1次
时机2:监听某个变量变化时,只执行1次
场景举例:监听父组件传入的props变量、监听自身的data或ref变量,变量第一次变化时执行代码,后续再变化不再执行
时机3:整个项目运行期间,永久只执行1次
场景举例:项目启动后只请求一次用户信息或全局配置、只初始化一次全局过滤器或全局指令、只执行一次全局初始化逻辑
核心特点:项目从启动到关闭,这段代码全程只会执行1次,哪怕切换所有页面、刷新组件都不会重复执行
二、方案一:组件初始化后永久执行一次(最优首选)
核心原理
利用Vue的生命周期钩子函数。Vue组件有固定的生命周期,其中初始化阶段的钩子函数,组件的一生只会触发一次。这是Vue官方设计的、专门用来执行组件初始化一次性逻辑的方案,无任何副作用、性能最优、写法最简单,优先级最高。
Vue2写法(选项式API)
Vue2中,组件初始化阶段有两个核心钩子,都满足只执行一次:
created:组件数据初始化完成就执行(DOM还未渲染),适合纯数据逻辑(请求接口、数据处理)
mounted:组件DOM渲染完成、挂载到页面后执行,适合所有逻辑(既可以处理数据,也可以操作DOM)
推荐用mounted,兼容所有场景。
<template>
<div>Vue2 组件</div>
</template>
<script>
export default {
data() {
return {
msg: "Vue2 只执行一次"
};
},
mounted() {
console.log("这段代码,组件一辈子只会执行一次");
this.initData();
},
methods: {
initData() {
console.log("执行初始化逻辑,只执行一次");
// 示例:请求初始化接口
// this.$axios.get("/api/init").then(res => {})
}
}
};
</script>Vue3写法
写法一:Vue3选项式API(和Vue2完全一致)
<script>
export default {
mounted() {
console.log("Vue3选项式 - 代码只执行一次");
this.initData();
},
methods: {
initData() {
// 你的一次性逻辑
}
}
};
</script>写法二:Vue3组合式API script setup(官方推荐)
<template>
<div>Vue3 组件</div>
</template>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
console.log("Vue3组合式 - 这段代码只执行一次");
initData();
})
const initData = () => {
console.log("Vue3 初始化逻辑执行");
// 你的业务代码:请求接口、初始化插件等
}
</script>补充说明:Vue3的<script setup>里的顶层代码(不在任何函数内的代码),也是组件初始化时执行一次,效果等价于created。
<script setup>
console.log("这段顶层代码,也是组件初始化只执行一次");
import { onMounted } from 'vue'
onMounted(() => { console.log("挂载后执行一次") })
</script>三、方案二:监听变量变化时只执行1次代码(精准场景)
适用场景
监听props变量、自身变量、全局变量,变量第一次发生变化时执行一次指定代码,后续再变化不再执行。
场景举例:父组件传值给子组件,子组件监听到值变化后只请求一次接口;监听搜索关键词,只在关键词第一次变化时执行一次过滤逻辑。
方式1:监听中执行后立即取消监听(最推荐,逻辑最优雅)
核心原理:给监听绑定一个停止监听函数,在监听的回调函数中执行完代码后立即调用这个函数停止监听,后续变量再变化监听就失效了。
Vue2写法
<script>
export default {
props: {
initVal: { type: Number, default: 0 }
},
watch: {
initVal(newVal) {
console.log("监听变量变化,执行一次代码");
this.doSomething(newVal);
this.$watch('initVal', () => {}).unwatch();
}
},
methods: {
doSomething(val) {
// 你的业务逻辑,只执行一次
}
}
};
</script>Vue3组合式写法
<script setup>
import { watch } from 'vue'
const props = defineProps({ initVal: { type: Number, default: 0 } })
const stopWatch = watch(
() => props.initVal,
(newVal) => {
console.log("Vue3监听变量,只执行一次");
doSomething(newVal);
stopWatch();
}
)
const doSomething = (val) => {
// 你的代码
}
</script>方式2:通过开关变量做标记控制执行(万能通用)
核心原理:定义一个布尔类型的开关变量(比如isExecuted),默认false。在监听回调中先判断开关是否为false,如果是则执行代码并把开关设为true。后续变量变化时开关是true,就不会再执行。
优点:逻辑简单、易理解、无任何API依赖、Vue2/Vue3通用、可灵活控制开关。
Vue3组合式写法
<script setup>
import { ref, watch } from 'vue'
const props = defineProps({ initVal: Number })
const isExecuted = ref(false)
watch(
() => props.initVal,
(newVal) => {
if (!isExecuted.value) {
console.log("通过开关标记,代码只执行一次");
doSomething(newVal);
isExecuted.value = true;
}
}
)
const doSomething = (val) => {
// 业务逻辑
}
</script>Vue2写法
<script>
export default {
data() {
return { isExecuted: false }
},
props: { initVal: Number },
watch: {
initVal(newVal) {
if (!this.isExecuted) {
this.doSomething(newVal);
this.isExecuted = true;
}
}
},
methods: {
doSomething(val) {
// 业务逻辑
}
}
};
</script>四、方案三:整个项目运行期间代码只执行一次(全局一次性逻辑)
适用场景
代码从项目启动到项目关闭全程只会执行1次,哪怕切换所有页面、刷新所有组件、路由跳转无数次,都绝对不会重复执行。
场景举例:项目初始化时只请求一次用户信息(token、个人资料)、只初始化一次全局配置(主题、语言)、只注册一次全局插件或全局指令、只执行一次全局埋点逻辑。
方案:在main.js中直接执行(最优首选)
核心原理:main.js是Vue项目的入口文件,项目启动时只会加载和执行一次main.js中的代码,后续所有操作都不会再重新执行这个文件。
Vue2的main.js写法
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
// 这里的代码,项目运行期间只执行一次
console.log("全局一次性逻辑:项目启动时执行");
// 示例1:请求全局用户信息
Vue.prototype.$axios.get("/api/getUserInfo").then(res => {
Vue.prototype.$userInfo = res.data;
})
// 示例2:初始化全局配置
localStorage.setItem("theme", "light");
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')Vue3的main.js写法
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import pinia from './stores'
// 这里的代码,项目运行期间只执行一次
console.log("Vue3全局一次性逻辑");
// 示例:请求全局配置接口
fetch("/api/globalConfig").then(res => res.json()).then(data => {
console.log("全局配置初始化完成");
})
const app = createApp(App)
app.use(router).use(pinia).mount('#app')五、补充:Vue模板中内容只渲染一次(v-once指令)
适用场景
不是代码逻辑只执行一次,而是模板中的DOM内容只渲染一次,后续组件重渲染时这个DOM不会再重新渲染,能优化性能。
核心用法
Vue提供了内置指令v-once,给模板标签加上这个指令后,该标签及其子标签的内容只会被渲染一次,后续无论数据怎么变化都不会再更新渲染。
<template>
<div>
<div>普通渲染:{{ msg }}</div>
<div v-once>只渲染一次:{{ msg }}</div>
<button @click="msg = '新内容'">修改msg</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const msg = ref("初始内容")
</script>效果:点击按钮修改msg,普通标签会显示新内容,带v-once的标签永远显示初始内容。
六、所有方案优先级和场景总结
核心优先级排序(从上到下,优先选上面的)
组件内代码只执行一次 → 用mounted(Vue2)或onMounted(Vue3),99%场景首选
监听变量变化只执行一次 → 用执行后取消监听或开关标记,精准场景首选
全局代码只执行一次 → 直接在main.js中写代码,全局场景唯一最优解
模板内容只渲染一次 → 用v-once指令,模板优化专用
避坑提醒
不要用computed实现代码只执行一次。computed是计算属性,侧重计算值,不是执行逻辑,且会随依赖变化重复执行
不要滥用全局变量标记。组件内的一次性逻辑用生命周期就够了,全局标记只用于全局场景
Vue3的<script setup>顶层代码虽然也只执行一次,但推荐用onMounted。逻辑更清晰,且能操作DOM,无任何限制
一句话速记
组件内一次用mounted,监听一次关监听,全局一次写main,模板一次v-once。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!