目录

el-select+el-tree实现下拉树形选择

主要实现el-select下使用树结构,支持筛选功能

封装的组件 composeTree.vue

复制代码
<template>
    <div class="vl-tree">
        <el-select class="treeScroll" popper-class="treeScrollSep"
            v-model="selectedList"
            placeholder="请选择"
            filterable
            :filter-method="handleFilter" 
            multiple
            collapse-tags
            size="mini"
            @visible-change="handleSelectVisibleChange"
            @remove-tag="removeTag"
            >
            <el-tree :filter-node-method="filterNode" show-checkbox ref="tree"
                @check-change="handleCheckChange"
                :data="treeList" 
                node-key="id"
                :props=" {
                    children: 'children',
                    label: 'name',
                    value: 'id',
                }">
                <template slot-scope="{ node, data }">
                    <slot :node="node" :data="data">
                        <span class="custom-tree-node">
                        {{data.name}}
                        </span>
                    </slot>
                </template>
            </el-tree>
            <el-option value="" style="display: none;"></el-option>
        </el-select>
    </div>
</template>
<script>
import { debounce } from '@/utils';  
let orgList = [];//列表初始值
export default {
    props: {
        selectedIdList: {
            type: Array,
            default: () => []
        },
        treeList: {
            type: Array,
            default: () => []
        }
    },
    model: {
        prop: 'selectedIdList',//选中的数组
        event: 'updateSelectedIdList'
    },
    watch: {
        selectedIdList: {
            handler(val) {
                debugger;
                this.$nextTick(() => {
                    this.$refs['tree'].setCheckedKeys(val,true);
                })
            },
            immediate: true
        },
        treeList: {
            handler(val) {
                if (val) {
                    orgList=JSON.parse(JSON.stringify(val));
                }
            },
            immediate: true
        }
    },
    data() {
        return {
            list: [],
            searchVal: '',
            noFilterTreeNode: false,//是否过滤树节点
            selectedList: [],
        }
    },
    created() {
        
    },
    methods: {
        //筛选
        handleFilter(val) {
            if (this.noFilterTreeNode) return;
            this.searchVal = val;
            let allList = JSON.parse(JSON.stringify(orgList));
            if (val == '') {
                this.searchList = allList;
            } else {
                this.searchList = this.filterTreeByKeyword(allList, val);
            }
            let self = this;
            debounce(function() {
                self.$nextTick(() => {
                    self.$refs['tree']?.filter(val);
                })
            },300,false)()
        },
        filterTreeByKeyword(treeData, keyword) {
            let result = [];
            function traverse(nodes) {
                for (let node of nodes) {
                    if (node.name.includes(keyword)) {
                        // 如果当前节点的 bareName 包含关键词,则添加到结果数组中
                        result.push(node);
                    }
                    if (node.children && node.children.length > 0) {
                        // 如果有子节点,则递归处理子节点列表
                        traverse(node.children);
                    }
                }
            }
            traverse(treeData); // 开始遍历整个树结构
            return result;
        },
        filterNode(value, data, node) {
            if (!value) return true;
            let obj = {
                has: false
            };
            this.searchList.map(item => {
                if (item.id == data.id) {
                    obj.has = true;
                } else {
                    let children = item.children || [];
                    this.hasFilterNode(children, data.id, obj)
                }
            })
            return obj.has;
        },
        hasFilterNode(children, id, obj) {
            if (obj.has) {
                return true;
            } else {
                for (let i = 0; i < children.length; i++) {
                    let child = children[i];
                    if (child.id == id) {
                        obj.has = true;
                        return true;
                    } else {
                        let children2 = child.children || [];
                        this.hasFilterNode(children2, id, obj)
                    }
                }
            }
        },
        removeTag(val) {
            let obj = this.checkedNodeList.find(item => item.name === val);
            this.$refs.tree.setChecked(obj.id, false);
        },
        // handleSelectChange() {
        //     let arr = [];
        //     this.selectedList.map(item => {
        //         let obj = this.checkedNodeList.find(val => val.name === item);
        //         if (obj) {
        //             arr.push(obj);
        //         }
        //     })
        //     this.checkedNodeList = arr;
        //     this.handleTreeSelect(arr);//变更树的选择
        // },
        //类别树值变动
        handleTreeSelect(row) {
            let arr = row.map(item => item.id);
            this.$refs['tree'].setCheckedKeys(arr,true);
        },
        handleSelectVisibleChange(val) {
            if (!val) {//select框隐藏时,重置树结构
                this.noFilterTreeNode = false;
                if (this.searchVal) {
                    this.handleFilter('')
                }
            }
        },
        //树选择变化
        handleCheckChange() {
            let checkList=this.$refs['tree'].getCheckedNodes(true);
            this.selectedList = checkList.map(item => item.name);
            this.$emit('updateSelectedList', checkList.map(item => item.id));
            this.checkedNodeList = checkList;
            this.noFilterTreeNode = true;//避免vl-tree筛选问题
        },

    }
}
</script>

页面中引用组件

复制代码
<template>
    <div>
        <h2>下拉框中树结构及搜索功能</h2>
        <div v-for="(v,i) in list" :key="i" class="box">
            <composeTree  :id="v.id" v-model="v.selectedIdList" :treeList="treeList">
               <!--  <template #default="{node,data}">
                    <div>
                        {{data.name}}-{{ data.id }}
                    </div>
                </template> -->
            </composeTree>
        </div>
    </div>
</template>
<script>
import composeTree from './composeTree.vue';
export default {
    data() {
        return {
            list: [
                {
                    id: 1,
                    selectedIdList:['Option001']
                },
                {
                    id: 2,
                    selectedIdList:['Option111']
                }
            ],
            treeList:[]
        }
        
    },
    components: {
        composeTree
    },
    created() {
        const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
        const options = Array.from({ length: 50 }).map((_, idx) => ({
            id: `Option${idx + 1}`,
            name: `${initials[idx % 10]}${idx}`,
            children: [
                {
                    id: `Option${'0' + idx + 1}`,
                    name: `${initials[idx % 10]}${'0'+idx}`,
                },
                {
                    id: `Option${'1' + idx + 1}`,
                    name: `${initials[idx % 10]}${'1'+idx}`,
                }
            ]
        }));
        this.treeList = options;
    }
}
</script>
<style lang="less" scoped>
.box {
    margin-bottom: 20px;
}
</style>
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
阿珊和她的猫1 分钟前
Webpack Dev Server的安装与配置:解决跨域问题
vue.js·webpack
ohMyGod_12329 分钟前
用React实现一个秒杀倒计时组件
前端·javascript·react.js
醋醋39 分钟前
Vue2源码记录
前端·vue.js
艾克马斯奎普特40 分钟前
Vue.js 3 渐进式实现之响应式系统——第四节:封装 track 和 trigger 函数
javascript·vue.js
敲代码的玉米C1 小时前
Vue Draggable 深入教程:从配置到实现的完整指南
vue.js
frontDeveloper1 小时前
Vue3基础使用概览
vue.js
frontDeveloper1 小时前
Vue2基础原理概览
vue.js
frontDeveloper1 小时前
Vue2基础使用概览
vue.js
JustHappy1 小时前
「我们一起做组件库🌻」虚拟消息队列?message组件有何不同?(VersakitUI开发实录)
前端·javascript·vue.js
Carlos_sam1 小时前
Openlayers:为Overlay创建element的四种方式
前端·javascript·vue.js