vue+elementui封装select-tree下拉树【单选

2023-11-07

组件代码:

<!--
    /**
     * 树形下拉选择组件,下拉框展示树形结构,提供选择某节点功能,方便其他模块调用
     * @author wz
     * @date 2020-06-09
     * 调用示例:
     * <tree-select :height="400" // 下拉框中树形高度
     *              :width="200" // 下拉框中树形宽度 不填写自适应el-select input框大小
     *              size="small"  // 输入框的尺寸: medium/small/mini
     *              :data="data" // 树结构的数据或者普通包含主键,父主键的普通集合
                    :obj="{}"    //可自定义字段,字段映射如下
     *              multiple   // 多选
                    //默认值:单选可传入数字,字符串,对象;多选传入【数字|字符|对象】数组,其他非法
                    :default-key="..."
     *              clearable   // 可清空选择
     *              collapseTags   // 多选时将选中值按文字的形式展示
                    expand-click-node   //点击节点自动展开。多选有效
                    check-click-node // 是否点击节点是选中 多选生效
     *              checkStrictly // 多选时,严格遵循父子不互相关联 效果参考elementui 对应属性效果
     *              @getValue="父组件获取值方法"> // 事件有两个参数:第一个是所有选中的节点ID,第二个是所有选中的节点数据
     *              </tree-select>
      <select-tree
     obj 字段映射如下,值填写你实际字段,可拓展字段。最终返回主键以及选择对象【全部字段】
                        id:'id',//可改成自己对应主键【改值】
                        label: 'name',// 显示名称
                        children: 'children', //子级字段名
                        path:'path',//路径
                        content:'content',//描述
                        pid:'pid',//父id
     */
-->
<template>
    <div>
        <div class="mask" v-show="isShowSelect"></div>
        <el-popover placement="bottom-start"  :width="popoverWidth"    trigger="manual"  v-model="isShowSelect" @hide="popoverHide">
            <el-tree class="common-tree" :width="width"   ref="tree" :data="treeData" :props="obj"
                     :show-checkbox="multiple"
                     :node-key="obj.id"
                     :check-strictly="checkStrictly"
                     :default-expanded-keys="defaultKeys"
                     :expand-on-click-node="multiple&&expandClickNode"
                     :check-on-click-node="checkClickNode"
                     :highlight-current="true"
                     @check-change="nodeClick"
                     @node-click="nodeClick"
                     ></el-tree>
            <el-select    slot="reference" ref="select" :size="size"
                       v-model="returnDataKeys"
                       :multiple="multiple"
                       :clearable="clearable"
                       :collapse-tags="collapseTags"
                       @click.native="selectClick"
                       @remove-tag="removeTag"
                       @clear="clean"
                       class="tree-select">
                <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
            </el-select>
            <el-row>
                <el-button v-if="multiple" class="ok" @click="isShowSelect=false" size="mini" type="text">确定</el-button>
            </el-row>
        </el-popover>
    </div>
</template>

<script>
    export default {
        name: 'test-code',
        props: {
            // 树结构数据
            data: {
                type: Array,
                default () {
                    return [];
                }
            },
            obj: {
                type: Object,
                required: false,
                default:()=>{
                    return {
                        id:'id',// ID
                        label: 'name',// 显示名称
                        children: 'children', //子级字段名
                        path:'path',//路径
                        content:'content',//描述
                        pid:'pid',//父id
                    }
                }
            },
            // 配置是否可多选
            multiple: {
                type: Boolean,
                default () {
                    return false;
                }
            },
            // 配置是否可清空选择
            clearable: {
                type: Boolean,
                default () {
                    return false;
                }
            },
            // 配置多选时是否将选中值按文字的形式展示
            collapseTags: {
                type: Boolean,
                default () {
                    return false;
                }
            },
            // 显示复选框情况下,是否严格遵循父子不互相关联
            checkStrictly: {
                type: Boolean,
                default () {
                    return false;
                }
            },
            //多选是设置点击节点是否可以选中
            checkClickNode:{
                type: Boolean,
                default () {
                    return false;
                }
            },
            //多选时:点击节点展开还是点三角标
            expandClickNode:{
                type: Boolean,
                default () {
                    return false;
                }
            },
            // 默认选中的节点key
            defaultKey: {
                type: [Number,String,Array,Object],
                default () {
                    return [];
                }
            },
            size: {
                type: String,
                default () {
                    return 'small';
                }
            },
            width: {
                type: String,
                default () {
                    return '100%';
                }
            },
            height: {
                type: String,
                default () {
                    return '300px';
                }
            }
        },
        //上面是父组件可传入参数
        data () {
            return {
                popoverWidth:"0px",//下拉框大小
                isShowSelect: false, // 是否显示树状选择器
                options: [],//select option选项
                returnDatas:[],//返回给父组件数组对象
                returnDataKeys:[],//返回父组件数组主键值
            };
        },
        computed: {
            treeData() { // 若非树状结构,则转化为树状结构数据
                return   JSON.stringify(this.data).indexOf(this.obj.children) !== -1 ? this.data :  this.switchTree();
            },
        },
        methods: {
            init(){
                // eslint-disable-next-line no-undef,no-debugger
                // debugger
                if(this.defaultKey!=undefined&&this.defaultKey.length>0){
                    if (this.multiple) {
                        // 多选
                        if( Object.prototype.toString.call(this.defaultKey).indexOf("Array")!=-1){
                            if(Object.prototype.toString.call(this.defaultKey[0]).indexOf("Object")!=-1){//对象
                                this. setDatas(this.defaultKey);
                            }else if(Object.prototype.toString.call(this.defaultKey[0]).indexOf("Number")!=-1
                                || Object.prototype.toString.call(this.defaultKey[0]).indexOf("String")!=-1){
                                this.setKeys(this.defaultKey);
                            }else{
                                console.log("多选:传入参数类型不匹配");
                                return;
                            }
                        }else {
                            console.log("多选:传入参数类型不匹配");
                            return;
                        }

                    } else {
                        // 单选
                        if( Object.prototype.toString.call(this.defaultKey).indexOf("Number")!=-1
                            || Object.prototype.toString.call(this.defaultKey).indexOf("String")!=-1
                            || Object.prototype.toString.call(this.defaultKey).indexOf("Object")!=-1 ){
                            this.setKey(this.defaultKey);
                        }else {
                            console.log("单选:传入参数类型不匹配");
                            return;

                        }

                    }
                }
            },
            //下拉框select点击[入口]
            selectClick(){
                this.$nextTick(function () {//设置下拉框自适应宽度
                    this.popoverWidth= this.$refs.select.$el.clientWidth-26;
                })
                //显示下拉框
                return this.isShowSelect = !this.isShowSelect
            },
            //单选: 树点击方法
            nodeClick (data, node) {
               if (!this.multiple) {//单选
                   this.isShowSelect=false;
                   this.setKey(node.key);
               }else{//多选
                   var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
                   var t=[];
                   this.options = checkedKeys.map((item) => {//设置option选项
                       var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
                       t.push(node.data);
                       return {label:node.label,value:node.key};
                   });
                   this.returnDataKeys = this.options.map((item) => {
                       return item.value;
                   });
                   this.returnDatas=t;
               }
            },
            //单选:清空选中
            clean () {
                this.$refs.tree.setCurrentKey(null);//清除树选中key
                this.returnDatas=null;this.returnDataKeys='';
                this.popoverHide ();

            },
            //单选:设置、初始化值 key
            setKey (thisKey) {
               this.$refs.tree.setCurrentKey(thisKey);
               var node = this.$refs.tree.getNode(thisKey);
               this.setData(node.data);
            },
            //单选:设置、初始化对象
            setData(data){
                this.options = [];
                this.options.push({label:data[this.obj.label],value:data[this.obj.id]});
                this.returnDatas = data;
                this.returnDataKeys=data[this.obj.id]
                
            },
            //多选:设置、初始化值 keys
            setKeys (thisKeys) {
                this.$refs.tree.setCheckedKeys(thisKeys);
                this.returnDataKeys=thisKeys;
                var t=[];
                thisKeys.map((item) => {//设置option选项
                    var node = this.$refs.tree.getNode(item); // 所有被选中的节点对应的node
                    t.push(node.data);
                    return {label:node.label,value:node.key};
                });
                this.returnDatas=t;
                this.popoverHide()
            },
            //多选:设置、初始化对象
            setDatas(data){
                this.$refs.tree.setCheckedNodes(data);
                this.returnDatas=data;
                var t=[];
                data.map((item) => {//设置option选项
                    t.push(item[this.obj.id]);
                });
                this.returnDataKeys=t;
                this.popoverHide()
            },
            // 多选,删除任一select选项的回调
            removeTag (val) {
                this.$refs.tree.setChecked(val, false);//设置为未选中
                var node = this.$refs.tree.getNode(val);//获取节点
                if (!this.checkStrictly && node.childNodes.length > 0) {
                    this.treeToList(node).map(item => {
                        if (item.childNodes.length <= 0) {
                            this.$refs.tree.setChecked(item, false);
                        }
                    });
                }
                this.nodeClick();
                this.popoverHide ();

            },
            //下拉框关闭执行
            popoverHide () {
                this.$emit('getValue', this.returnDataKeys, this.returnDatas);
            },
            // 多选,清空所有勾选
            clearSelectedNodes () {
                var checkedKeys = this.$refs.tree.getCheckedKeys(); // 所有被选中的节点的 key 所组成的数组数据
                for (let i = 0; i < checkedKeys.length; i++) {
                    this.$refs.tree.setChecked(checkedKeys[i], false);
                }
            },

            //树形转为集合
            treeToList (tree) {
                var queen = [];
                var out = [];
                queen = queen.concat(tree);
                while (queen.length) {
                    var first = queen.shift();
                    if (first.childNodes) {
                        queen = queen.concat(first.childNodes);
                    }
                    out.push(first);
                }
                return out;
            },
            switchTree() {
                return this.buildTree(this.data, this.defaultValue);
            },
            // 将一维的扁平数组转换为多层级对象
            buildTree(data, id) {
                const fa = (id) => {
                    const temp = [];
                    for (let i = 0; i < data.length; i++) {
                        const n = data[i];
                        if (n[this.obj.pid] === id) {
                            n[this.obj.children] = fa(n[this.obj.id]);
                            temp.push(n);
                        }
                    }
                    return temp;
                };
                return fa(id);
            },

        },
        watch: {
            // eslint-disable-next-line no-unused-vars
            isShowSelect (val) {
                // 隐藏select自带的下拉框
                this.$refs.select.blur();
            },
            treeData(){//监听tree数据
                this.$nextTick(()=> {
                 this.init();
                })
            }
        }
    };
</script>

<style scoped>
    .mask{
        height: 100%;
        position: fixed;
        top: 0;
        left: 0;
        opacity: 0;
        z-index: 11;
    }
    .common-tree{
        overflow: auto;
    }
    .tree-select{
        z-index: 111;
    }
    .ok{
        float: right;
    }
    .el-row{
        padding-top: 0px !important;
    }
</style>

调用示例:

标签:

<el-form ref="form" :model="form" label-width="80px">
 <el-form-item label="菜单路径:" prop="menu" >
                        <select-tree size="small" :data="menuFolder" clearable checkStrictly @getValue="setTreeMenu"></select-tree>
                    </el-form-item></el-form>
methods:中方法获取值:
 setTreeMenu(key,data){//获取子组件值
                console.log(key)
                console.log(data)
            },

单选效果:

标题

多选效果:

标题

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue+elementui封装select-tree下拉树【单选 的相关文章

  • ssh登录时提示「permission denied please try again」

    ssh使用root账号登录系统 提示permission denied please try again 可能导致该情况的几种原因 密码被改了 只能换其他账号登录 之后使用sudo命令执行 使用root还没打开 可以使用以下几步进行修改 使
  • Maven: Could not transfer artifact xxx from/to xxx

    1 美图 2 背景 遇到这个问题 Could not transfer artifact xxx from to xxx 暂时还没解决 解决后 会补上 Maven报错 Could not transfer artifact xxx from
  • float(“inf“)、float(“-inf“)

    一 python里如何表示正负无穷 正无穷 float inf 负无穷 float inf 二 用inf做简单加 乘算术运算会得到inf print 1 float inf inf print 2 float inf inf 三 除了inf
  • python线性表

    顺序表 顺序表 将元素顺序地存放在一块连续的存储区里 元素间的顺序关系由它们的存储顺序自然表示 数据元素本身连续存储 每个元素所占的存储单元大小固定相同 元素的下标是其逻辑地址 而元素存储的物理地址 实际内存地址 可以通过存储区的起始地址L

随机推荐

  • 山石网科国产化入侵防御系统,打造全生命周期的安全防护

    随着互联网的普及和网络安全的威胁日益增加 botnet感染成为了企业面临的重要问题之一 botnet是一种由分散的客户端 或肉鸡 组成的网络 这些客户端被植入了bot程序 受控于攻击者 攻击者通过这些客户端的bot程序 利用C C服务器对这
  • 指数分布的定义形式及应用

    转载请注明出处 http blog csdn net ningyaliuhebei article details 46409941 指数分布是连续型随机变量 指数分布具有无记忆性 指数分布是特殊的gamma分布 指数分布 Exponent
  • python主流web框架识别

    想学习web框架 又想熟悉python 问题来了 有没有极简的数据来支撑快速开发 特来研究 不能去研究几十个 没时间 研究主流的即可 Django Tornado Flask Twisted 所谓网络框架是指这样的一组Python包 它能够
  • 树组件根节点+叶节点渲染

    本人使用的是eleme的树组件进行的数据渲染 Element The world s most popular Vue UI frameworkElement 一套为开发者 设计师和产品经理准备的基于 Vue 2 0 的桌面端组件库http
  • 进阶题解:反转链表

    入门级题解 https blog csdn net m0 46663240 article details 122602996 一刷代码随想录 再次遇到这个反转链表 当时可是难到我了 现在做还是比较轻松的 思路及关键点 1 有两部分 一部分
  • ROS入门四 服务中的Server和Client

    服务中的Server和Client 简介 使用 spawn服务写一个客户端程序创建一只新海龟 服务模型 创建turtle spawn cpp 配置CMakeLists txt中的编译规则 编译并运行 总结流程 创建一个服务接受client消
  • 数学建模——仓内拣货优化问题

    仓内拣货优化问题 求解 某电商公司客户订单下达仓库后 商品开始下架出库 出库主要包含5 个流程如图1所示 定位 仓库有多个货架 每个货架有多个货格 商品摆放在货格中 且每个货格最多摆放一种商品 商品可以摆放在多个货格 订单下达仓库后 定位操
  • springboot有关type-aliases-package设置,xml别名爆红错误

    在application yaml中设置 mybatis mapperLocations classpath mapper xml type aliases package com chan springcloud entities 但xm
  • 【CSS】动态背景1

    效果 代码
  • 利用Vulnhub复现漏洞 - mini_httpd任意文件读取漏洞(CVE-2018-18778)

    mini httpd任意文件读取漏洞 CVE 2018 18778 Vulnhub官方复现教程 漏洞原理 复现过程 启动环境 端口设置 浏览器设置 BurpSuit设置 漏洞复现 Vulnhub官方复现教程 https vulhub org
  • 【目录贴】硕士实验室嵌入式学习路线参考清单

    下面是对我在硕士期间边学边实践所写的部分文章 挑选整理出一个 学习清单 其实我写到目前为止 如果你看进去了这些东西 可以说各种东西达到了熟悉 熟练的状态 可不敢说精通 面试官会出手 如果看到这篇路线总结 无论你是本科还是硕士 你也别太感觉东
  • TCP的半关闭状态以及tcp-keepalive

    文章目录 半关闭状态 实现方法 tcp keepalive 开启 tcp keepalive 方法1 Linux系统全局开启 方法2 setsockopt 设置 socket 半关闭状态 一次TCP四次挥手的过程如上图所示 设左侧为客户端
  • elasticsearch 去重查询并进行分页

    去重查询的俩种方式 在进行去重查询时 原来的目的是对于查询出的结果中一模一样的数据进行去重 但是各种百度发现都是对于单一字段的去重查询 最后索性新增了一个字段 将其他字段拼接了起来 从而根据拼接的字段进行去重查询 1 使用字段聚合 top
  • windows:windows10 下如何让程序被 Cortana搜索到

    参考 https blog csdn net qq 26462567 article details 101011871 总结 添加快捷方式到开始菜单目录
  • 测试框架pytest教程(5)运行失败用例-rerun failed tests

    content of test 50 py import pytest pytest mark parametrize i range 50 def test num i if i in 17 25 pytest fail bad luck
  • 八度音阶和频率的关

    八度音阶和频率的关系 Frequency in hertz semitones above or below middle C Octave Note 0 1 2 3 4 5 6 7 8 9 C 16 352 48 32 703 36 65
  • Qt 常用的字符转换,QString如何转换成const char类型, 转 PWCHAR wchar_t*

    常用的字符转换 日常记录 QString如何转换成const char类型 const char cmd data qstring toStdString c str qstring为待转换的qstring类型字符串 QString for
  • redis主从复制和哨兵模式

    redisi主从和哨兵模式 主从复制概扩及原理 redisi主从复制模式 redis哨兵原理 redis哨兵模式 主从复制概扩及原理 Redis主从复制是指将一个Redis实例 即主库 的数据复制到其他Redis实例 即从库 的过程 主节点
  • 一分钟了解HTTP和HTTPS协议

    很多人存在这样的疑惑就是http与https的区别 这篇文章就跟大家介绍一下 一句话总结HTTPS是身披SSL外壳的HTTP HTTPS更安全 实际使用中绝大多数的网站现在都采用的是HTTPS协议 这也是未来互联网发展的趋势 什么是协议 网
  • vue+elementui封装select-tree下拉树【单选

    组件代码