赞
踩
不知道大家有没碰到用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
2022年2月21日 尝试已把组件功能打包发布到npm 中了,https://www.npmjs.com/package/ge-transfer readme中使用说明以及参数说明直接拉注释,所以显示有些混乱,初始化数据得在mounted
中,不能直接在使用该组件的父组件中的data
中定义,因为子组件还没渲染完成,所以展示不了初始数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。