transfer.vue 6.09 KB
<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>