You need to enable JavaScript to run this app. Vue组件初始化前动态属性值初始化方案咨询,created阶段$refs为空
优惠活动
大模型
产品
解决方案
定价
更多

Vue组件初始化前动态属性值初始化方案咨询,created阶段$refs为空

问题描述

需要给Vue.js组件绑定动态属性,且需绑定复合值,但不清楚应在何时何处初始化这些属性的默认值。尝试在created()生命周期钩子中执行初始化操作,但此时this.$refs为空。
自定义的MyField类除值本身外,还包含enabled等扩展属性。项目不使用静态属性,模板中仅字段名是静态的,且字段名同时作为属性名。所有模板对应的script内容均为通用逻辑,可通过mixin等方式注入。

示例代码如下:

<template>
  <enhanced-field type='text' v-model="meta$['name'].value" ... ref="name" :disabled="!meta$['name'].enabled" />
</template>
<script>
export default {
   data() {
     return {
       meta$: new Map() // 可替换为vuex store
     }
   },
   created() {
      // 此处尝试初始化默认值,但此时this.$refs为空
      Object.keys(this.$refs).forEach((field) => {
            var v = this.meta$[field];
            if (!v) 
                this.meta$[field] = new MyField(this.$refs[field].nodeName);
        });
   },
   // ....
}
</script>

2021.11.25 更新

背景

应用有统一控制器处理表单提交,会根据组件事件处理的静态配置跳转新页面,事件处理数据不以JavaScript函数存储,而是作为页面的XML标签存在,因此数据不是页面加载后获取,而是在进入页面前就已完成获取。常规情况下每个页面无需编写自定义JavaScript函数,所有逻辑均在页面XML中配置,Vue的事件处理逻辑会将配置的处理数据转换为JavaScript执行,目标是将遗留系统迁移到基于Vue.js的版本。

临时解决方案

跳转新页面前,将页面数据存入名为pending的键值对变量并挂载到route对象上,在beforeRouteEnter钩子中将route上的pending数据移动到页面级数据容器(例如$thisPageVM.data$,键值对结构),之后所有字段的mounted钩子会尝试从该页面级容器获取数据,若不存在则初始化默认值并回存到页面级容器。数据本身存储在页面级,每个字段保留一份computed副本,表单提交时会发送该页面级容器的数据。

现存技术问题

字段的model是computed变量val,该computed变量在mounted钩子触发前就被调用,因此需要在mounted钩子中调用this.$recompute('val')重新初始化其值,$recompute是Vue2版本下的hack实现方案。


解决方案

核心矛盾为created阶段DOM还未挂载,$refs必然为空,所有依赖DOM节点、子组件实例的初始化逻辑都不能放在这个阶段执行,结合项目场景,有三个优化方向可以完全规避当前需要hack$recompute的问题:

  • 针对不需要依赖$refs属性的初始化逻辑:页面数据在进入页面前就已经全部获取完成,完全可以在beforeRouteEnter钩子中一次性完成所有meta$字段的初始化,不需要等待子组件mounted触发再逐个初始化,此时初始化完成的数据在computed首次调用时就已经存在,不需要后续重新计算。
  • 针对必须依赖$refs的初始化逻辑:统一移到mounted钩子中执行,Vue2中mounted触发时所有子组件已经完成挂载,$refs可以正常访问。如果需要等待所有异步子组件全部挂载完成,可以在mounted中加一层$nextTick包裹初始化逻辑:
mounted() {
  this.$nextTick(() => {
    // 此处$refs已完全填充,执行初始化逻辑即可
    Object.keys(this.$refs).forEach((field) => {
      if (!this.meta$[field]) {
        // 使用$set赋值保证Vue2的响应式触发
        this.$set(this.meta$, field, new MyField(this.$refs[field].nodeName))
      }
    })
  })
}
  • 如果要保留现有每个字段自己初始化的逻辑,不需要用hack的$recompute:给val这个computed的依赖项设置一个初始的响应式标记位,初始化完成后修改标记位触发computed自动重新计算即可。

内容的提问来源于stack exchange,提问作者Daniel Yang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 05:36:07