吐槽

最近项目使用vue+element-ui做后台,其中有个功能用到了数据穿梭框,刚好element里有,原本相安无事(哈哈),突然老大说要对选择中的列来个自定义排序(当时我就老不乐意了,我一个后端兼职前端这么久了,用用前端框架就差不多了啊,现在功能都写完了,突然多了这个功能,element的兄弟有没提供,这是要换插件的节奏啊),于是爱恨交错人憔悴,怕只怕这需求推不掉。百度,bing,google,苦心人天不负


欲哭无泪,你怎么能改需求呢,不厚道。接着翻N多帖子,全特么标题党,待解决,个别靠谱的要改源码(看起来好复杂,不敢试)
那么,只能自己动手丰衣足食了。

效果图


知识点

大佬对数组的总结,搬过来占坑

方法说明实例
push( );在原来数组中的元素最后面添加元素arr.push(“再见58”);
unshift( );在原来数组中的元素最前面添加元素arr.shift(“你好58”);
pop();移除数组中最后面的一个元素arr.pop();
shift();移除数组中最前面的一个元素arr.shift();
concat();拼接两个数组中的元素(哪个数组在前面,拼接后它的元素就在前面)arrA.concat(arrB);
join(" ");把数组转换为字符串(将数组中的元素通过特殊符号链接成字符串)arr.join("*");
split(" ");把字符串转为数组(通过字符串的某个特定符号或者字母拆分为数组的元素)txtStr = “avbvcvdvevf”;txtStr.split(“v”);

这些方法在上移下移置顶置底的时候将会用到

代码实现

这里写了一个组件(js版的,不是前端小伙伴用到的*.vue)
用法:

<warmer-transfer  :sourcedata="sourcedata" sourcetitle="源列表" :targetdata="targetdata" targettitle="目标列表"></warmer-transfer>

warmer-transfer.js

Vue.component('warmer-transfer', {
    props: ['sourcedata','sourcetitle','targetdata','targettitle'],
    data: function () {
        return {
            sourceList: [],
            targetList: [],
        };
    },
    filters: {},
    computed: {
        // 源数据中选中的数量
        sourceRefNum() {
            return this.sourceList.filter(item => item.isSelected).length;
        },
        // 目标数据中选中的数量
        targetRefNum() {
            return this.targetList.filter(item => item.isSelected).length;
        },
        // 选择的源记录数量
        selectSourceItemNumber() {
            return this.sourceList.filter(item => item.isSelected).length;
        },
        // 选择目标记录数量
        selectTargetItemNumber() {
            return this.targetList.filter(item => item.isSelected).length;
        },
    },
    created() {
        if(this.targetdata===null||this.targetdata.length===0){
            this.sourceList = this.formatData(val);
            return;
        }
        var source=[];
        var target=this.targetdata;
        this.sourcedata.forEach(function (item) {
            let data = target.filter(n => n.name==item.name);
            if(data==null||data.length==0){
                source.push(item);
            }
        })
        this.sourceList = this.formatData(source);
        this.targetList = this.formatData(this.targetdata);
    },
    watch: {

    },
    mounted() {

    },
    methods: {
        formatData(dataList) {
            let data = dataList.map(item => {
                return {
                    ...item,
                    isSelected: false
                };
            });
            return data;
        },
        moveItems(direction) {
            let selectedItem = this.targetList.filter(item => item.isSelected).map(item => {
                return item.name;
            });
            if (direction == 1) {//下移
                for (var i = selectedItem.length - 1; i >= 0; i--) {
                    let index = this.targetList.map(item => {
                        return item.name;
                    }).indexOf(selectedItem[i]);
                    if (index >= this.targetList.length - 1) return;
                    this.targetList[index] = this.targetList.splice(index + 1, 1, this.targetList[index])[0];
                }
            }
            if (direction == 0) {//上移
                for (var i = 0; i < selectedItem.length; i++) {
                    let index = this.targetList.map(item => {
                        return item.name;
                    }).indexOf(selectedItem[i]);
                    if (index <= 0) return;
                    this.targetList[index] = this.targetList.splice(index - 1, 1, this.targetList[index])[0];
                }
            }
            if (direction == 3) {//置底
                for (var i = 0; i < selectedItem.length; i++) {
                    let index = this.targetList.map(item => {
                        return item.name;
                    }).indexOf(selectedItem[i]);
                    if (index >= this.targetList.length - 1) return;
                    this.targetList.push(this.targetList[index]);
                    this.targetList.splice(index, 1);
                }
            }
            if (direction == 4) {//置顶
                for (var i = selectedItem.length - 1; i >= 0; i--) {
                    let index = this.targetList.map(item => {
                        return item.name;
                    }).indexOf(selectedItem[i]);
                    if (index <= 0) return;
                    this.targetList.unshift(this.targetList[index]);
                    this.targetList.splice(index + 1, 1);
                }
            }
        },
        exchange(fd, td) {
            let selectedItem = fd.filter(item => item.isSelected).map(item => {
                return {
                    ...item,
                    isSelected: false
                };
            });
            td.push(...selectedItem);
            var selectedlist = fd.filter(item => !item.isSelected);
            return selectedlist;
        },
        // 全选状态
        selectedAllStatus(type) {
            if (type == 0) {
                if (this.selectSourceItemNumber === this.sourceList.length && this.selectSourceItemNumber !== 0) {
                    return true;
                } else {
                    return false;
                }
            }
            else {
                if (this.selectTargetItemNumber === this.targetList.length && this.selectTargetItemNumber !== 0) {
                    return true;
                } else {
                    return false;
                }
            }
        },
        // 全选及反选
        toggleAll(type) {
            if (type == 0) {
                let len = this.sourceList.length;
                let slen = this.sourceList.filter(item => item.isSelected).length;
                if (len !== slen) {
                    this.sourceList.map(item => (item.isSelected = true));
                } else {
                    this.sourceList.map(item => (item.isSelected = false));
                }
            } else {
                let len = this.targetList.length;
                let slen = this.targetList.filter(item => item.isSelected).length;
                if (len !== slen) {
                    this.targetList.map(item => (item.isSelected = true));
                } else {
                    this.targetList.map(item => (item.isSelected = false));
                }
            }
        },
        // 把选择数据转移到目标(右框)
        toTarget() {
            this.sourceList = this.exchange(this.sourceList, this.targetList);
        },
        // 把选择数据转回到源(左框)
        toSource() {
            this.targetList = this.exchange(this.targetList, this.sourceList);
        }
    },
    template:
        `
        <div class="ty-transfer mt20 ml20">
            <div class="fl ty-transfer-list transfer-list-left">
                <div class="ty-transfer-list-head">
                    <div class="tyc-check-blue dib ml10">
                        <input :disabled="sourceList.length == 0" type="checkbox" @click="toggleAll(0)"
                               :checked="selectedAllStatus(0)" class="transfer-all-check">
                        <span>全选</span>
                    </div>
                    <div class="dib fs14 fw ml5">{{sourcetitle}} {{selectSourceItemNumber}}/{{sourceList.length}}</div>
                </div>
                <div class="ty-transfer-list-body">
                    <ul class="ty-tree-select">
                        <li v-for="item in sourceList">
                            <div class="ty-tree-div">
                                <label class="tyue-checkbox-wrapper">
		                            <span class="tyue-checkbox">
		                                <input type="checkbox" v-model="item.isSelected" class="tyue-checkbox-input">
		                                <span class="tyue-checkbox-circle"></span>
		                            </span>
                                    <span class="tyue-checkbox-txt">{{item.name}}</span>
                                </label>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="fl ty-transfer-operation">
                <span @click="toTarget"
                      :class="[sourceList.length != 0 && sourceRefNum != 0 ? 'active' : 'disabled', 'ty-transfer-btn-toright to-switch']"></span>
                <span @click="toSource"
                      :class="[targetList.length != 0 && targetRefNum != 0 ? 'active' : 'disabled', 'ty-transfer-btn-toleft to-switch']"></span>
            </div>
            <div class="fl ty-transfer-list transfer-list-right">
                <div class="ty-transfer-list-head">
                    <div class="tyc-check-blue dib ml10">
                        <input :disabled="targetList.length == 0" type="checkbox" @click="toggleAll(1)"
                               :checked="selectedAllStatus(1)" class="transfer-all-check">
                        <span>全选</span>
                    </div>
                    <div class="dib fs14 fw ml5">{{targettitle}} {{selectTargetItemNumber}}/{{targetList.length}}</div>
                </div>
                <div class="ty-transfer-list-body">
                    <ul class="ty-tree-select">
                        <li v-for="item in targetList">
                            <div class="ty-tree-div">
                                <label class="tyue-checkbox-wrapper">
		                            <span class="tyue-checkbox">
		                                <input type="checkbox" v-model="item.isSelected" class="tyue-checkbox-input">
		                                <span class="tyue-checkbox-circle"></span>
		                            </span>
                                    <span class="tyue-checkbox-txt">{{item.name}}</span>
                                </label>
                            </div>
                        </li>
                    </ul>
                </div>
            </div>
            <div class="fl ty-transfer-operation four-icon">
                <span @click="moveItems(4)"
                      :class="[targetList.length != 0 && targetRefNum != 0? 'active' : 'disabled', 'ty-transfer-btn-zhiding to-switch  normal']"></span>
                <span @click="moveItems(0)"
                      :class="[targetList.length != 0 && targetRefNum != 0? 'active' : 'disabled', 'ty-transfer-btn-totop to-switch']"></span>
                <span @click="moveItems(1)"
                      :class="[targetList.length != 0 && targetRefNum != 0? 'active' : 'disabled', 'ty-transfer-btn-tobottom to-switch']"></span>
                <span @click="moveItems(3)"
                      :class="[targetList.length != 0 && targetRefNum != 0? 'active' : 'disabled', 'ty-transfer-btn-zhidi to-switch normal']"></span>
            </div>
            <div class="clearboth"></div>

        </div>
		`
})

源码下载

GitHub

参考资料

大佬的穿梭框,这个不带排序,完美实现穿梭功能,萌新膜拜,我是大佬的搬运工

告辞

所以到最后,还是相当于换了个插件,哈哈哈

Logo

前往低代码交流专区

更多推荐