Vue页面刷新时动态创建的计算属性未找到报错解决方案
问题原因
你在created钩子中动态给this.$options.computed添加属性的写法时机不对。
Vue实例初始化时,会在beforeCreate和created两个钩子之间完成data、computed、methods等选项的解析、响应式绑定、实例代理工作。等created钩子触发时,所有计算属性已经初始化完成,这时候再往配置里加新的计算属性,Vue不会重新执行初始化逻辑,实例上自然找不到对应属性,刷新页面直接初始化渲染就会抛错。
路由切换时偶然生效是组件复用、配置热更新带来的巧合,不属于稳定可复用的逻辑。
可复用实现方案
推荐两种无兼容问题的写法,都可以很方便封装后跨组件复用。
方案1:工具函数扩展(最稳定,和Vuex原生map辅助函数用法一致)
直接抽离一个生成计算属性配置的工具函数,在组件的computed选项里展开使用即可,完全不碰实例运行时修改配置的逻辑,没有任何时序问题:
// 抽成公共工具,比如放在src/utils/vuex.js里 /** * 生成绑定message模块state的双向计算属性 * @param {string[]} propKeys 要绑定的字段名列表 */ export function mapMessageProps(propKeys) { return propKeys.reduce((computedConfig, key) => { computedConfig[key] = { get() { return this.getMessageProp(key) }, set(value) { this.setMessageProp([key, value]) } } return computedConfig }, {}) }
组件中使用:
import { mapMessageProps } from '@/utils/vuex' export default { computed: { // 其他自定义计算属性 xxx() { /* ... */ }, // 直接展开生成的配置即可 ...mapMessageProps(['messageText', 'location']) } }
方案2:Mixin封装(支持自定义字段声明,组件代码更简洁)
如果想进一步简化组件内写法,可以用mixin封装,注意要把动态添加计算属性的逻辑挪到beforeCreate钩子里执行——这个钩子触发时Vue还没开始解析computed配置,修改完配置再进入初始化流程就能被正常识别:
// 公共mixin,比如src/mixins/vuexMessage.js export default { beforeCreate() { // 读取组件上声明的stepProps字段,支持数组格式 const syncProps = this.$options.stepProps if (!Array.isArray(syncProps) || !syncProps.length) return // 初始化computed配置 this.$options.computed = this.$options.computed || {} syncProps.forEach(key => { // 已经手动定义过的属性不覆盖 if (this.$options.computed[key]) return this.$options.computed[key] = { get() { return this.getMessageProp(key) }, set(value) { this.setMessageProp([key, value]) } } }) } }
组件中使用:
import vuexMessageMixin from '@/mixins/vuexMessage' export default { mixins: [vuexMessageMixin], // 只要声明需要双向绑定的字段名即可,不需要重复写get/set stepProps: ['messageText', 'location'], // 其他业务逻辑正常写 }
两种方案都支持任意数量的属性扩展,刷新页面、路由切换场景下都能正常运行,不存在你之前遇到的属性找不到的问题。
内容的提问来源于stack exchange,提问作者Jamal Ali
相关产品推荐
相关产品推荐

