阅读 75

element-ui级联选择器因四级联动地址数据过大造成的页面卡顿崩溃的解决方案

应公司产品业务需求,要把所有原有的三级联动数据扩展成四级联动,我们的地址数据是放在前端的,引入四级地址数据后,有时页面会卡顿几秒才出来,或者直接浏览器崩溃了,必须关掉重新打开,经反复测试实验感觉根本原因还是数据量太大造成的。一开始想的延迟渲染该组件的方案都不完美,最后还是想着解决数据量的问题,用动态加载的方法,而不是一开始就把所有的数据给该组件

下面是本小菜自己写的动态加载数据的方法:

在一开始该页面的
Chinese地址数据为null,在加载页面的时候先只加载省级的数据,在点击省份的时候加载进该省的市级数据,在点击市的时候加载该市以下的区级数据,以此类推。所以该页面的地址数据chinese里只会包含(加载进)了有用到过的数据,而不是所有的四级地址数据,看下getOption
方法:

created() {// 获取四级联动省级数据this.chinese = [];for(let i = 0; i < this.$cityTown.length; i++){let obj = {};obj.value = this.$cityTown[i].value;obj.label = this.$cityTown[i].label;obj.children = [];this.chinese.push(obj);}},复制代码

 写在共用js里的getOption方法:

/* 动态加载所需四级联动地址数据方法参数:(当前页面的地址数据(数组), 当前code数组, 当前需要获取数据方式(只有写在change事件里传'change'))例如: (this.chinese, [420000,4200100,420101], 'get')返回(加载进入)新的地址数据*/export const getOption = (chinese, val, type) => {  if (val.length === 1 || (val.length >= 1 && type === 'get')) {    for (let i = 0; i < chinese.length; i++) {      if (chinese[i].value === val[0] && chinese[i].children.length === 0) {        if (cityTown[i].children.length) {          var arr = []          for (let a = 0; a < cityTown[i].children.length; a++) {            let obj = {};            obj.value = cityTown[i].children[a].value;            obj.label = cityTown[i].children[a].label;            if (cityTown[i].children[a].children) {              obj.children = [];            }            arr.push(obj);          }          chinese[i].children = arr;          arr = [];        }        if (val.length === 1) {          return chinese        }      }    }  }  if (val.length === 2 || (val.length >= 2 && type === 'get')) {    for (let i = 0; i < chinese.length; i++) {      if (chinese[i].value === val[0]) {        if (cityTown[i].children.length) {          for (let a = 0; a < cityTown[i].children.length; a++) {            if (chinese[i].children[a].children) {              if (chinese[i].children[a].value === val[1] && chinese[i].children[a].children.length === 0) {                if (cityTown[i].children[a].children.length) {                  var arr1 = [];                  for (let b = 0; b < cityTown[i].children[a].children.length; b++) {                    let obj1 = {};                    obj1.value = cityTown[i].children[a].children[b].value;                    obj1.label = cityTown[i].children[a].children[b].label;                    if (cityTown[i].children[a].children[b].children) {                      obj1.children = [];                    }                    arr1.push(obj1);                  }                  chinese[i].children[a].children = arr1;                  arr1 = [];                }                if (val.length === 2) {                  return chinese                }              }            }          }        }      }    }  }  if (val.length === 3 || (type === 'get' && val.length >= 3)) {    for (let i = 0; i < chinese.length; i++) {      if (chinese[i].value === val[0]) {        if (cityTown[i].children.length) {          for (let a = 0; a < cityTown[i].children.length; a++) {            if (chinese[i].children[a].value === val[1]) {              if (cityTown[i].children[a].children.length) {                for (let b = 0; b < cityTown[i].children[a].children.length; b++) {                  if (chinese[i].children[a].children[b].children) {                    if (chinese[i].children[a].children[b].value === val[2] && chinese[i].children[a].children[b].children.length === 0) {                      if (cityTown[i].children[a].children[b].children.length) {                        var arr2 = [];                        for (let c = 0; c < cityTown[i].children[a].children[b].children.length; c++) {                          let obj2 = {};                          obj2.value = cityTown[i].children[a].children[b].children[c].value;                          obj2.label = cityTown[i].children[a].children[b].children[c].label;                          arr2.push(obj2);                        }                        chinese[i].children[a].children[b].children = arr2;                        arr2 = []                      }                      if (val.length === 3) {                        return chinese                      }                    }                  }                }              }            }          }        }      }    }  }  return chinese}复制代码

这个方法注意使用的时候,如果是用户操作的时候那么触发的是change事件,type要传change,如果页面初始化就要显示地址数据,type传get,get会把每一层去对比加载进数据,而change只会根据现有数组长度加载下一层的数据。

如果你的需求里级联选择器不需要检索,只需引入这个方法在合适的时候调用就已经完美解决了!如果刚好有这个需求,那么这个方法是会影响你的检索功能的,this.chinese里数据只包含部分地址数据(就是页面上用到过、加载过的数据),而不是整个所有的四级地址数据

为了解决对检索的影响,又写了一个检索的方法,检索方法里要用到上面的getOptions方法:

// 此级联选择器地址检索用到的方法,需结合楼上getOption方法的基础之上,同样是按需加载地址数据的思想/* 参数:当前搜索输入的关键词 例如:(this.chinese, '江夏区')   同样在当前页用this.chinese接收  这里的this.chinese就是当前页所用到的地址数据*/export const getfilterOption = (chinese, val) => {  var list = ['北京市', '天津市', '上海市', '重庆市'];  var toNext = true;  for (let i = 0; i < list.length; i++) {    let str = list[i];    if (str.indexOf(val) >= 0) {      toNext = false;    }  }  for (let a = 0; a < cityTown.length; a++) {    if (cityTown[a].label.indexOf(val) >= 0 && toNext) {      let provData = cityTown[a].children;      for (let b = 0; b < provData.length; b++) {        let value1 = [cityTown[a].value, provData[b].value];        chinese = getOption(chinese, value1, 'get');      }    } else {      let provData = cityTown[a].children;      for (let b = 0; b < provData.length; b++) {        if (provData[b].label.indexOf(val) >= 0) {          if (provData[b].children) {            let cityData = provData[b].children;            for (let c = 0; c < cityData.length; c++) {              let value2 = [cityTown[a].value, provData[b].value, cityData[c].value];              chinese = getOption(chinese, value2, 'get');            }          } else {            let value2 = [cityTown[a].value, provData[b].value];            chinese = getOption(chinese, value2, 'get');          }        } else {          if (provData[b].children) {            let cityData = provData[b].children;            for (let c = 0; c < cityData.length; c++) {              if (cityData[c].label.indexOf(val) >= 0) {                let value2 = [cityTown[a].value, provData[b].value, cityData[c].value];                chinese = getOption(chinese, value2, 'get');              } else {                if (cityData[c].children) {                  let districtData = cityData[c].children;                  for (let d = 0; d < districtData.length; d++) {                    if (districtData[d].label.indexOf(val) >= 0) {                      let value3 = [cityTown[a].value, provData[b].value, cityData[c].value, districtData[d].value];                      chinese = getOption(chinese, value3, 'get');                    }                  }                }              }            }          }        }      }    }  }  return chinese}复制代码

这个检索方法在级联选择器的检索钩子before-filter里调用就行了

// 检索前钩子    filterHandle(val) {      var _this = this;      if (val && val.length >= 2) {        _this.chinese = getfilterOption(_this.chinese, val);      } else {        return false      }    },复制代码

至此,所有因为四级地址的数据问题就解决了,需要注意一点的就是新版本的element-ui级联选择器似乎样式比较难看,引用这些方法的时候也有问题,我们的项目用的2.4.9版本是没问题的


关注下面的标签,发现更多相似文章
评论