Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉

这篇具有很好参考价值的文章主要介绍了Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

        今天小谭要给大家分享的是基于element ui 的下拉框和树型控件二次分装的树型下拉框,element plus新增了这一组件,但是对于还在使用vue2的我来说,就很不友好。组件可以实现单选和多选,以及其他常用功能,废话不多说,直接上效果图:

element树形下拉框,vue.js,前端,javascript,elementuielement树形下拉框,vue.js,前端,javascript,elementui


代码实现

效果图如上,接下来实现代码:

使用时,如果想实现回显效果node-key必须要传!!!

HTMl:

<!-- 
 * @description: 通用树型下拉框
 * @fileName: treeSelect.vue 
 * @author: t 
 * @date: 2023-03-07 17:15:03
 * @Attributes: data	展示数据	array
                props	配置选项,具体配置可以参照element ui库中el-tree的配置	object
                show-checkbox	节点是否可被选择	boolean
                check-strictly	在显示复选框的情况下,是否严格的遵循父子不互相关联的做法,默认为 false	boolean
                icon-class	自定义树节点的图标	string
                load	加载子树数据的方法,仅当 lazy 属性为true 时生效	function(node, resolve)
                lazy	是否懒加载子节点,需与 load 方法结合使用	boolean
                disabled	下拉框是否禁用
                getCheckedKeys	若节点可被选择(即 show-checkbox 为 true),则返回目前被选中的节点的 key 所组成的数组
                getCurrentNode	获取当前被选中节点的 data,若没有节点被选中则返回 null  
                collapse-tags	多选时是否将选中值按文字的形式展示
                select-last-node	单选时是否只能选择最后一个节点
                Scoped Slot 自定义树节点的内容,参数为 { node, data }
                show-count 若节点中存在children 则在父节点展示所属children的数量,注意但设置插槽时 show-count将失效!
                clearable	单选时是否可以清空选项
                filterable 属性即可启用搜索功
                !!!!!必传!!!!!! props-value	每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 !!!!!!
!-->
<!--:clearable="$attrs['show-checkbox']==undefined?$attrs['clearable']:false"-->
<template>
    <el-select
        :value="valueFilter(value)"
        :placeholder="$attrs['placeholder']"
        :multiple="$attrs['show-checkbox']"
        :disabled="$attrs['disabled']"
        :filterable="$attrs['filterable']"
        :clearable="$attrs['clearable']"
        :collapse-tags="$attrs['collapse-tags']"
        @change="selectChange"
        @clear="selectClear"
        ref="mySelect"
        :filter-method="remoteMethod"
    >
        <template slot="empty">
            <div class="selecTree">
                <el-tree
                    :data="data"
                    :props="props"
                    @node-click="handleNodeClick"
                    :show-checkbox="$attrs['show-checkbox']"
                    :check-strictly="$attrs['check-strictly']"
                    :icon-class="$attrs['icon-class']"
                    :lazy="$attrs['lazy']"
                    :load="$attrs['load']"
                    :node-key="props.value"
                    :filter-node-method="filterNode"
                    @check-change="handleCheckChange"
                    :default-expanded-keys="defaultExpandedKeys"
                    ref="myTree"
                >
                    <template slot-scope="{ node, data }">
                        <slot :node="node" :data="data">
                            <span class="slotSpan">
                                <span>
                                    {{ data[props.label] }}
                                    <b v-if="$attrs['show-count'] != undefined && data[props.children]">({{ data[props.children].length }})</b>
                                </span>
                            </span>
                        </slot>
                    </template>
                </el-tree>
            </div>
        </template>
    </el-select>
</template>

JS:

export default {
    props: {
        value: {
            type: undefined,
            default: null,
        },
        data: {
            type: Array,
            default: null,
        },
        props: {
            type: Object,
            default: null,
        },
    },
    data() {
        return {
            defaultExpandedKeys: [],
        };
    },
    created() {
        this.propsInit();
    },
    mounted() {
        setTimeout(this.initData, 10);
    },
    beforeUpdate() {
        this.propsInit();
        this.initData();
    },

    methods: {
        initData() {
            if (this.$attrs['show-checkbox'] === undefined) {
                let newItem = this.recurrenceQuery(this.data, this.props.value, this.value);
                if (newItem.length) {
                    if (this.props.value && newItem[0][this.props.value]) {
                        this.defaultExpandedKeys = [newItem[0][this.props.value]];
                    }
                    this.$nextTick(() => {
                        this.$refs.myTree.setCurrentNode(newItem[0]);
                    });
                }
            } else {
                let newValue = JSON.parse(JSON.stringify(this.value));
                if (!(newValue instanceof Array)) {
                    newValue = [newValue];
                }
                if (newValue?.length) {
                    let checkList = newValue.map(key => {
                        if (key) {
                            let newItem = this.recurrenceQuery(this.data, this.props.value, key);
                            return newItem[0] || '';
                        }
                    });
                    if (checkList?.length) {
                        let defaultExpandedKeys = checkList.map(item => item?.[this.props.value || '']);
                        if (defaultExpandedKeys.length) this.defaultExpandedKeys = defaultExpandedKeys;
                        this.$nextTick(() => {
                            this.$refs.myTree.setCheckedNodes(checkList);
                        });
                    }
                }
            }
            this.$forceUpdate();
        },
        // 多选
        handleCheckChange(data, e, ev) {
            let checkList = this.$refs.myTree.getCheckedNodes();
            let setList = null;
            if (checkList.length) {
                setList = checkList.map(item => item[this.props.value]);
            }
            this.$emit('input', setList);
            // 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点
            this.$emit('change', data, e, ev);
        },
        // 单选事件
        handleNodeClick(data, e) {
            if (!(this.$attrs['select-last-node'] === undefined)) {
                if (data[this.props.children] && data[this.props.children]?.length) {
                    return false;
                }
            }
            if (this.$attrs['show-checkbox'] === undefined) {
                this.$emit('input', data[this.props.value]);
                this.$refs.mySelect.blur();
            }
            this.$emit('change', data, e);
        },
        //   递归查找通用方法
        recurrenceQuery(list, key, value) {
            if (!list || !key || !value) return [];
            let queryData = [];
            list.map(item => {
                if (item[this.props.children] && item[this.props.children].length) {
                    queryData.push(...this.recurrenceQuery(item[this.props.children], key, value));
                }
                if (item[key] == value) {
                    queryData.push(item);
                }
                return item;
            });
            return queryData;
        },
        selectChange(e) {
            if (this.$attrs['show-checkbox'] !== undefined) {
                let checkList = e.map(key => {
                    let newItem = this.recurrenceQuery(this.data, this.props.label, key);
                    return newItem[0] || '';
                });
                this.$refs.myTree.setCheckedNodes(checkList);
                this.$emit('input', e);
            }
        },
        selectClear(flag) {
            if (this.$attrs['show-checkbox'] === undefined) {
                if (!flag) this.$emit('input', '');
                this.$refs.myTree.setCurrentKey(null);
            } else {
                if (!flag) this.$emit('input', []);
                this.$refs.myTree.setCheckedKeys([]);
            }
            this.remoteMethod('');
        },
        getCheckedNodes() {
            if (this.value !== null && this.value !== undefined && this.value !== '') {
                return this.$refs.myTree.getCheckedNodes();
            }
            return [];
        },
        getCurrentNode() {
            if (this.value !== null && this.value !== undefined && this.value !== '') {
                return this.$refs.myTree.getCurrentNode();
            }
            return null;
        },
        valueFilter(val) {
            if (this.$attrs['show-checkbox'] === undefined) {
                let res = '';
                [res] = this.recurrenceQuery(this.data, this.props.value, val);
                return res?.[this.props.label] || '';
            } else {
                if (!val?.length) return [];
                let res = val.map(item => {
                    let [newItem] = this.recurrenceQuery(this.data, this.props.value, item);
                    return newItem?.[this.props.label] || '';
                });
                if (!res?.length) return [];
                res = res.filter(item => item);
                return res;
            }
        },
        propsInit() {
            this.props.label = this.props.label || 'label';
            this.props.value = this.props.value || 'value';
            this.props.children = this.props.children || 'children';
            if (this.$attrs['select-last-node'] !== undefined && !this.props.disabled) {
                this.props.disabled = data => data?.[this.props.children]?.length;
                this.$attrs['check-strictly'] = true;
            }
        },

        remoteMethod(query) {
            this.$refs.myTree.filter(query);
        },
        filterNode(value, data) {
            if (!value) return true;
            return data[this.props.label].indexOf(value) !== -1;
        },
    },

    watch: {
        value: {
            deep: true,
            handler(val) {
                if (!val || !val?.length) {
                    this.selectClear(true);
                }
            },
        },
    },
};

CSS:文章来源地址https://www.toymoban.com/news/detail-538437.html

.selecTree {
    max-height: 50vh;
    overflow: auto;
    padding: 5px;
}
.el-select {
    width: 100%;
}
.slotSpan {
    font-size: 14px;
    b {
        font-weight: normal;
        font-size: 12px;
        color: #999;
    }
}
.selecTree ::v-deep .el-tree-node__content {
    font-size: 14px;
}

到了这里,关于Element树型下拉框/vue2树型下拉框/TreeSelect/树型下拉的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • vue2 element ui 实现图标下拉选择

    1.展示效果 代码展示: (1)封装icon.js (2) 在需要使用的页面复制进去 (3)在自己需要使用的地方复制进去 (4)css样式部分 (5)初始化数据

    2024年02月10日
    浏览(33)
  • vue3+element-plus组件下拉列表,数组数据转成树形数据

    引入组件 可以直接在项目中引入element-plus表格组件,如果需要变成下拉列表样式需要添加以下属性: row-key 必填 最好给数字或唯一属性 , 给每个节点设置id 不填的话 没有办法实现展开效果 load 这个是动态添加数据的 前提(开启lazy ,表格数组里设置了hasChildren:true) tre

    2024年02月13日
    浏览(38)
  • vue2+element-ui el-tree树形控件封装

    1.封装 根据官网配置项封装了下el-tree 方便维护和复用,有用的话点赞收藏叭~ 2.使用 如若要对不同的一级二级节点设置不同的样式可以参考这样:

    2024年02月12日
    浏览(40)
  • VUE2+Element-ui树形控件tree结构的值获取和传给后台

    最近做到了权限管理模块 其中的菜单权限需要用到tree结构进行多选功能的渲染操作 废话少说,直接上代码 将tree结构放在form中配合表单使用 并附带全选和全不选,展开和折叠功能 其中的show-checkbox作用是对tree数据的多选模式 要写在data中的数据 其中defaultProps一定不能忘记

    2024年02月05日
    浏览(43)
  • 【vue2+element ui】添加修改共用表单的下拉框回显问题分析以及解决方案(附共用表单代码)

    简介 本人前端水平不佳,本文分享在编写个人项目前端代码的时候遇到的回显问题的解决办法,仅供参考。 问题复原 首先展示表单中的问题代码,本次前端的设计是添加和修改操作共用表单,但是其中有一个下拉框展示形式,按照惯例通过:value进行双向绑定,保证点击修改

    2024年02月07日
    浏览(33)
  • vue2+elementUI 下拉树形多选框

    效果如图所示:  1.新建el-select-tree.vue组件 2.页面引入组件使用

    2024年02月12日
    浏览(33)
  • vue-treeselect(适配Vue3.2)及Element-plus的TreeSelect组件

    1.1、vue2 使用的版本 官网地址:https://www.npmjs.com/package/@riophae/vue-treeselect 是3年前更新的 安装: 如果你的项目是vue3的话,使用该安装命令会提示,此命令只针对vue2.2版本 具体提示内容是: peerDependencies WARNING @riophae/vue-treeselect@latest requires a peer of vue@^2.2.0 but vue@3.2.39 was instal

    2024年02月15日
    浏览(52)
  • vue+element Ui 树型组件tree懒加载+搜索框远程请求数据为平铺类型

    本人之前一直是耕耘后台研发,最近接了个小需求需要接触到vue,记录一下我遇到的一些前端解决时间长的问题 需求: 1:每次动态请求接口获取下一节点数据 2:接口返回的数据是list,不带子节点,用pid来维护父子之间的关系 3:带有搜索框,搜索框为请求远程数据,数据

    2024年02月05日
    浏览(32)
  • vue+element ui 完成 树形数据穿梭框

    element ui中的穿梭框只能实现平铺数据的穿梭,这次的需求是要树形数据穿梭,所以写的是tree组件自己组合的穿梭框

    2024年02月15日
    浏览(31)
  • vue2.x + element-ui提示:找不到node_modules/async-validator/es/index.js文件

    no such file or directory, open ‘xx/node_modules/async-validator/es/index.js’ 我按照提示确实没有在node_modules找到async-validator文件夹,本来是手动npm install了这个文件,但是发现找不到es文件夹了,所以就干脆又运行了一遍安装element-ui包的命令将这个漏掉的包补上了。

    2024年02月02日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包