Vue实现数组四级联动

更新日期: 2021-08-13阅读: 1.1k标签: 数组

前言

最近项目上有个需求就是做下拉列表的四级联动,使用的是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,换成之后就没问题了,也算一个小插曲吧。


链接: https://www.fly63.com/article/detial/10636

探索JavaScript数组奥秘

avaScript数组同后端语言一样,具有它自己的数据结构,归根结底,这种数据结构,本质就是一种集合。在后端语言中(如java,.net等),数组是这样定义的:数组是用来存储相同数据类型的集合

js使用数组+循环+条件实现数字转换为汉字的简单方法。

单个数字转汉字的解决方法:利用数组存储0-9的汉字、 ary.length和str.length不用多说,这是指ary数组和str字符串的长度。这里我们需要注意的是str.charAt(j)和ary[i],分别指在str这个字符串中索引为j的元素,在ary中索引为i的元素。

[译]async-await 数组循环的几个坑

在 Javascript 循环中使用 async/ await 循环遍历数组似乎很简单,但是在将两者结合使用时需要注意一些非直观的行为。让我们看看三个不同的例子,看看你应该注意什么,以及哪个循环最适合特定用例。

数组、字符串去重

今天说的数组和字符串去重呢,主要用到es6新的数据结构 Set,它类似于数组,但是成员的值都是唯一的,没有重复的值,所以活用Set来进行数组和字符串的去重。

JavaScript 数组方法

数组方法:1、Array.join([param]) 方法:将数组中所有的元素都转换为字符串并连接起来,通过字符 param 连接,默认使用逗号,返回最后生成的字符串2、Array.reverse() 方法:将数组中的元素颠倒顺序(在原数组中重新排列它们),返回逆序数组

如何删除JavaScript 数组中的虚值

falsy(虚值)是在 Boolean 上下文中已认定可转换为‘假‘的值.JavaScript 在需要用到布尔类型值的上下文中使用强制类型转换(Type Conversion )将值转换为布尔值,比如:在条件语句或者循环语句中。

JavaScript中十种一步拷贝数组的方法

JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下。扩展运算符(浅拷贝)自从ES6出现以来,这已经成为最流行的方法。

JS数组的几个经典api

本文主要来讲数组api的一些操作,如简单实现扁平化n维数组、数组去重、求数组最大值、数组求和、排序、对象和数组的转化等。扁平化嵌套数组/展平和阵列孔——flat()

关于Vue不能监听(watch)数组变化

vue无法监听数组变化的情况,但是数组在下面两种情况下无法监听:利用索引直接设置数组项时,例如arr[indexofitem]=newValue;修改数组的长度时,例如arr.length=newLength

JS计算两个数组的交集、差集、并集、补集(多种实现方式)

使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本,使用 ES5 语法来实现虽然会麻烦些,但兼容性最好,不用考虑浏览器 JavaScript 版本。也不用引入其他第三方库。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!