自定义穿梭框
一、前言穿梭框普遍都只显示一个字段,想显示多个字段,需要自己用表格搭建,我就是这么干的。二、element uivue2代码<template><div class="rongqi"><div class="transtable"><div><div style="display: flex;"><el-input v-model=
·
一、前言
穿梭框普遍都只显示一个字段,想显示多个字段,需要自己用表格搭建,我就是这么干的。
二、element ui vue2代码
<template>
<div class="rongqi">
<div class="transtable">
<div>
<div style="display: flex;">
<el-input v-model="leftinput" size="mini" style="width:66%;"></el-input>
<el-select v-model="leftselect" filterable placeholder="请选择" size="mini" style="width:33%;">
<el-option
v-for="item in leftoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button size="mini" type="primary">重置</el-button>
</div>
<el-table
:data="_newdata"
ref="lefttable"
@selection-change="leftSelectionChange"
tooltip-effect="dark"
height="400"
border>
<el-table-column type="selection" width="40" align="center" :selectable="selectablefunc"></el-table-column>
<el-table-column v-for="(item,index) in columnsleft" :label="item.label" :prop="item.prop"
:key="index+'right'"
:width="item.width || null" :fixed="item.fixed || false"></el-table-column>
</el-table>
</div>
<div class="action">
<el-button type="primary" style="margin-left:10px;margin-bottom: 10px;" :disabled="rightSelectArray.length===0"
@click="toleftaction()"><
</el-button>
<el-button type="primary" :disabled="leftSelectArray.length===0" @click="torightaction">></el-button>
</div>
<div>
<div style="display: flex;">
<el-input v-model="rightinput" size="mini" style="width:66%;"></el-input>
<el-select v-model="rightselect" filterable placeholder="请选择" size="mini" style="width:33%;">
<el-option
v-for="item in rightoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<el-button size="mini" type="primary" @click="resetright">重置</el-button>
</div>
<el-table
:data="_olddata"
ref="righttable"
@selection-change="rightSelectionChange"
tooltip-effect="dark"
height="400"
border>
<el-table-column type="selection" width="40" align="center"></el-table-column>
<el-table-column v-for="(item,index) in columnsright" :label="item.label" :prop="item.prop"
:key="index+'right'"
:width="item.width || null" :fixed="item.fixed || false"></el-table-column>
</el-table>
</div>
</div>
<div class="error">
<span>{{ errortext }}</span>
</div>
</div>
</template>
<script>
export default {
name: "newtranstable",
props: {
// 待选的数据
data: {
type: Array,
default(shuju) {
return Array.isArray(shuju) || []
},
},
// 显示的字段
colums: {
type: Array,
default(shuju) {
return Array.isArray(shuju) || []
}
},
// 左侧显示的字段
colnumleft: {
type: Array,
default(shuju) {
return Array.isArray(shuju) || []
},
},
// 右侧显示的字段
colnumright: {
type: Array,
default(shuju) {
return Array.isArray(shuju) || []
},
},
// 必填校验
required: {
type: Boolean,
default: true,
},
// 默认显示的数据
defaultData: {
type: Array,
default(shuju) {
return Array.isArray(shuju) || []
},
},
// 最大选择数量
max: {
type: Number,
default: 0,
},
// 判断不可选的回调函数
disableFun: {
type: Function,
default: null,
},
// 区分同一数据的依据,默认是ID
bond:{
type:String,
default:"id",
},
},
data() {
return {
newdata: [], // 左侧被选中的数据列表
leftSelectArray: [], // 左侧被选中的字段
rightSelectArray: [], // 左侧被选中的字段
errortext: "", // 错误信息
formdata: {}, // 过滤的关键字
leftinput: "", // 左侧的搜索关键字
leftselect: "", // 左侧的过滤key
rightinput: "", // 右侧的搜索关键字
rightselect: "", // 右侧的过滤key
}
},
// 监听外层最新数据,显示到组件内部
watch: {
defaultData(newValue) {
this.newdata = newValue
},
},
computed: {
// 左侧字段
columnsleft() {
if (this.colnumleft.length > 0) {
return this.colnumleft
} else {
return this.colums
}
},
// 右侧字段
columnsright() {
if (this.colnumright.length > 0) {
return this.colnumright
} else {
return this.colums
}
},
// 将已经选择的数据过滤掉
_olddata() {
const linshi1 = this.data.filter(item => {
const jieguo = this.newdata.find(el=>el[this.bond].toString()===item[this.bond].toString())
return !jieguo
})
if(this.rightinput && this.rightselect){
return linshi1.filter(item=>{
return item[this.rightselect] && item[this.rightselect].indexOf(this.rightinput) > -1
})
}else{
return linshi1
}
},
_newdata(){
if(this.leftinput && this.leftselect){
return this.newdata.filter(item=>{
return item[this.leftselect] && item[this.leftselect].indexOf(this.leftinput) > -1
})
}else{
return this.newdata
}
},
// 右侧key列表
rightoptions(){
let oldlist = []
if(this.colnumright.length > 0){
oldlist = this.colnumright
}else{
oldlist = this.colums
}
return oldlist.filter(item=>{
return item.prop
}).map(item=>{
return {label: item.label,value: item.prop}
})
},
// 左侧key列表
leftoptions(){
let oldlist = []
if(this.colnumleft.length > 0){
oldlist = this.colnumleft
}else{
oldlist = this.colums
}
return oldlist.filter(item=>{
return item.prop
}).map(item=>{
return {label: item.label,value: item.prop}
})
},
},
methods: {
// 右侧表格选择
rightSelectionChange(selectitems) {
console.log("被选中的key数组", selectitems)
this.rightSelectArray = selectitems
},
// 左侧表格选择
leftSelectionChange(selectitems) {
console.log("被选中的key数组", selectitems)
this.leftSelectArray = selectitems
},
// 点击向左转移
toleftaction() {
this.newdata = [...this.newdata, ...this.rightSelectArray]
this.checkerror()
},
// 点击向右转移
torightaction() {
this.newdata = this.newdata.filter(item => {
const jieguo = this.leftSelectArray.find(el => el.id === item.id)
return !jieguo
})
this.checkerror()
},
// 校验错误
checkerror() {
if (this.required && this.newdata.length === 0) {
this.errortext = "请选择一条数据"
} else if (this.max && this.newdata.length > this.max) {
this.errortext = `最多选择${this.max}条数据`
} else {
this.errortext = ""
}
},
validate(func) {
this.checkerror()
func(this.error, this.newdata)
},
reset() {
this.newdata = []
this.leftSelectArray = []
this.rightSelectArray = []
this.errortext = ""
this.formdata = {}
console.log("主动初始化穿梭框一次")
},
// 判断是否可以选中的
selectablefunc(row, index) {
if (this.disableFun) {
return this.disableFun(row, index)
} else {
return row.checkbox === undefined || row.checkbox === null ? true : !!row.checked
}
},
// 右侧重置搜索
resetright(){
this.rightinput = ""
},
// 左侧重置搜索
resetleft(){
this.leftinput = ""
},
},
}
</script>
<style scoped lang="less">
.rongqi {
width: 100%;
display: flex;
flex-direction: column;
.transtable {
width: 100%;
display: flex;
.action {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
}
.error {
height: 20px;
width: 100%;
color: #8a2424;
span {
line-height: 20px;
}
}
}
</style>
三、naive ui vue3 代码
<template>
<div class="flex juzhong1">
<div>
<div>
<n-input-group>
<n-input :style="{ width: '66%' }" v-model:value="leftinputtext" placeholder="请输入关键字"/>
<n-select :style="{ width: '33%' }" v-model:value="leftselectkey" :options="leftoptions"/>
<n-button type="info">重置</n-button>
</n-input-group>
</div>
<n-data-table
class="min-h-240px"
:columns="columnleft"
:data="leftalllist"
:row-key="row => row[props.bondkey]"
@update:checked-row-keys="handleleftCheck"
v-model:checked-row-keys="leftlist"
/>
<div>{{ errorMsg }}</div>
</div>
<div class="juzhong1 flex-col">
<n-button :disabled="rightbtn" class="m-1" @click="moveleft" type="info">{{ "<<" }}</n-button>
<n-button :disabled="leftbtn" class="m-1" @click="moveright" type="info">{{ ">>" }}</n-button>
</div>
<div>
<div>
<n-input-group>
<n-input :style="{ width: '66%' }" v-model:value="rightinputtext" placeholder="请输入关键字"/>
<n-select :style="{ width: '33%' }" v-model:value="rightselectkey" :options="rightoptions"/>
<n-button type="info">重置</n-button>
</n-input-group>
</div>
<n-data-table
class="min-h-240px"
:columns="colnumright"
:data="rightalllist"
:row-key="row => row[props.bondkey]"
@update:checked-row-keys="handlerightCheck"
v-model:checked-row-keys="rightlist"
/>
</div>
</div>
</template>
<script setup name="transfer">
import {useRoute, useRouter} from "vue-router";
import {defineProps} from "vue";
const router = useRouter()
const route = useRoute()
const props = defineProps({
// 右边的字段
colnumright: {
type: Array,
default: [],
},
// 左边的字典
colnumleft: {
type: Array,
default: [],
},
// 默认的字段
colnum: {
type: Array,
default: [],
},
// 备选的数据
origindata: {
type: Array,
},
// 被选中的数据
default: {
type: Array,
default: [],
},
// 识别的唯一键
bondkey: {
type: String,
default: 'id',
},
// 必填
required: {
type: Boolean,
default: false,
},
// 最大数量
max: {
type: Number,
default: 0,
},
})
// 错误
const errorMsg = ref("")
// 字段
const columnleft = computed(() => {
const ziduanlist = props.colnumleft.length > 0 ? props.colnumleft : props.colnum
const check = ziduanlist.find(el => el.type === "selection")
if (!check) {
return [{
type: 'selection', width: 60, disabled(row, index) {
return row.checkbox === undefined || row.checkbox === null ? true : !!row.checked
},
}, ...ziduanlist]
} else {
return ziduanlist
}
})
const colnumright = computed(() => {
const ziduanlist = props.colnumright.length > 0 ? props.colnumright : props.colnum
const check = ziduanlist.find(el => el.type === "selection")
if (!check) {
return [{
type: 'selection', width: 60, disabled(row, index) {
return row.checkbox === undefined || row.checkbox === null ? true : !!row.checked
},
}, ...ziduanlist]
} else {
return ziduanlist
}
})
const leftoptions = computed(() => {
let oldlist = []
if (props.colnumleft.length > 0) {
oldlist = props.colnumleft
} else {
oldlist = props.colnum
}
return oldlist.filter((item) => {
return item.type !== "selection" && item.key
}).map(item => {
return {label: item.title, value: item.key,}
})
})
const rightoptions = computed(() => {
let oldlist = []
if (props.colnumleft.length > 0) {
oldlist = props.colnumleft
} else {
oldlist = props.colnum
}
return oldlist.filter((item) => {
return item.type !== "selection" && item.key
}).map(item => {
return {label: item.title, value: item.key,}
})
})
// 左边的数据
const leftinputtext = ref("") // 手动输入的过滤关键字
const leftselectkey = ref("") // 过滤的key
const resultlist = ref([]) // 所有左侧的数据
const leftalllist = computed(() => { // 显示左侧的数据
if (leftinputtext.value && leftselectkey.value) {
return resultlist.value.filter(item => {
return item[leftselectkey.value] && item[leftselectkey.value].indexOf(leftinputtext.value) > -1
})
} else {
return resultlist.value
}
})
const leftlist = ref([]) // 左侧被选中的数据
const leftbtn = computed(() => { // 向右移动的按钮
return leftlist.value.length === 0
})
// 右边数据
const rightinputtext = ref("") // 右侧过滤的关键字
const rightselectkey = ref("") // 右侧过滤的key
const rightalllist = computed(() => { // 右侧显示的数据
// 先过滤已经移到左边的
const linshilist = props.origindata.filter(item => {
const jieguo = resultlist.value.find(el => el[props.bondkey] === item[props.bondkey])
return !jieguo
})
// 再过滤关键字
if (rightinputtext.value && rightselectkey.value) {
return linshilist.filter(item => {
return item[rightselectkey.value] && item[rightselectkey.value].indexOf(rightinputtext.value) > -1
})
} else {
return linshilist
}
})
const rightlist = ref([]) // 右侧被选中的数据
const rightbtn = computed(() => { // 向左移动的按钮
return rightlist.value.length === 0
})
// 选择回调
const handleleftCheck = (selectlist) => {
console.log(selectlist)
leftlist.value = selectlist
}
const handlerightCheck = (selectlist) => {
console.log(selectlist)
rightlist.value = selectlist
}
// 点击向左移动
const moveleft = () => {
rightlist.value.forEach(item => {
const obj = props.origindata.find(el => el[props.bondkey] === item)
console.log("找到了,", obj)
if (obj) {
resultlist.value.push(obj)
}
})
// leftlist.value = []
rightlist.value = []
}
// 点击向右移动
const moveright = () => {
resultlist.value = resultlist.value.filter(item => {
return !leftlist.value.includes(item[props.bondkey])
})
leftlist.value = []
// rightlist.value = []
}
// 校验回调
const jiaoyan = (funcitem) => {
if (props.required) {
if (resultlist.value.length > 0) {
funcitem(resultlist.value)
} else {
errorMsg.value = "最少选择一条数据"
}
} else {
funcitem(resultlist.value)
}
}
// 重置
const reset = () => {
resultlist.value = []
}
// 生命周期区域
onMounted(()=>{
rightselectkey.value = rightoptions.value[0].value
leftselectkey.value = leftoptions.value[0].value
})
defineExpose({jiaoyan, reset})
</script>
<style scoped>
</style>
四、navie ui vue3 效果
更多推荐
已为社区贡献6条内容
所有评论(0)