element远程搜索tree

RemoteTreeSelect.vue

<template>
    <el-select
        size="small"
        class="component remote-tree-select"
        popper-class="component remote-tree-select dropdown-wrapper"

        :placeholder="placeholder"
        :loading="loading"
        :value="localValue"
        
        multiple
        collapse-tags

        filterable
        :filter-method="searchFunc"

        @visible-change="e => !e && searchFunc()"

        @remove-tag="removeItem">
        <el-option v-show="false" value=""></el-option>

        <el-option
            v-for="item in selectedOptions"
            :key="item[defaultProps.key]"
            :value="item[defaultProps.key]"
            :label="item[defaultProps.label]"
            v-show="false">
        </el-option>

        <el-tree
            ref="treeEl"

            lazy
            :load="syncFunc"

            show-checkbox
            check-strictly

            @check="selectNode"

            :data="localOptions"
            :props="defaultProps"
            :node-key="defaultProps.key"
            :default-checked-keys="localValue"
            :render-content="renderTreeLabel">
        </el-tree>
    </el-select>
</template>

<script>
export default {
    name: 'RemoteTreeSelect',
    props: {
        placeholder: {
            type: String,
            default: '请选择'
        },
        value: {
            types: Object || String,
            default: () => ({})
        },
        props: {
            type: Object,
            default: () => ({
                key: 'id',
                children: 'children',
                label: 'label'
            })
        },
        syncOptionsFunc: {
            type: Function
        },
        remoteSearchFunc: {
            type: Function
        }
    },
    computed: {
        defaultProps () {
            return Object.assign({
                key: 'id',
                children: 'children',
                label: 'label'
            }, this.props)
        },
        localValue () {
            return this.value[this.defaultProps.key] && [this.value[this.defaultProps.key]] || []
        }
    },
    data: () => ({
        loading: false,
        searchTxt: '',
        localOptions: [],
        selectedOptions: [],
        option: []
    }),
    methods: {
        checkNode (key, obj = this.option) {
            if (this.option.length === 0) {
                throw undefined
            }
            const index = obj.findIndex(item => item[this.defaultProps.key] == key)
            if (index !== -1) {
                throw obj[index][this.defaultProps.children]
            }

            for (let i = 0; i < obj.length; i++) {
                obj[i][this.defaultProps.children] && this.checkNode(key, obj[i][this.defaultProps.children])
            }

            throw undefined
        },
        setNode (key, node, obj = this.option) {
            if (this.option.length === 0) {
                this.option = node
                throw '无记录'
            }
            const index = obj.findIndex(item => item[this.defaultProps.key] == key)
            if (index !== -1) {
                obj[index][this.defaultProps.children] = node
                throw '命中'
            }

            for (let i = 0; i < obj.length; i++) {
                obj[i][this.defaultProps.children] && this.setNode(key, node, obj[i][this.defaultProps.children])
            }
        },
        syncFunc (/* 节点 node */ node = {}, /* 请求成功返回节点值 */ resolve) {
            try {
                this.checkNode(node.key)
            } catch (result) {
                if (result) {
                    resolve(result)
                    return
                }
            }
            this.syncOptionsFunc(node, e => {
                try {
                    this.setNode(node.key, e)
                } catch (err) {
                    // console.log(err)
                }
                resolve(e)
            })
        },
        searchFunc (v = '') {
            this.searchTxt = v

            if (v) {
                this.loading = true
                this.remoteSearchFunc(v, e => {
                    this.localOptions = e
                    this.loading = false
                })
            } else {
                this.localOptions = this.option
            }
        },
        removeItem () {
            this.selectedOptions = []
            this.$refs.treeEl.setCheckedKeys([])
            this.$emit('input', '')
        },
        selectNode (e) {
            if (!this.localValue.includes(e[this.defaultProps.key])) {
                this.selectedOptions = [{
                    [this.defaultProps.key]: e[this.defaultProps.key],
                    [this.defaultProps.label]: e[this.defaultProps.label]
                }]
                this.$emit('input', {
                    [this.defaultProps.key]: e[this.defaultProps.key],
                    [this.defaultProps.label]: e[this.defaultProps.label]
                })
                this.$refs.treeEl.setCheckedKeys([e[this.defaultProps.key]])
            } else {
                this.selectedOptions = []
                this.$emit('input', '')
            }
        },
        renderTreeLabel (h, { node }) {
            const { label } = node
            let renderContent = [ label ]

            if (
                this.searchTxt
                && label.indexOf(this.searchTxt) !== -1
            ) {
                let temp = label.split(this.searchTxt)
                let iterator = temp.length * 2 - 2

                for (let i = 0; i < iterator; i += 2) {
                    temp.splice(
                        i + 1,
                        0,
                        h('span', { style: 'color: #4B8BEE' }, this.searchTxt)
                    )
                }

                renderContent = [ ...temp ]
            }
            return h('span', {}, renderContent)
        }
    }
}
</script>

App.vue






你可能感兴趣的:(笔记)