[自定义适合大数据的select虚拟树选择组件]element puls的select和Tree V2 虚拟化树形控件 实现大数据 下拉选择,支持单选和多选

<template>
    <div class="select_tree_box">
        <el-select
            v-model="dataValue"
            clearable
            filterable
            ref="treeSelect"
            :multiple="multiple"
            collapse-tags
            collapse-tags-tooltip
            :placeholder="placeholder || '请选择'"
            :filter-method="selectFilter"
            @clear="clearSelected"
            @change="selectChange"
        >
            <el-option v-for="op in selsectOptions" :key="op.value" :value="op.value" :label="op.label">
                <span>{{ op.label }}</span>
            </el-option>
            <el-option :value="select.currentNodeKey" :label="select.currentNodeLabel" v-show="selsectOptions.length == 0">
                <el-tree-v2
                    id="tree_v2"
                    style="width: 300px"
                    ref="treeV2"
                    :data="listData"
                    :height="240"
                    :indent="6"
                    @node-click="nodeClick"
                    :expand-on-click-node="false"
                    :filter-method="treeFilter"
                >
                    <template #default="{ node }">
                        <div class="i-custom-tree" :class="{ active: multiple ? dataValue?.includes(node.data.value) : dataValue == node.data.value }">
                            <div style="width: 120px">{{ node.label }}</div>
                            <el-icon v-if="multiple ? dataValue?.includes(node.data.value) : dataValue == node.data.value"><Select /></el-icon>
                        </div>
                    </template>
                </el-tree-v2>
            </el-option>
            <el-option v-for="op in options" :key="op.value" :value="op.value" :label="op.label"> <span></span> </el-option>
        </el-select>
    </div>
</template>
<script lang="ts" setup>
import { TreeNodeData } from 'element-plus/es/components/tree/src/tree.type';
//树数据请求接口
import { userDeptTree } from '/@/api/system/dept';

const props = defineProps({
    //是否多选
    multiple: {
        type: Boolean,
        default: false,
    },
    //提示信息
    placeholder: {
        type: String,
        default: '请选择',
    },
    showRoot: {
        type: Boolean,
        default: false,
    },
    //是否排除供应商
    isExcludeSupplier: {
        type: Boolean,
        default: false,
    },
});
const model = defineModel();
const dataValue = ref(); 
const listData = ref([]);
const options = ref([]);
const selsectOptions = ref([]);
const select: any = reactive({
    currentNodeKey: '',
    currentNodeLabel: '',
});
const treeSelect = ref<HTMLElement | null>(null);
watch(
    () => model.value,
    (newValue: any, oldValue: any) => {
        console.log('props.multiple', props.multiple);
        if (props.multiple) {
            // 多选模式
            // data.value=[]
            dataValue.value = newValue || [];
            console.log(model.value, 'model.value');
        } else {
            // 单选模式
            dataValue.value = '';
            dataValue.value = newValue;
        }
    },
    { immediate: true }
);
onMounted(() => {
    console.log(model.value, 'model.value');
    if (props.multiple) {
        // 多选模式
        dataValue.value = model.value || [];
        console.log(model.value, 'model.value');
    } else {
        // 单选模式
        dataValue.value = model.value || '';
    }
    // 服务端请求数据
    userDeptTree(props.isExcludeSupplier).then((res: any) => {
        if (res.code == 0) {
            if (props.showRoot) {
                const obj = {
                    value: '0',
                    label: '根组织',
                    disabled: true,
                    children: [] as any[],
                };
                obj.children = res.data;
                listData.value = [obj];
            } else {
                listData.value = res.data;
            }
        }
    });
});
const clearSelected = () => {
    model.value = '';
};
const treeV2: any = ref<HTMLElement | null>(null);
const selectFilter = (query: string) => {
    selsectOptions.value = [];
    treeV2.value.filter(query);
};
const nodeClick = (data: any, node: any) => {
    select.currentNodeKey = data.value;
    select.currentNodeLabel = data.label;
    nextTick(() => {
        options.value.push({
            value: data.value,
            label: data.label,
        });
    });
    if (props.multiple) {
        dataValue.value.push(data.value);
        model.value = dataValue.value;
    } else {
        // 单选模式
        model.value = data.value;
    }
    (treeSelect.value as any).blur();
};

const selectChange = (value: any) => {
    for (let index = 0; index < value.length; index++) {
        const op = selsectOptions.value?.find((item: any) => item.value == value[index]);
        if (op) {
            const n = options.value.findIndex((item: any) => item.value == op.value);
            if (n >= 0) {
                options.value.push(op);
            }
        }
    }
    (treeSelect.value as any).blur();
};

const treeFilter = (query: string, node: TreeNodeData) => {
    if (query && node.label!.includes(query)) {
        nextTick(() => {
            selsectOptions.value.unshift({
                label: node.label,
                value: node.value,
            });
        });
    }
    return query ? false : true;
};

const handleChange = (value: any) => {
    if (props.multiple) {
        // 多选模式
        model.value = value;
    } else {
        // 单选模式
        model.value = value;
    }
};
</script>
<style lang="scss" scoped>
.select_tree_box {
    width: 100%;
}
:deep(.el-select__selection) {
    width: 214px;
}
:deep(.el-tag.is-closable) {
    max-width: 130px !important;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.is-selected:after {
    content: none;
}
.el-scrollbar .el-scrollbar__view .el-select-dropdown__item {
    height: auto;
    max-height: 274px;
    padding: 0;
    overflow: hidden;
}

.el-select-dropdown__item.selected {
    font-weight: normal;
}

ul li :deep(.el-tree .el-tree-node__content) {
    height: auto;
    padding: 0 20px;
}

.el-tree-node__label {
    font-weight: normal;
}

.el-tree :deep(.is-current .el-tree-node__label) {
    color: #409eff;
    font-weight: 700;
}

.el-tree :deep(.is-current .el-tree-node__children .el-tree-node__label) {
    color: #606266;
    font-weight: normal;
}
.selectInput {
    padding: 0 5px;
    box-sizing: border-box;
}
.el-select {
    width: 100% !important;
}
.i-custom-tree {
    font-weight: 100;
}
.i-custom-tree.active {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    width: 100%;
    font-weight: 100;
    color: var(--next-main-color);
    .el-icon {
        padding-top: 18px;
    }
}
</style>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容