Vue实现无限级树形选择器

下面是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日

相关文章

  • 使用CSS3来制作消息提醒框

    下面我将详细讲解使用CSS3来制作消息提醒框的完整攻略。 准备工作 在开始制作消息提醒框之前,我们需要准备以下工作: 创建一个HTML文件,用于展示我们的消息提醒框。 引入CSS文件,我们将在其中编写消息提醒框的样式。 制作步骤 接下来,我们将按照以下步骤来制作消息提醒框。 步骤一:HTML结构 首先,我们需要在HTML文件中添加一个容器元素,用于容纳消息提…

    css 2023年6月9日
    00
  • newasp中main类

    下面是详细的讲解“newasp中main类”的攻略。 什么是 newasp 中的 main 类? main 类是 newasp 框架中的一个核心类。当我们在 newasp 框架中编写一个应用程序时,会去定义一个 main 类,并在该类中实现一个名为 main 的方法。这个方法是应用程序的入口,框架会直接调用该方法。 在该方法内部,我们可以编写应用程序的业务逻…

    css 2023年6月10日
    00
  • 结合CSS3的新特性来总结垂直居中的实现方法

    垂直居中从来都是前端开发中一个比较棘手的问题,但是随着CSS3新特性的不断推出,我们现在可以使用更简单、更优雅的方式实现垂直居中效果。本文就结合CSS3的新特性来总结一下垂直居中的实现方法。 Flexbox布局 Flexbox布局作为CSS3中新增的一种布局模式,简单且实用。使用Flexbox布局可以很容易地实现水平&垂直居中。 我们先来看一下如何使…

    css 2023年6月9日
    00
  • swiper4实现移动端导航栏tab滑动切换

    实现移动端导航栏tab滑动切换,可以使用Swiper4这个强大的移动端轮播图插件。 下面是实现步骤: 引入Swiper4插件的js和css文件 <link rel="stylesheet" href="https://unpkg.com/swiper/css/swiper.min.css"> <scr…

    css 2023年6月10日
    00
  • div中内容上下居中小结

    下面是“div中内容上下居中小结”的完整攻略。 1. 使用flex布局 使用flex布局是一种简单且通用的方法,可以将容器中的内容上下居中。具体方法如下: .container { display: flex; justify-content: center; align-items: center; } 上述代码会使.container容器中的内容在纵向上…

    css 2023年6月10日
    00
  • 详解DIV+CSS布局的好处和意义

    详解DIV+CSS布局的好处和意义 什么是DIV+CSS布局 DIV+CSS布局是一种网页制作方法,它使用HTML中的 标签来分隔页面结构,使用CSS样式来定义该结构的外观。与传统的表格布局方式相比,DIV+CSS布局更加灵活、语义化,更利于SEO优化。 DIV+CSS布局的好处 灵活性更高:使用DIV+CSS布局的网站结构更加清晰,CSS样式文件和HTML…

    css 2023年6月9日
    00
  • iframe去边框、无边框使用大全(实践经验整理)

    iframe去边框、无边框使用大全(实践经验整理) 去边框 方法一:使用CSS样式去除边框 <iframe src="https://www.example.com" style="border:none;"></iframe> 使用样式border:none可以去除iframe的边框。 方法二…

    css 2023年6月10日
    00
  • css设置Overflow实现隐藏滚动条的同时又可以滚动

    下面是关于如何通过设置CSS的Overflow属性实现隐藏滚动条的同时又可以滚动的详细攻略: 一、背景知识: 我们都知道,Overflow属性决定了一个元素的内容区域超出容器后的表现方式。当Overflow属性的值为”hidden”时,超出容器的部分就会被隐藏掉;当Overflow属性的值为”scroll”或”auto”时,超出容器的部分就会被显示,并出现滚…

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