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