vue2中使用template包裹了两个el-button,并且template添加了判断条件,但是当showSteps值变化为3时,其中设置了disabled的‘生成’按钮禁用属性失效,仍然可以点击,elementui版本:2.15.14;webpack版本:3.12.0,vue版本:2.7.16 代码如下
<template>
<div>
<el-input-number v-model="showSteps"></el-input-number>
<el-button size="small" :disabled="!canSave">关闭</el-button>
<template v-if="![3, 4, 6].includes(showSteps)">
<el-button v-if="showEdit" size="small">edit</el-button>
</template>
<template v-if="showSteps === 3">
<el-button type="success" size="small">赋值</el-button>
<el-button type="primary" size="small" :disabled="!canSave">生成</el-button>
</template>
<template v-else>
<el-button v-if="false" type="primary" size="small" :disabled="!canSave">next</el-button>
</template>
</div>
</template>
<script>
export default {
data() {
return {
canSave: false,
showSteps: 1,
dataStep: 4,
}
},
computed: {
showEdit() {
return this.showSteps <= this.dataStep && this.editStep !== this.showSteps
}
},
}
</script>
目前已知将template标签更换为span、或者为’生成’按钮添加key可以解决这个问题,求助各位是什么样原因导致了这个问题
使用template标签包裹的话,必须严格的v-if + v-else-if + v-else判断就不会出问题
为什么用 v-if 判断会失效?
每个模块会单独挂载/销毁每一块 DOM,造成:
- 条件切换时原有的 DOM 可能被销毁又重新创建;
- 某些状态(比如绑定的 :disabled)会丢失或初始化异常;
- 尤其在 template 里嵌套多个块的时候,Vue 的虚拟 DOM diff 策略可能出现不稳定行为。
为什么用 v-else-if 就没问题?
因为 v-if + v-else-if + v-else 是一个连续块,Vue 会把它们当作一个整体处理,不会销毁和重建 DOM,而是根据条件“启用或禁用当前分支”。 这样状态就不会中间被“抛失”,所有绑定(比如 :disabled)也会正确应用。这样就能保证:
- 所有分支是“互斥”的;
- Vue 渲染时只保留一个逻辑分支;
- DOM 不被反复销毁与重建,响应式绑定更稳定。
那为什么将template换成span也是可以的?
原因是:<template> 本身不渲染成实际 DOM 元素
- 每个 <template> 是“虚拟容器”,Vue 会动态添加/移除内部元素;
- 如果条件快速变化(比如 condA → condB → condA),Vue 可能需要频繁地销毁/重建里面的 <button>;
- 这会造成状态丢失,或者某些属性(如 :disabled)暂时失效。
span又是好的,原因:
- <span> 是真实 DOM 元素,Vue 会保留这段元素,即使它当前不显示;
- 因为真实 DOM 存在,Vue 的 Virtual DOM diff 算法会尽量复用已有 DOM,不会反复销毁重建;
- 所以按钮状态更稳定,像 :disabled 不容易失效。
当然加key的原因这个就不用说了,显式根据key重新渲染保证渲染一致性。
Edit
看起来是 diff 算法的问题,认为是同一个node节点了。
可以这样修改一下👇
<template v-if="![3, 4, 6].includes(showSteps)">
<el-button v-if="showEdit" size="small">edit</el-button>
</template>
- <template v-if="showSteps === 3">
+ <template v-else-if="showSteps === 3">
<el-button type="success" size="small">赋值</el-button>
<el-button type="primary" size="small" :disabled="!canSave">生成</el-button>
</template>