vue数据穿梭框自定义排序
吐槽最近项目使用vue+element-ui做后台,其中有个功能用到了数据穿梭框,刚好element里有,原本相安无事(哈哈),突然老大说要对选择中的列来个自定义排序(当时我就老不乐意了,我一个后端兼职前端这么久了,用用前端框架就差不多了啊,现在功能都写完了,突然多了这个功能,element的兄弟有没提供,这是要换插件的节奏啊),于是爱恨交错人憔悴,怕只怕这需求推不掉。百度,bing,googl.
·
吐槽
最近项目使用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>
`
})
源码下载
参考资料
大佬的穿梭框,这个不带排序,完美实现穿梭功能,萌新膜拜,我是大佬的搬运工
告辞
所以到最后,还是相当于换了个插件,哈哈哈
更多推荐
已为社区贡献1条内容
所有评论(0)