最近在写公司业务的时候,有需要用到transfer的业务场景,但是ele给的穿梭框组件并不是很符合期望要求,故自己基于eleui手写了一个穿梭框;
效果如下:
具体代码如下,给大家一个参考!
<template>
<div class="transfer">
<!-- 左侧列表 -->
<div class="card">
<div class="card-header">
<el-checkbox
v-model="achecked"
:disabled="alist.length > 0 ? false : true"
@change="aCheckBoxChange"
></el-checkbox>
<span>a列表</span>
<span class="number-box"
>{{
getCheckedList({
arr: alist,
type: "length",
checkedStr: "achecked",
})
}}
/ {{ alist.length }}</span
>
</div>
<ul>
<template v-if="alist.length > 0">
<li
v-for="item in alist"
:key="item.id"
@click="item.checked = !item.checked"
:class="{ 'select-option': item.checked }"
>
{{ item.title }}
</li>
</template>
<el-empty v-else></el-empty>
</ul>
</div>
<!-- 穿梭操作按钮 -->
<div class="handler-button">
<el-button
type="primary"
icon="el-icon-arrow-left"
:disabled="getBlistSlected"
@click="transferToLeft"
></el-button>
<el-button
type="primary"
icon="el-icon-arrow-right"
:disabled="getAlistSlected"
@click="transferToRight"
></el-button>
</div>
<!-- 右侧列表 -->
<div class="card">
<div class="card-header">
<el-checkbox
v-model="bchecked"
:disabled="blist.length > 0 ? false : true"
@change="bCheckBoxChange"
></el-checkbox>
<span> b列表</span>
<span class="number-box"
>{{
getCheckedList({
arr: blist,
type: "length",
checkedStr: "bchecked",
})
}}
/ {{ blist.length }}</span
>
</div>
<ul>
<template v-if="blist.length > 0">
<li
v-for="item in blist"
:key="item.id"
@click="item.checked = !item.checked"
:class="{ 'select-option': item.checked }"
>
{{ item.title }}
</li>
</template>
<el-empty v-else></el-empty>
</ul>
</div>
</div>
</template>
<script>
export default {
data() {
return {
achecked: false,
bchecked: false,
alist: [
{
id: 11153551,
title: "a1",
checked: false,
},
{
id: 24546515,
title: "a2",
checked: false,
},
{
id: 347845231,
title: "a3",
checked: false,
},
{
id: 421321332,
title: "a4",
checked: false,
},
{
id: 545546645,
title: "a5",
checked: false,
},
{
id: 6242153,
title: "a6",
checked: false,
},
{
id: 77898846,
title: "a7",
checked: false,
},
],
blist: [
{
id: 15745,
title: "b1",
checked: false,
},
{
id: 23232,
title: "b2",
checked: false,
},
{
id: 35353,
title: "b3",
checked: false,
},
{
id: 45645465,
title: "b4",
checked: false,
},
{
id: 523123,
title: "b5",
checked: false,
},
{
id: 689788,
title: "b6",
checked: false,
},
{
id: 746565,
title: "b7",
checked: false,
},
],
};
},
computed: {
getAlistSlected() {
if (
this.getCheckedList({
arr: this.alist,
type: "length",
checkedStr: "achecked",
}) > 0
) {
return false;
}
return true;
},
getBlistSlected() {
if (
this.getCheckedList({
arr: this.blist,
type: "length",
checkedStr: "bchecked",
}) > 0
) {
return false;
}
return true;
},
},
methods: {
getCheckedList({ arr, type = "data", checkedStr }) {
let list = arr.filter((item) => item.checked);
if (list.length === arr.length) this[checkedStr] = true;
else this[checkedStr] = false;
if (type === "data") return list;
if (type === "length") return list.length;
},
getNoCheckedList(arr, type = "data") {
let list = arr.filter((item) => !item.checked);
if (type === "data") return list;
if (type === "length") return list.length;
},
aCheckBoxChange(e) {
if (e) {
this.alist.forEach((e) => (e.checked = true));
} else {
this.alist.forEach((e) => (e.checked = false));
}
},
bCheckBoxChange(e) {
if (e) {
this.blist.forEach((e) => (e.checked = true));
} else {
this.blist.forEach((e) => (e.checked = false));
}
},
//深拷贝
deepClone(obj) {
let newObj = null;
if (typeof obj === "object" && obj !== null) {
newObj = obj instanceof Array ? [] : {};
for (let i in obj) {
newObj[i] =
typeof obj[i] === "object" ? this.deepClone(obj[i]) : obj[i];
}
} else {
newObj = obj;
}
return newObj;
},
transferToRight() {
let alist = this.deepClone(this.alist);
let selectedList = this.getCheckedList({
arr: alist,
checkedStr: "achecked",
});
selectedList.forEach((item) => (item.checked = false));
this.blist = [...this.blist, ...selectedList];
this.alist = this.getNoCheckedList(this.alist);
},
transferToLeft() {
let blist = this.deepClone(this.blist);
let selectedList = this.getCheckedList({
arr: blist,
checkedStr: "bchecked",
});
selectedList.forEach((item) => (item.checked = false));
this.alist = [...this.alist, ...selectedList];
this.blist = this.getNoCheckedList(this.blist);
},
},
};
</script>
<style scoped lang="scss">
$card-width: 500px; //左右两侧card宽高
$ul-height: 500px; //ul高度
$li-height: 36px; //每个选项的高度
.transfer {
display: flex;
align-items: center;
justify-content: center;
.handler-button {
margin: 0 20px;
white-space: nowrap;
}
}
ul,
li {
padding: 0;
margin: 0;
list-style: none;
display: block;
}
.select-option {
background: #409eff !important;
color: #ffffff;
}
.card {
width: $card-width;
border: 1px solid #ebeef5;
border-radius: 10px;
.card-header {
background: #f5f7fa;
height: 40px;
line-height: 40px;
padding: 0 16px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
.number-box {
font-weight: normal;
font-size: 14px;
color: #666;
}
}
ul {
padding: 10px;
height: $ul-height;
overflow-y: auto;
li {
height: $li-height;
line-height: $li-height;
padding: 0 20px;
border-radius: 5px;
font-size: 14px;
background: #f5f5f5;
margin: 10px 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&:hover {
cursor: pointer;
background: #ececec;
}
}
}
}
</style>