
本文讲解如何在 vue 2 中通过 `this.$set` 正确为 bootstrap table 的 `items` 数组项动态添加响应式属性(如 `state`),解决因直接赋值导致 dom 不更新的问题。
在 Vue 2 中,响应式系统依赖于对象属性的 getter/setter 代理机制。当你对已存在的响应式对象(如 this.customItems[i])直接新增属性(例如 item.state = true),Vue 无法自动侦测该变化,因此模板中 v-if="row.item.state" 始终读取为 undefined,即使 console.log 显示数据已写入——这是因为新属性未被纳入响应式追踪。
✅ 正确做法:使用 this.$set
必须使用 this.$set(target, key, value)(或全局 Vue.set)显式声明新属性,确保其响应式生效:
methods: {
isSingleRow(event) {
this.singleRow.push(event);
for (let i in this.customItems) {
// ❌ 错误:非响应式赋值
// this.customItems[i].state = this.singleRow[i];
// ✅ 正确:强制创建响应式属性
this.$set(this.customItems[i], 'state', this.singleRow[i]);
console.log('EHO ', i, ' state:', this.customItems[i].state);
}
}
}? 提示:this.$set 是 Vue 2 提供的官方 API,专用于向响应式对象/数组中添加新属性并触发视图更新。
? 补充说明与最佳实践
-
为什么 created() 中 emit 不可靠?
子组件 created 钩子执行时,父组件的 customItems 可能尚未完成初始化或异步加载,导致 singleRow 索引错位。建议改为监听 items 更新后触发逻辑,例如:watch: { customItems: { handler() { // 确保 items 已就绪再批量初始化 state this.customItems.forEach((item, index) => { this.$set(item, 'state', this.singleRow[index] ?? false); }); }, immediate: true, deep: true } } -
子组件优化建议
当前子组件 tableRowsLength() 在 created 中调用,但未考虑 innerTableItems 是否已从 API 加载完成。应结合 v-if 或 watch 等待数据就绪:watch: { innerTableItems: { handler() { if (this.innerTableItems.length) { this.$emit('onitembind', this.innerTableItems.length !== 1); } }, immediate: true } } -
模板中正确引用 slot
注意你原代码中 是独立于的,需确保它位于 标签内部且语法正确(注意引号为英文):
✅ 总结
| 问题 | 解决方案 |
|---|---|
| row.item.state 在模板中为 undefined | 使用 this.$set(obj, 'state', value) 替代直接赋值 |
| 子组件过早 emit 导致索引不匹配 | 改用 watch 监听数据就绪后再通信 |
| 模板结构混乱影响 slot 渲染 | 确保所有 v-slot 模板均置于 |
遵循上述方式,即可实现父子组件间表格行状态(true/false)的可靠、响应式同步,确保 Bootstrap Table 的条件渲染(如图标显示)实时生效。










