You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue v-if条件未满足时内部子组件仍提前接收数据问题排查

问题现象

在v-if绑定条件未满足的预期下,嵌套的PkSelect子组件提前触发渲染、接收到了传入的props值,相关代码与日志如下:

模板代码

<div v-if="mappingData && mappingData.length && !loading">  
    <div v-for="element in mappingData" :key="element.attribute" >          
        <PkSelect :preselectIndex="[element.value]" 
:options="element.select_options" v-model:optionIndexModel="element.value"></PkSelect>
    </div>
</div>

递归赋值逻辑

const recursiveFuzzyFill = () => {
    let awaitme = new Promise((resolve, reject) => {
        try {
            if (mappingData.value[loopIndex] && fuse.search(mappingData.value[loopIndex].label).length) {
                var refIndex = fuse.search(mappingData.value[loopIndex].label)[0].refIndex;
                mappingData.value[loopIndex].value = refIndex;
                console.log("Value:", mappingData.value[loopIndex].value);
                resolve();
            } else {
                resolve();
            }
        } catch (error) {
            reject();
            loopIndex = 0;
            return;
        }
    });

    awaitme.then(() => {
        if (loopIndex === (mappingData.value.length - 1)) {
            setTimeout(() => {
                loopIndex = 0;
                loading.value = false;
                console.log("Loading:", loading.value);
            }, 5000);
            return;
        } else {
            loopIndex++;
            recursiveFuzzyFill();
        }
    });
}

实际运行日志

Value: 16
PkSelect.vue:709 Preselect Index: 16
PkSelect.vue:709 Preselect Index: null
PkSelect.vue:709 Preselect Index: null
PkSelect.vue:709 Preselect Index: null
PkSelect.vue:709 Preselect Index: null
PkSelect.vue:709 Preselect Index: null
PkSelect.vue:709 Preselect Index: null
ConfigMapping.vue:184 Value: 27
ConfigMapping.vue:184 Value: 13
ConfigMapping.vue:184 Value: 18
ConfigMapping.vue:201 Loading: false

预期逻辑是loading在所有数据处理完成5秒后置为false,此时v-if条件才满足、子组件才渲染,但实际子组件在日志输出第一行Value:16时就已经开始接收参数。

问题产生原因

这个现象是三个执行时序问题叠加造成的:

  • loading状态控制逻辑本身有漏洞:翻遍recursiveFuzzyFill的代码,只有最后5秒延时回调里设置了loading.value = false,没有任何代码在数据处理开始时将loading设为true。如果loading初始值就是false,那只要mappingData被赋值为非空数组,v-if的三个判断条件直接全部满足,根本不会等你那5秒延时。如果你本来设了loading初始值为true,那大概率是给mappingData赋值的时机早于你把loading设为true的时机,首次响应式更新时v-if条件已经短暂成立,直接触发了子组件渲染。
  • Vue的DOM更新本身是异步批量执行的:所有响应式状态的修改不会立刻触发DOM重渲染,Vue会把更新任务推到微任务队列,等当前同步代码执行完后统一处理。你写的递归逻辑里,new Promise传入的executor是完全同步运行的,then回调也属于微任务,和Vue的DOM更新任务在同一个队列里。当你第一次给mappingData第一项赋值value=16时就触发了响应式,组件更新任务立刻入队,这时候你后续的递归逻辑(给其他项赋值、最后设置loading状态)还排在微任务队列更靠后的位置,DOM更新先执行,直接渲染出了只完成第一项赋值的PkSelect组件,打出第一条Preselect Index:16和剩下6条null的日志。
  • 无意义的Promise封装打乱了执行顺序:你的fuse搜索逻辑全是同步代码,根本不需要用Promise包裹。现在的写法把递归逻辑放在then回调里,人为拉长了微任务执行链,直接导致Vue的DOM更新任务插在了第一次赋值和后续递归赋值的中间,才出现组件提前渲染、只拿到部分数据的情况。

从日志就能验证这个判断:7条PkSelect的preselect日志全部出现在后面3条Value日志之前,说明组件在你处理完第一个元素的时候就已经完成首次挂载了,后面给其他元素赋值属于组件挂载后的props更新,如果你的preselectIndex相关逻辑只在组件mounted阶段执行,自然不会再打印新的preselect日志。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:27:19