数据量庞大的分页穿梭框实现

博客地址:https://ainyi.com/#/63 昨天偶然看到评论区一位老哥的需求,一时兴起,就答应了当天写好源码写个博客 回来的晚,第二天才写好。。 写个分页的穿梭框,从而解决数据量庞大的问题 我之前写过一篇博客:关于 Element 组件的穿梭框的重构 介绍并实现的方法 但是第二个分页的 demo 没有,在上一家公司匆匆解决后,没有写入自己的 GitHub,有点可惜... 当时可是在上班,而且太忙了,不过既然答应了这位老哥写个 demo,就要做到,也是给自己一个挑战 进入正题 看实现效果图 既然之前博客谈过,这里就不仔细谈了,主要放主要的源码 问题 Element 官方组件目前(==18年==)明显对于多选==三级联动的穿梭框==没有解决方案,也对==数据量庞大的穿梭框==没有结局方案(各位看官可以试一下,放入几千条数据到穿梭框,卡到爆...),遂只能自己重写组件,完成业务需求 功能 实现分页 搜索,做成在所有数据里搜索,不是在当前分页的数据里搜索,这样就不用在每个分页都搜索一次了。搜索后的结果也会自动分页。(全部数据和仅作展示的数据存都是存放在不同变量) 全选只在当前页里的全选 穿梭框左右两个框的联动 关键点 每个框作为一个子组件(组件化思想) 分页关键判断临界点 搜索,监听 keyword 的变化,传递到父组件搜索,从全局数据搜索 把备选的数据当做已选的过滤数组,把已选的数据当做备选的过滤数组,在全局 data 进行过滤,最后再进行一次搜索(备选、已选)(考虑到是在搜索过后点击的) 中间的左右箭头(加入已选和移除已选)放在父组件控制数据流动 数据流动:子备选框 -> 父组件 -> 子已选框 (移除已选相反) 源码 Districts.vue(包裹两个穿梭框的父组件) export default { props: { data: { type: Array, }, }, data () { return { dataList: [], // 未选中(已过滤出已选)的数据 selectList: [], // 已选中的数据,传递到子组件的数据 dataListNoCheck: [], // 未选中的(或已搜索)传递到子组件的数据 selectListCheck: [], // 已选中的(或已搜索)传递到子组件的数据 checkData: [], // 已勾选的数据(待添加或删除数据) noSelectkeyword: '', haSelectkeyword: '', disablePre: true, disableNex: true, }; }, created () { this.getDistrict(); }, methods: { // 分页数据 getDistrict () { this.dataList = this.data; this.dataListNoCheck = this.dataList; }, searchWord (keyword, titleId) { // 过滤掉数据,保留搜索的数据 if (titleId === 0) { this.noSelectkeyword = keyword; this.dataListNoCheck = this.dataList.filter(val => val.name.includes(keyword)); } else { this.haSelectkeyword = keyword; this.selectListCheck = this.selectList.filter(val => val.name.includes(keyword)); } let refsName = titleId === 0 ? 'noSelect' : 'hasSelect'; // 延迟执行 setTimeout(() => { this.$refs[refsName].getDistrict(); }, 0); }, // 检查左右按钮可用性 checkDisable (data, id) { if (id === 0) { data.length > 0 ? (this.disableNex = false) : (this.disableNex = true); } else { data.length > 0 ? (this.disablePre = false) : (this.disablePre = true); } }, // 选择 checkSelect (val) { this.checkData = val; }, // 关键:把未选择的数据当做已选择的过滤数组,把已选择的数据当做未选择的过滤数组,在全局data进行过滤,最后进行一次搜索 // 添加至已选 addData () { let dataFilter = [ ...this.selectList, ...this.checkData, ]; this.dataList = this.data.filter(item1 => { return dataFilter.every(item2 => item2 !== item1); }); this.selectList = this.data.filter(item1 => { return this.dataList.every(item2 => item2 !== item1); }); // 搜索一次 this.searchWord(this.noSelectkeyword, 0); this.searchWord(this.haSelectkeyword, 1); }, // 从已选中删除 deleteData () { let dataFilter = [ ...this.dataList, ...this.checkData, ]; this.selectList = this.data.filter(item1 => { return dataFilter.every(item2 => item2 !== item1); }); this.dataList = this.data.filter(item1 => { return this.selectList.every(item2 => item2 !== item1); }); // 搜索一次 this.searchWord(this.noSelectkeyword, 0); this.searchWord(this.haSelectkeyword, 1); }, }, components: { Transfer, }, }; Transfer.vue(穿梭框子组件) export default { props: { titleId: { type: Number, }, districtList: { // 父组件传递的数据 type: Array, }, }, data () { return { title: ['渠道', '已选中'], districtListMock: [], // 展示的数据 (搜索和分页会自动修改这个数组) checkedCities: [], // 已选择,数据格式:[id,id,id...] isIndeterminate: false, checkAll: false, searchWord: '', len: 0, total: 0, pageIndex: 0, disabledPre: true, disabledNex: false, }; }, created () { this.getDistrict(); }, watch: { // 搜索框的监听器 searchWord (newWord) { this.$emit('search-word', newWord, this.titleId); }, // districtListMock 和 checkAll 的监听器 districtListMock () { // 当方框中无已选择的数据时,不能勾选checkBox if (this.checkedCities.length === 0) { this.checkAll = false; this.isIndeterminate = false; } }, checkedCities (newWord) { this.$emit('check-disable', newWord, this.titleId); }, // 当列表中无数据时,不能勾选checkBox checkAll () { this.checkAll = this.districtListMock.length === 0 ? false : this.checkAll; }, }, methods: { // 分页数据 getDistrict () { this.len = this.districtList.length; this.total = Math.ceil(this.len / 200); this.pageIndex = 0; this.pageData(); }, pageData () { this.checkedCities = []; if (this.total > 1 && this.pageIndex < (this.total - 1)) { this.pageIndex === 0 ? this.disabledPre = true : this.disabledPre = false; this.disabledNex = false; this.districtListMock = this.districtList.slice(this.pageIndex \\* 200, this.pageIndex \\* 200 + 200); } else { this.total > 1 ? this.disabledPre = false : this.disabledPre = true; this.disabledNex = true; this.districtListMock = this.districtList.slice(this.pageIndex \\* 200, this.len); } }, // 上一页 prev () { this.pageIndex > 0 && --this.pageIndex; this.pageData(); }, // 下一页 next () { this.pageIndex <= (this.total - 1) && ++this.pageIndex; this.pageData(); }, // 单选 handleCheckedChange (value) { let checkedCount = value.length; this.checkAll = checkedCount === this.districtListMock.length; this.isIndeterminate = checkedCount > 0 && checkedCount < this.districtListMock.length; // 子传父 this.$emit('check-district', value); }, // 全选 handleCheckAllChange (val) { this.checkedCities = val ? this.districtListMock.map(val => val) : []; this.isIndeterminate = false; // 子传父 this.$emit('check-district', this.checkedCities); }, }, }; 具体源码可前往 Github:https://github.com/Krryxa/my-transfer 欢迎 start 呼呼,双休好好休息了~~ 博客地址:https://ainyi.com/#/63 个人博客:https://ainyi.com 音乐博客:https://www.ainyi.com GitHub:https://github.com/Krryxahttps://www.cnblogs.com/ainyi/p/10125443.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信