[自定义适合大数据的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>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,366评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,521评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,689评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,925评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,942评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,727评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,447评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,349评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,820评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,990评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,127评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,812评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,471评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,017评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,142评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,388评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,066评论 2 355

推荐阅读更多精彩内容