问题不太好描述,复现一下场景:
列表页面,通过新增按钮打开弹窗
弹窗中还有列表,通过弹窗中的新增按钮操作列表
列表中有插槽,其中一项点击可以打开新的弹窗
新的弹窗用来勾选数据回显到列表中,处理为当前项的子节点
点确定之后,列表被处理成类似这种效果
通过确定按钮,将勾选的list数组传到父组件,进行赋值操作
然后log打印父组件列表的数据,发现打印有值,但是页面上什么都不展示
解决这种问题,常用的方法有
this.$ set / 扩展运算符 / this.$nextTick /setTimeout
我都试过了,依然不起作用
解决办法是父组件的列表每次新增的时候得有children字段
代码如下:
父组件的新增
addList() {
this.dataSource.push({
id: uuid(),
hasItem: false,
children:[],//必须有
})
},
父组件列表,用的是element文档上树形数据与懒加载示例的第一个
<el-table
row-key="id"
default-expand-all
:data="dataSource"
:tree-props="{ children: 'children' }"
border
ref="table"
highlight-current-row
:height="screenHeight - 500 + 'px'"
class="elTable mgrTable"
style="width: 100%; margin-bottom: 20px"
>
勾选数据后的确定事件
checkTreesure(arr) {
//处理索引,可忽略
let childrenSum = this.dataSource.reduce((sum, item) => {
return sum + (item.children ? item.children.length : 0)
}, 0)
let newIdx = this.checkTreeIndex - childrenSum
if (!this.dataSource[newIdx]) {
this.dataSource.splice(newIdx, 1, {})
}
if (!this.dataSource[newIdx].children) {
this.dataSource[newIdx].children = []
}
//重点,使用this.$set或者直接赋值也可以
this.$set(this.dataSource[newIdx], 'children', arr.map(item => {
return {
id: uuid(),
sizes: item.dictValue,
hasItem: true,
pid: this.dataSource[newIdx].id,
};
}));
//替换写法,直接赋值
// const newArr = arr.map(item => {
// return {
// id: uuid(),
// sizes: item.dictValue,
// hasItem: true,
// pid: this.dataSource[newIdx].id,
// };
// })
// this.dataSource[newIdx].children = newArr
this.$nextTick(() => {
this.$refs.table.doLayout();
});
this.checkTreeVisible = false
},
总结:
这个bug应该不是组件嵌套过深的原因,而是新增的时候没有加children,组件的渲染依赖于特定的数据结构或状态,利用索引直接设置一个项,Vue 可能无法追踪它的变化