Vue2封装实现下拉菜单的Tree树形选择器效果

博客提及goto.vue,阐述其在需要使用的页面中进行调取,最终可生成想要的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

vue2+element 结合element的效果

效果图

请添加图片描述

treeSelect.vue

components-treeSelect.vue

PS 如果输入框部分 点击不生效使用@mousedown.native替代@click

<template>
  <div class="tree-select" @click.stop>
    <!-- 输入框部分 -->
    <el-input
      v-model="selectedLabel"
      :placeholder="placeholder"
      @click="toggleTree"
    >
    </el-input>

    <!-- 树形下拉区域 -->
    <div v-show="showTree" class="tree-container">
      <el-tree
        ref="tree"
        :data="options"
        show-checkbox
        :props="defaultProps"
        @node-click="handleNodeClick"
        node-key="id"
        :check-strictly="true"
        @check="handleCheckChange"
      ></el-tree>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    value: [String, Number, Array], // 选中的值(单选)
    options: { type: Array, default: () => [] }, // 树形数据
    placeholder: { type: String, default: '请选择' },
    defaultProps: {
      type: Object,
      default: () => ({ })
    }
  },
  data() {
    return {
      showTree: false,
      selectedLabel: ''
    };
  },
  watch: {
    value(newVal) {
      // 根据 value 回显 label
      this.updateLabel(newVal);
    }
  },
  mounted() {
    // 监听点击其他空白区域事件
    document.addEventListener('click', this.handleOutsideClick);
  },
  beforeDestroy() {
    // 移除点击其他空白区域事件监听
    document.removeEventListener('click', this.handleOutsideClick);
  },
  methods: {
    toggleTree() {
      this.showTree = !this.showTree;
    },
    handleNodeClick(node) {
      // 手动勾选当前节点
      this.$nextTick(() => {
        this.$refs.tree.setChecked(node, true, false);
        this.handleSingleSelect(node);
      });
    },
    handleCheckChange(data, checked) {
      if (checked) {
        // 清空所有选中状态
        this.$refs.tree.setCheckedKeys([]);
        // 设置当前节点为选中状态
        this.$refs.tree.setChecked(data.id, true);
        this.handleSingleSelect(data);
      } else {
        // 取消当前节点的选中状态
        this.$refs.tree.setChecked(data.id, false);
        this.selectedLabel = '';
        this.$emit('input', null);
      }
    },
    handleSingleSelect(node) {
      // 取消所有其他节点的勾选状态
      const allNodes = this.$refs.tree.getCheckedNodes(false, true);
      allNodes.forEach(n => {
        if (n.id!== node.id) {
          this.$refs.tree.setChecked(n, false, false);
        }
      });
      this.$emit('input', node.id);
      this.selectedLabel = node[this.defaultProps.label];
    },
    updateLabel(value) {
      if (!value) return;
      const findNode = (nodes) => {
        for (const node of nodes) {
          if (node.id === value) {
            return node;
          }
          if (node.childs) {
            const found = findNode(node.childs);
            if (found) {
              return found;
            }
          }
        }
        return null;
      };
      const node = findNode(this.options);
      if (node) {
        this.selectedLabel = node[this.defaultProps.label];
      }
    },
    handleOutsideClick() {
      // 点击其他空白区域隐藏树形菜单
      this.showTree = false;
    }
  }
};
</script>

<style>
.tree-select {
  position: relative;
}

.tree-container {
  position: absolute;
  width: 100%;
  border: 1px solid #e4e7ed;
  z-index: 999;
  background: white;
}

.el-icon-arrow-down.is-reverse {
  transform: rotate(180deg);
}
</style>    

使用页面

 <template>
  <tree-select 
    v-model="selectedId"
    :options="treeData"
    :defaultProps="defaultProps"
    placeholder="请选择"
    @change="handleChange"
  />
</template>
<script>
import TreeSelect from '@/components/pop.vue';
export default {
  components: { TreeSelect },
  data() {
    return {
      selectedId: '',
       defaultProps:{label: 'label',     value: 'id',     children: 'children'   },
       treeData: [
        // 示例树形数据
        {
          id: 1,
          label: '一级节点 1',
          children: [
            {
              id: 11,
              label: '二级节点 1-1',
            },
            {
              id: 12,
              label: '二级节点 1-2',
            },
          ],
        },
        {
          id: 2,
          label: '一级节点 2',
          children: [
            {
              id: 21,
              label: '二级节点 2-1',
            },
          ],
        },
      ]
    };
  },
 methods: { handleChange(value) { console.log('选中的值改变为:', value);     }   }
};
</script>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值