Vue实现无限级树形选择器

yizhihongxing

下面是Vue实现无限级树形选择器的完整攻略:

1. 需求分析

首先,我们需要确定本次开发的需求。本次开发要实现一个无限级别的树形选择器,包含以下要求:

  • 根据给定的数据结构渲染树形结构;
  • 支持无限极展开和收起;
  • 支持多选和单选;
  • 支持选择器搜索;

2. 技术选型

基于此,我们可以选择使用Vue.js框架进行开发,并结合Vue组件,Element-ui库来完成组件的构建。

3. 数据结构设计

树形结构的展开和收起是通过组件之间的嵌套来实现的,因此我们需要确定树形结构的数据结构设计。

例如如下的数据结构:

{
  "label": "一级选择器",
  "value": "0",
  "children": [{
    "label": "二级选择器1",
    "value": "1-1",
    "children": [{
      "label": "三级选择器1-1",
      "value": "1-1-1"
    }, {
      "label": "三级选择器1-2",
      "value": "1-1-2"
    }]
  }, {
    "label": "二级选择器2",
    "value": "1-2",
    "children": [{
      "label": "三级选择器2-1",
      "value": "1-2-1"
    }, {
      "label": "三级选择器2-2",
      "value": "1-2-2"
    }]
  }]
}

4. 组件设计

4.1 父组件

父组件的作用是渲染整个树形结构,并且控制每个子组件的展开和收起。

<template>
  <div>
    <tree-node
      :data="treeData"
      :multiple="multiple"
      :is-searchable="isSearchable"
      :search-placeholder="searchPlaceholder"
      v-model="selectedValues"
    />
  </div>
</template>

<script>
import TreeNode from './tree-node.vue'

export default {
  name: "TreeSelector",
  components: {TreeNode},
  props: {
    treeData: {
      required: true,
      type: Object
    },
    value: {
      default: [],
      type: [Array, String, Number]
    },
    multiple: {
      default: false,
      type: Boolean
    },
    isSearchable: {
      default: true,
      type: Boolean
    },
    searchPlaceholder: {
      default: '搜索',
      type: String
    },
  },
  data() {
    return {
      selectedValues: []
    }
  },
  mounted() {
    this.selectedValues = this.value
  },
  watch: {
    selectedValues: function (val) {
      this.$emit('input', val);
    },
    value: function (val) {
      this.selectedValues = val
    }
  }
};
</script>

4.2 子组件

子组件的作用是渲染每个节点,包含展开和收起。

<template>
  <div>
    <el-tree
      v-if="!isSearchVisible"
      :data="data"
      :node-key="props.nodeKey"
      :props="props"
      :default-expand-all="true"
      :expand-on-click-node="false"
      @node-click="handleNodeClick"
      @check-change="handleCheckChange"
      :show-checkbox="multiple"
      v-model="checkedKeys">
    </el-tree>
    <el-tree
      v-else
      :data="filteredData"
      :node-key="props.nodeKey"
      :props="props"
      :default-expand-all="true"
      :expand-on-click-node="false"
      @node-click="handleNodeClick"
      @check-change="handleCheckChange"
      :show-checkbox="multiple"
      v-model="checkedKeys">
    </el-tree>
  </div>
</template>

<script>
export default {
  name: "TreeNode",
  props: {
    data: {
      required: true,
      type: Object
    },
    multiple: {
      default: false,
      type: Boolean
    },
    isSearchable: {
      default: true,
      type: Boolean
    },
    searchPlaceholder: {
      default: '搜索',
      type: String
    }
  },
  data() {
    return {
      checkedKeys: [],
      filteredData: [],
      props: {
        label: 'label',
        children: 'children'
      }
    }
  },
  methods: {
    handleNodeClick(data) {
      this.$emit('node-click', data);
    },
    handleCheckChange(data, checked) {
      this.$emit('check-change', data, checked);
    }
  },
  watch: {
    data: {
      handler(val) {
        this.checkedKeys = this.$parent.selectedValues;
      },
      deep: true
    }
  },
  computed: {
    isSearchVisible() {
      return this.isSearchable && this.filteredData.length > 0;
    }
  },
  mounted() {
    this.checkedKeys = this.$parent.selectedValues;
  }
};
</script>

4.3 过滤器组件

筛选器功能是根据关键字搜索匹配的节点。

<template>
  <div>
    <el-input
      :placeholder="searchPlaceholder"
      v-model="filterText"
      clearable
      size="mini"
      @clear="filterText = ''"
    />
    <div v-if="filteredData && filteredData.length > 0">
      <el-tree
        :data="filteredData"
        :node-key="props.nodeKey"
        :props="props"
        :default-expand-all="true"
        :expand-on-click-node="false"
        @node-click="handleNodeClick"
        @check-change="handleCheckChange"
        :show-checkbox="multiple"
        v-model="checkedKeys"
      />
    </div>
    <p v-else>没有找到匹配的节点</p>
  </div>
</template>

<script>
export default {
  name: 'TreeSelectorFilter',
  props: {
    data: {
      type: Array,
      required: true
    },
    multiple: {
      default: false,
      type: Boolean
    },
    searchPlaceholder: {
      default: '搜索',
      type: String
    }
  },
  data() {
    return {
      filterText: '',
      checkedKeys: [],
      filteredData: [],
      props: {
        label: 'label',
        children: 'children'
      }
    }
  },
  methods: {
    handleNodeClick(data) {
      this.$emit('node-click', data);
    },
    handleCheckChange(data, checked) {
      this.$emit('check-change', data, checked);
    }
  },
  watch: {
    filterText: function (val) {
      if (!val) {
        this.filteredData = [];
      } else {
        this.filteredData = this.filterTreeData(this.data, val);
      }
    },
    data: function () {
      this.checkedKeys = []
    }
  },
  mounted() {
    this.filteredData = this.data;
  },
  computed: {
    filterTreeData() {
      const filter = function (data, text) {
        return data.filter(function (item) {
          if (item.label.indexOf(text) > -1) {
            return true;
          } else if (item.children && item.children.length > 0) {
            return filter(item.children, text);
          } else {
            return false;
          }
        });
      };
      return filter;
    }
  }
};
</script>

5. 示例说明

5.1 示例一:基本用法

<template>
  <tree-selector :tree-data="treeData" v-model="selectedValues" />
</template>

<script>
import TreeSelector from "./components/tree-selector.vue";

export default {
  name: "App",
  components: {
    TreeSelector
  },
  data() {
    return {
      treeData: {
        label: "全国",
        value: "0",
        children: [{
          label: "浙江",
          value: "1",
          children: [{
            label: "杭州",
            value: "1-1"
          }, {
            label: "宁波",
            value: "1-2"
          }]
        }, {
          label: "福建",
          value: "2",
          children: [{
            label: "福州",
            value: "2-1"
          }]
        }]
      },
      selectedValues: []
    };
  }
};
</script>

5.2 示例二:多选

<template>
  <tree-selector :tree-data="treeData" v-model="selectedValues" :multiple="true" />
</template>

<script>
import TreeSelector from "./components/tree-selector.vue";

export default {
  name: "App",
  components: {
    TreeSelector
  },
  data() {
    return {
      treeData: {
        label: "全国",
        value: "0",
        children: [{
          label: "浙江",
          value: "1",
          children: [{
            label: "杭州",
            value: "1-1"
          }, {
            label: "宁波",
            value: "1-2"
          }]
        }, {
          label: "福建",
          value: "2",
          children: [{
            label: "福州",
            value: "2-1"
          }]
        }]
      },
      selectedValues: []
    };
  }
};
</script>

以上就是Vue实现无限级树形选择器的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue实现无限级树形选择器 - Python技术站

(0)
上一篇 2023年6月9日
下一篇 2023年6月9日

相关文章

  • 实现div滚动条默认最底部以及默认最右边的示例代码

    实现div滚动条默认最底部以及默认最右边可以通过设置scrollTop和scrollLeft属性来实现。 滚动到底部 下面是一个示例代码,用于实现滚动条默认滚动到div的底部。 .chat-box{ height: 300px; overflow-y: scroll; } const chatBox = document.querySelector(‘.ch…

    css 2023年6月10日
    00
  • IE6和IE7中行内元素后的浮动元素被折行的问题解决

    当一个行内元素后面跟着一个浮动元素时,IE6和IE7会出现该行包含浮动元素的“坍塌”问题,导致浮动元素被折行到下一行。下面是详细的解决攻略: 解决攻略: 1. 给浮动元素添加display:inline属性 该方式是最简单的解决方法。将浮动元素从块级元素转化成行内元素,可以解决IE6和IE7中行内元素后的浮动元素被折行的问题。 float: left; di…

    css 2023年6月10日
    00
  • 老生常谈position定位——让人又爱又恨的属性

    对于“老生常谈position定位——让人又爱又恨的属性”,我可以给你一个完整的攻略。 什么是position定位? position是CSS中非常重要的一个属性,它用于设置元素的定位方式。常见的取值有static(静态定位)、relative(相对定位)、absolute(绝对定位)和fixed(固定定位)。 元素的位置可以由CSS的left、right、…

    css 2023年6月10日
    00
  • CSS 三栏等高布局实现方法

    CSS三栏等高布局实现方法 在Web开发中,三栏等高布局是一种常见的布局方式。本攻略将详细讲解CSS三栏等高布局的实现方法,包括基本原理、使用方法和示例说明。 1. 基本原理 CSS三栏等高布局的基本原理是通过使用CSS的float属性和clear属性来实现。具体来说,可以将三个元素分别设置为左浮动、右浮动和不浮动,并使用clear属性来清除浮动,从而实现三…

    css 2023年5月18日
    00
  • css控制超链接(css超链接样式)

    CSS控制超链接完整攻略 超链接是网页中常用的元素之一,在阅读过程中点击超链接可以实现页面的跳转。而且,通过CSS样式控制,可以美化超链接的外观,增加用户体验。下面是CSS控制超链接完整攻略: 基本语法格式 在CSS中,通过a标签来控制超链接的样式。a标签表示网页中的超链接,可以通过以下声明属性来控制其外观: a:link { /*超链接默认样式*/ } a…

    css 2023年6月10日
    00
  • Knockout visible绑定使用方法

    下面介绍一下”Knockout visible绑定使用方法”的完整攻略。 什么是Knockout visible绑定? Knockout visible绑定是Knockout.js提供的一个绑定方法,用于控制HTML元素的显示和隐藏。当参数为true时,元素会显示,当参数为false时,元素会隐藏。 Knockout visible 绑定的语法: data-…

    css 2023年6月10日
    00
  • JavaScript知识点总结之如何提高性能

    下面我来详细讲解一下“JavaScript知识点总结之如何提高性能”的完整攻略。 前言 在编写JavaScript代码时,我们经常会遇到一些性能问题,例如代码运行缓慢、浏览器崩溃等。这时,我们需要优化代码的性能,提高代码的执行效率。以下是一些优化代码性能的技巧。 提高代码性能的技巧 1. 使用变量缓存 在JavaScript中,每次访问一个变量或对象的属性时…

    css 2023年6月11日
    00
  • CSS属性探秘系列(五):min-width

    下面是关于 CSS 属性 min-width 的完整攻略: 一、什么是 min-width min-width 是 CSS 中用来设置最小宽度的一个属性。它的作用是当元素的宽度小于指定的最小宽度时,自动扩展到指定的最小宽度。同时,若元素的宽度大于最小宽度,则不会对其做任何改变。 二、min-width 的语法 min-width 的语法很简单,只需要设置具体…

    css 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部