前言

最近我的项目上有个需要就是做下拉列表的四级联动,应用的是vuejs + elementui,应用数组存储对象的模式做为列表渲染到页面上的数据,然而在下拉列表联动的时候发现几个问题,当初记录下解决办法,分享给大家。

  1. 批改对象数组后前端页面不从新渲染
  2. 查看或者编辑回显数据时,联动数据渲染出错(只显示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