共计 3423 个字符,预计需要花费 9 分钟才能阅读完成。
前言
最近我的项目上有个需要就是做下拉列表的四级联动,应用的是 vuejs + elementui,应用数组存储对象的模式做为列表渲染到页面上的数据,然而在下拉列表联动的时候发现几个问题,当初记录下解决办法,分享给大家。
- 批改对象数组后前端页面不从新渲染
- 查看或者编辑回显数据时,联动数据渲染出错(只显示 key,不显示 name)
对于简单数据处理
之前在写 React 的时候,简单一点的数据会通过 Immutable.js 来实现,通过 get 和 set 来实现数据的设置和读取,以及深层拷贝等性能,当初到了 Vue 发现数据简单一点就不晓得如何解决,第三方对于 vue 的 immutable.js 框架也没有理解过,前面有工夫能够关注并学习下(大家有应用过的能够分享给我)。
四级联动问题解决办法
- 问题一:批改对象数组后前端页面不从新渲染
这个问题其实 Vue 官网也阐明过对于数组变动不会从新渲染页面的问题。
Vue 不能检测以下数组的变动:
当你利用索引间接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
当你批改数组的长度时,例如:vm.items.length = newLength
举个例子:
var vm = new Vue({
data: {items: ['a', 'b', 'c']
}
})
vm.items[1] = ‘x’ // 不是响应性的
vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种形式都能够实现和 vm.items[indexOfItem] = newValue 雷同的成果,同时也将在响应式零碎内触发状态更新:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
你也能够应用 vm.$set 实例办法,该办法是全局办法 Vue.set 的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
为了解决第二类问题,你能够应用 splice:
vm.items.splice(newLength)
因而解决办法就是代码里应用Vue.set(vm.items, indexOfItem, newValue)
,上面就演示个例子:
export default {data(){
return {
arrys :[
{
one: '',
oneList: Promise: getOneList(),
two: '',
twoList: Promise: getTwoList(one),
three: '',
threeList: Promise: getThreeList(two),
four: '',
fourList: Promise: getFourList(three),
}
]
}
},
methods: {
// one 下拉列表 change 事件
oneChange(key, index){this.getTwoList(key).then(res => {this.arrys.forEach((item, i) => {if (i === index) {
// 因为是四级联动,所以 change one 之后,two、three 和 four 都要置空
let newitem = {two: [],
twoList: res,
three: '',
four: '',
threeList: [],
fourList: []}
// 阐明:批改 arrys 中第 i 个的数据,只有应用 Vue.set 页面才会从新渲染
// newitem 会笼罩 item 中的数据,并生成一个新的援用指针
Vue.set(this.arrys, i, Object.assign({}, item, newitem))
}
})
});
},
// two 下拉列表 change 事件
twoChange(key, index){ },
// three 下拉列表 change 事件
threeChange(key, index){ },
// four 下拉列表 change 事件
fourChange(key, index){ },
// 获取 one 列表
getOneList(){},
// 获取 two 列表
getTwoList(oneKey){ },
// 获取 three 列表
getThreeList(twoKey){ },
// 获取 four 列表
getFourList(threeKey){}}
}
依照下面的代码就能够实现四级联动及 change 的时候页面可能动静渲染,这样就实现了联动成果以及批改对象数组后前端页面不从新渲染问题了。
- 问题二:查看或者编辑回显数据时,联动数据渲染出错(只显示 key,不显示 name)
这个问题是这样的:咱们保留到后盾数据 one、two、three 和 four,而 oneList、twoList、threeList 和 fourList 不必保留(通过另外接口获取,并每次关上的时候都去调用),之后咱们查看和编辑上一次的四级联动的时候,咱们发现下拉列表中 one、two、three 和 four 只显示 key,不显示 name,起因就在于 oneList、twoList、threeList 和 fourList 比 one、two、three 和 four 数据赋值时要“慢”,因为是异步的关系,所以当 list 回调回来的时候,页面曾经渲染了,所以不胜利,因而就呈现了问题二:只显示 Key,不显示 name 的问题。
那么如何解决这慢的问题呢?咱们能够应用 Promise.all 来解决。
// 假如 res 是后盾返回的要渲染到页面上的四级联动数组数据
let resdata = res;
// 给 one、two、three 和 four 赋值
resdata.forEach(item => {
this.arrys.push({
one: item.one,
two: item.two,
three: item.three,
four: item.four
})
})
// 获取 twoList(阐明:因为 oneList 是首级,所以间接获取就好,这里就不展现代码了)
Promise.all(resdata.map(item => this.getTwoList(item.one)))
.then(twoListData => {twoListData.forEach((data, i) => {this.arrys[i].twoList = data;
})
})
// promise 获取 threeList 列表
Promise.all(resdata.map(item => this.getThreeList(item.two)))
.then(threeListData => {threeListData.forEach((data, i) => {this.arrys[i].threeList = data;
})
})
// promise 获取 fourList 列表
Promise.all(resdata.map(item => this.getFourList(item.three)))
.then(fourListData => {fourListData.forEach((data, i) => {this.arrys[i].fourList = data;
})
})
为什么要写三次 Promise.all?因为 forEach 是异样的,所以不能在 forEach 外面循环获取 Promise 来给 arrys 赋值,如果大家有更好的办法能够提出来。
这样就解决了第二个问题。
总结
1、可能有人会问:为什么不把 oneList 和 twoList 设置成公共的列表,和 arrys 数组离开,这样不是更不便读取吗?答案是:不能,因为是四级联动,所以只能每个对象外面保留一份 oneList 和 twoList,构想一下:如果 arrys 数组外面有三条数据,我扭转了第一条的 one,那么 twoList 就会变动,而第二条的 twoList 也就跟着变了,这就是不是独自的四级联动了,而是所有 twoList 都跟着动了!
2、el-select 只有独自赋值 key 和 list,就能显示对应的 name(阐明当 key 赋值下来的时候,el-select 的 list 就去找对应的,找到了就显示出名称 name)
3、做的过程中发现有个问题:change 的时候发现 two 和 three 还有 four 只显示 key,不显示 name,起初发现是因为应用了 ht-select 而没有用 elementUI 自带的 el-select,换成之后就没问题了,也算一个小插曲吧。
援用
学习应用 Promise