186 lines
No EOL
6.1 KiB
Vue
186 lines
No EOL
6.1 KiB
Vue
<template>
|
|
<div :class="classes">
|
|
<List
|
|
v-ref:left
|
|
:prefix-cls="prefixCls + '-list'"
|
|
:data="leftData"
|
|
:render-format="renderFormat"
|
|
:checked-keys.sync="leftCheckedKeys"
|
|
:valid-keys-count.sync="leftValidKeysCount"
|
|
:style="listStyle"
|
|
:title="titles[0]"
|
|
:filterable="filterable"
|
|
:filter-placeholder="filterPlaceholder"
|
|
:filter-method="filterMethod"
|
|
:not-found-text="notFoundText">
|
|
<slot></slot>
|
|
</List><Operation
|
|
:prefix-cls="prefixCls"
|
|
:operations="operations"
|
|
:left-active="leftValidKeysCount > 0"
|
|
:right-active="rightValidKeysCount > 0"></Operation><List
|
|
v-ref:right
|
|
:prefix-cls="prefixCls + '-list'"
|
|
:data="rightData"
|
|
:render-format="renderFormat"
|
|
:checked-keys.sync="rightCheckedKeys"
|
|
:valid-keys-count.sync="rightValidKeysCount"
|
|
:style="listStyle"
|
|
:title="titles[1]"
|
|
:filterable="filterable"
|
|
:filter-placeholder="filterPlaceholder"
|
|
:filter-method="filterMethod"
|
|
:not-found-text="notFoundText">
|
|
<slot></slot>
|
|
</List>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import List from './list.vue';
|
|
import Operation from './operation.vue';
|
|
|
|
const prefixCls = 'ivu-transfer';
|
|
|
|
export default {
|
|
components: { List, Operation },
|
|
props: {
|
|
data: {
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
renderFormat: {
|
|
type: Function,
|
|
default (item) {
|
|
return item.label || item.key;
|
|
}
|
|
},
|
|
targetKeys: {
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
selectedKeys: {
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
listStyle: {
|
|
type: Object,
|
|
default () {
|
|
return {}
|
|
}
|
|
},
|
|
titles: {
|
|
type: Array,
|
|
default () {
|
|
return ['源列表', '目的列表']
|
|
}
|
|
},
|
|
operations: {
|
|
type: Array,
|
|
default () {
|
|
return []
|
|
}
|
|
},
|
|
filterable: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
filterPlaceholder: {
|
|
type: String,
|
|
default: '请输入搜索内容'
|
|
},
|
|
filterMethod: {
|
|
type: Function,
|
|
default (data, query) {
|
|
const type = ('label' in data) ? 'label' : 'key';
|
|
return data[type].indexOf(query) > -1;
|
|
}
|
|
},
|
|
notFoundText: {
|
|
type: String,
|
|
default: '列表为空'
|
|
}
|
|
},
|
|
data () {
|
|
return {
|
|
prefixCls: prefixCls,
|
|
leftData: [],
|
|
rightData: [],
|
|
leftCheckedKeys: [],
|
|
rightCheckedKeys: []
|
|
}
|
|
},
|
|
computed: {
|
|
classes () {
|
|
return [
|
|
`${prefixCls}`
|
|
]
|
|
},
|
|
leftValidKeysCount () {
|
|
return this.getValidKeys('left').length;
|
|
},
|
|
rightValidKeysCount () {
|
|
return this.getValidKeys('right').length;
|
|
}
|
|
},
|
|
methods: {
|
|
getValidKeys (direction) {
|
|
return this[`${direction}Data`].filter(data => !data.disabled && this[`${direction}CheckedKeys`].indexOf(data.key) > -1).map(data => data.key);
|
|
},
|
|
splitData (init = false) {
|
|
this.leftData = [...this.data];
|
|
this.rightData = [];
|
|
if (this.targetKeys.length > 0) {
|
|
this.targetKeys.forEach((targetKey) => {
|
|
this.rightData.push(
|
|
this.leftData.filter((data, index) => {
|
|
if (data.key === targetKey) {
|
|
this.leftData.splice(index, 1);
|
|
return true;
|
|
}
|
|
return false;
|
|
})[0]);
|
|
});
|
|
}
|
|
if (init) {
|
|
this.splitSelectedKey();
|
|
}
|
|
},
|
|
splitSelectedKey () {
|
|
const selectedKeys = this.selectedKeys;
|
|
if (selectedKeys.length > 0) {
|
|
this.leftCheckedKeys = this.leftData
|
|
.filter(data => selectedKeys.indexOf(data.key) > -1)
|
|
.map(data => data.key);
|
|
this.rightCheckedKeys = this.rightData
|
|
.filter(data => selectedKeys.indexOf(data.key) > -1)
|
|
.map(data => data.key);
|
|
}
|
|
},
|
|
moveTo (direction) {
|
|
const targetKeys = this.targetKeys;
|
|
const opposite = direction === 'left' ? 'right' : 'left';
|
|
const moveKeys = this.getValidKeys(opposite);
|
|
const newTargetKeys = direction === 'right' ?
|
|
moveKeys.concat(targetKeys) :
|
|
targetKeys.filter(targetKey => !moveKeys.some(checkedKey => targetKey === checkedKey));
|
|
|
|
this.$refs[opposite].toggleSelectAll(false);
|
|
this.$emit('on-change', newTargetKeys, direction, moveKeys);
|
|
}
|
|
},
|
|
watch: {
|
|
targetKeys () {
|
|
this.splitData(false);
|
|
}
|
|
},
|
|
created () {
|
|
this.splitData(true);
|
|
}
|
|
}
|
|
</script> |