不知道大家有没碰到用elementui中transfer组件功能,里面的列表其实是el-checkbox-group。这就有个问题,如果列表中有多列数据需要区分显示就没办法了,毕竟是el-checkbox。但是这种需求的功能一般项目都不多。
下面这个是我改造的效果

初始数据也可以在右边已选框中。如果有多列可以很好区分开,同时支持待选列表也就是左边table搜索功能。
基本实现思路:
1.左右两边各一个table列表,左边代表待选区,右边代表已选区。
2.通过table自带多选功能把勾选中的值通过中间按钮push到右边table绑定的数组中,同时左边删除被勾选的item。
3.右边删除功能删除右边该行的数据同时左边push回这条数据。
4.右边每次有数据变动(添加或者删除)时,需要$emit数据到父组件进行数据提交更新。(transfer组件是作为子组件使用的)
5.搜索功能是可选的,左边列表数组通过Input搜索框绑定的v-model值来indexOf()。
5.1这里需要注意的是,检索出来的列表数据实时更新。所以在删除检索值要判断是否删除所有输入值(我这里最后删除到" "空值时会出现重复数据,所以加个判断)。
6.因为是子组件,所以初始值是通过父组件传递的。但传递数据可能会动态更新,所以用watch监听props内容。(注意:watch在组件通过v-if创建时并不会执行)
下面开始上代码:
HTML:
<template>
<div style="border: 1px solid #cccccc;padding: 10px">
<div style="dispaly:inline" v-if="hasSearch">
<el-form ref="inputRefs" :model="searchInput" :inline="true">
<el-form-item prop="tableDataName">
<el-input icon="search" v-model="searchInput.tableDataName" :placeholder="searchHolder?searchHolder:'请输入搜索内容'" style="width:240px" @change="realTime"></el-input>
</el-form-item>
</el-form>
</div>
<el-row>
<el-col :span="10">
<el-table
:data="tableData"
border
height="280"
style="width: 100%;margin-bottom: 0px"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="40">
</el-table-column>
<el-table-column v-for="(item, key) in tableKey"
:key="key"
:prop="item.value"
:label="item.name"
:width="item.width"
show-overflow-tooltip
>
</el-table-column>
</el-table>
</el-col>
<el-col :span="4">
<div style="margin-top: 100%;margin-left:25%;margin-right:25%">
<!-- <el-button @click="selectItems">获取选中数据</el-button> -->
<el-button type="primary" @click="selectItems" icon="icon el-icon-d-arrow-right"></el-button>
</div>
</el-col>
<el-col :span="10">
<el-table
:data="resultData"
height="280"
style="width: 100%;margin-bottom: 0px"
border
>
<el-table-column v-for="(item, key) in tableKey"
:key="key"
:prop="item.value"
:label="item.name"
:width="item.width"
show-overflow-tooltip
>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button
size="mini"
type="danger"
@click.native.prevent="handleDelete(scope.$index, scope.row,resultData)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
</template>
这两个table其实也就是百度上的自定义table功能。而tableKey则是从父组件通过props传进来的数组。
tableKey: [{
name: '主账号',
value: 'accountNames',
label: 100
},{
name: '主账号别名',
value: 'accountNbrs',
label: 100
}],
JS:
<script>
export default {
/**
* 参数说明:
* searchHolder: 搜索框提示的内容
* receiveData: 接收到的数据-待选列表
* hasSearch: 是否需要搜索功能
* tableKey: 字段名
* isCheckValue: 用于初始化数据时,数据在已选的右边table中-已选列表
* dispatchData: 发送右边已选table中的数据到父组件事件
*
*
* 使用模板
* <g-transfer :hasSearch="true" :isCheckValue="exportFieldVlue" :searchHolder="pSearchHolder" :receiveData="exportFieldData" @dispatchData="getCurrentNodeTransfer" :tableKey="tableKey"></g-transfer>
*
* $emit提交到父组件上的值是右边table框中该条的完整数据字段,若想只要某个字段需要在父组件中操作
*
* 修改记录:
* 2018年8月3日11:15:00
* ge.libin
* 1.初始化赋值等操作原先在created钩子上赋值,现在改为用watch监听方式。同时原先界面有用v-if的方式去掉
* 2.删除搜索、重置按钮功能,改为输入框实时检索待选列表数据
* */
props:{
searchHolder:{ type: String},
receiveData:{type: Array,required: true},
hasSearch:{type: Boolean,required: true},
tableKey:{type: Array,required: true},
isCheckValue: {type: Array}
},
data() {
return {
tableData:[],
multipleSelection:[],
resultData:[],
searchInput:{
tableDataName: "", //搜索框绑定值
},
filterTableDataEnd:[],
resetData:[], //用于搜索重置
filterBeforeData:[] //用于存放搜索操作前数据。
}
},
methods:{
realTime(){
// console.log("已执行实时搜索功能");
//每次手动将数据置空,因为会出现多次点击搜索情况
this.filterTableDataEnd=[];
//这里是为了阻止搜索框删除完最后一个值时再检索,数据会重复显示问题
if(this.searchInput.tableDataName == ""){
this.tableData = this.resetData;
return;
}
this.tableKey.forEach((v,i) => {
this.resetData.forEach((value, index) => {
if(value && value[v.value]){
if(value[v.value].indexOf(this.searchInput.tableDataName)>=0){
this.filterTableDataEnd.push(value)
}
}
});
});
this.tableData = this.filterTableDataEnd;
},
/**
* 跟据当前索引位置删除数据
* 同时把该条删除的数据添加到左边待选table中
*/
handleDelete(index, row,resultData) {
resultData.splice(index,1);//右边删除数据
this.filterBeforeData.push(row);
this.resetData = this.filterBeforeData;
//根据删除后得到的数据再进行一次搜索展示
this.realTime();
this.$emit('dispatchData',this.resultData);
},
handleSelectionChange(val){
this.multipleSelection = val;
},
selectItems:function () {
//等同下一行代码---数组合并,频繁使用用concat会造成内存浪费
this.resultData.push.apply(this.resultData,this.multipleSelection);
//把获取的数据发送到父组件
this.$emit('dispatchData',this.resultData);
//在返回push数据后剩余的待选列表所有数据赋值到resetData中,然后再在待选列表中显示检索删除被剩余的数据
this.filterBeforeData = this.overlap(this.filterBeforeData,this.resultData);
this.resetData = this.filterBeforeData;
//删除左边被选中的数据,返回待选列表中被剩余的数据
this.tableData = this.overlap(this.tableData,this.resultData);
},
/**
* 删除选中item
* @param arr 数据
* @param arr2
* @returns {Array}
*/
overlap:function(arr, arr2) {
var arr3 = new Array();
var index = 0, i = 0, j = 0;
for (i = 0; i < arr.length; i++) {
var has = false;
for (j = 0; j < arr2.length; j++) {
if (arr[i] == arr2[j]) {
has = true;
break;
}
}
if (!has) {
arr3[index++] = arr[i];
}
}
return arr3;
},
},
created(){
// this.tableData = this.receiveData;
// this.resetData = this.tableData;
// if(this.isCheckValue){
// this.resultData = this.isCheckValue;
// //数据初始化时把数据emit到父组件操作方法中
// this.$emit('dispatchData',this.resultData);
// }
},
watch:{
receiveData(val){
this.tableData = val;
this.resetData = val;
this.filterBeforeData =val;
},
isCheckValue(val){
this.resultData = val;
this.$emit('dispatchData',this.resultData);
}
},
computed:{
}
}
</script>
这里是在watch中把父组件传递过来的数据进行初始化赋值。而搜索功能则是通过待选table绑定的数组中的字段来检索,而字段又是通过tableKey中的值来获取。(因为table也是动态的,不知道绑定数组中具体的字段名,所以需要通过tableKey来对应)。
其他的在代码中也有注释说明。
如果想看组件文件代码的话,下载地址:https://download.csdn.net/download/u012138137/10604091
后续修改的代码,下载地址:(新增已选列表搜索功能,修复搜索时数据重复问题)
https://download.csdn.net/download/u012138137/10723369
2019年1月28日 功能改进以及一些问题优化(把已选列表中只能单个删除改为多选转移,效果同原生el看去一样,原先单个删除有的代码只注释没删除同样可以参考)
https://download.csdn.net/download/u012138137/10880865