记录基于Vue.js的移动端Tree树形组件

目录

一、Liquor Tree

入门 :

Development

Component Options 组件选项

Structure 结构

二、vue-treeselect

Introduction 介绍

Getting Started 入门


    Vue 树形选择器( Vue tree select )组件在搭建 Vue 的 app 中特别常用,Vue tree select 除了简单的树形结构外,还有非常多样的功能来配合不同场景的使用。比如搜索过滤,前端添加删除树枝,前端编辑修改子树名,拖拽排序,对用户操作事件记录等。本文记录了我自己使用多年最好用的 2 款 Vue tree select 组件,每一款都经过我实际测试,推荐给大家。


一、Liquor Tree

酒树 (Liquor Tree)

    Liquor Tree 是一款轻量级树形选择器,对移动端友好,可拖放,支持键盘快捷键,每个操作动作都有事件记录,与 Vue 高度整合。Liquor Tree 代码简洁,扩展性强,可根据你的应用场景按需定制。

    A Vue tree component that allows you to present hierarchically organized data in a nice and logical manner.

    Vue 树组件,可让您以美观和逻辑的方式呈现层次结构的数据。

    supports mobile, and has a variety of response events. Flexible configuration options, and support for keyboard navigation.

    支持移动,并具有各种响应事件。 灵活的配置选项,并支持键盘导航。

    View demo    查看演示    Documentation

github 地址 :

GitHub - amsik/liquor-tree: Tree component based on Vue.js


Vue 官方地址 :

Liquor Tree

Liquor-Tree

产品特点 :

  • 拖放 移动友好
  • 每个动作的事件
  • 灵活的配置
  • 每页任意数量的实例
  • 多选
  • 键盘导航
  • 过滤
  • 分类
  • 与 Vuex 集成

入门 :

安装 :

Npm:

$ npm install liquor-tree

Yarn:

$ yarn add liquor-tree

要在自己的计算机上运行该演示,请执行以下操作:

克隆此存储库

  • npm install ( npm安装 )
  • npm run build ( npm运行构建 )
  • npm run storybook
  • 访问 http://localhost:9001/

这里有很多例子供您参考。 所有来源都位于 liquor-tree/docs/storybook/stories


它必须安装到 VueJS 实例中。请查看官方文档,了解如何使用 VueJS 组件 components

(当然,如果需要的话)。
您不需要关心样式,它们会自动附加到文档中。
当与模块系统一起使用时,有三种方法可以注册组件(可能更多…我不知道)。
好了,下面这是我们的方式:

import Vue from 'vue'
import LiquorTree from 'liquor-tree'

// global registration
Vue.use(LiquorTree) // 第一种

// or
Vue.component(LiquorTree.name, LiquorTree) // 第二种

// or
import LiquorTree from 'liquor-tree'

// local registration
export default {
  name: 'your-awesome-component',
  components: {
    [LiquorTree.name]: LiquorTree // 第三种
  },
  ...
}

要注册库,您可以在我上面提到的 3 种方法之间进行选择。

当直接在浏览器中使用时,您可以通过CND包含 liquor-tree(这是库的最新版本): 

<script src="https://cdn.jsdelivr.net/npm/liquor-tree/dist/liquor-tree.umd.js"></script>

Usage 用法

  <!-- Vue Component -->
  <template>
    <tree
        :data="items"
        :options="options"
        ref="tree"
    />
  </template>

  <script>
    import Vue from 'vue'
    import LiquorTree from 'liquor-tree'

    Vue.use(LiquorTree)

    export default {
      ...
      data() {
        return {
          items: [
            {text: 'Item 1'},
            {text: 'Item 2'},
            {text: 'Item 3', children: [
              {text: 'Item 3.1'},
              {text: 'Item 3.2'}
            ]},
      {
        text: '园区其他机构',
        children: [
          {
            text: '园区其他机构1',
            children: [
              { text: '园区其他机构1.1.1' },
              { text: '园区其他机构1.1.2' },
              { text: '园区其他机构1.1.3' },
            ],
          },
          {
            text: '园区其他机构2',
            children: [
              { text: '园区其他机构2.1.1' },
              { text: '园区其他机构2.1.2' },
              { text: '园区其他机构2.1.3' },
            ],
          },
        ],
      },
          ],
          options: {
            checkbox: true
          }
        }
      }
      ...
    }
  </script>

Development

Check out the package.jsons script section. There are 2 scripts:

  • npm run dev - it will open browser and you can play with code
  • npm run build - it will craete a module file in production mode

Component Options 组件选项

Name 名称Type 类型DefaultDescription 描述
multipleBooleantrue

Allows to select more than one node.

允许选择多个节点

checkboxBooleanfalse

checkbox mode. It shows checkboxes for every node

复选框模式。它显示每个节点的复选框

checkOnSelectBooleanfalse

For checkbox mode only. Node will have checked state when user clicks either text or checkbox

仅用于复选框模式。当用户单击文本或复选框时,节点将处于选中状态

autoCheckChildrenBooleantrue

For checkbox mode only. Children will have the same checked state as their parent.

仅用于复选框模式。子级将具有与其父级相同的选中状态。

parentSelectBooleanfalse

By clicking node which has children it expands node. i.e we have two ways to expand/collapse node: by clicking on arrow and on text

通过单击具有子节点的节点,可以展开节点。即,我们有两种方法来展开/折叠节点:单击箭头和文本

keyboardNavigationBooleantrue

Allows user to navigate tree using keyboard

允许用户使用键盘浏览树

propertyNamesObject-

This options allows the default tree’s structure to be redefined. See example

此选项允许重新定义默认树的结构。见示例

deletionBoolean | Functionfalse

If keyboardNavigation is false this property is ignored. This property defines deletion behaviour. See example

如果 keyboardNavigation 为 false ,则忽略此属性。此属性定义删除行为。见示例

fetchDataObject-See guide
dndObject-See guide   请参阅指南
editingObject-See guide

Structure 结构

The component has only two props: data and options. 该组件只有两个支柱:数据和选项。

  • property options - This property defines tree behavior.   属性选项 - 此属性定义树行为
  • property data - Array-like object that defines tree nodes. 属性数据 - 定义树节点的类似数组的对象

关于 Liquor Tree 树形组件的介绍就到此为止了,因为此组件未满足业务需求:搜索过滤功能。

再加上官方文档全都是英文的,所以就懒得再继续研究下去了。

因此另辟蹊径,找到了个人认为更加友好、更加优秀的一款 Tree 树形组件。

期间查询到一款应该还不错 :LyTree 树形组件 ( 貌似无搜索过滤 )

链接 🔗 : tree树形组件 - DCloud 插件市场


二、vue-treeselect

@riophae/vue-treeselect

GitHub 地址 🔗 : GitHub - riophae/vue-treeselect: A multi-select component with nested options support for Vue.jsA multi-select component with nested options support for Vue.js - GitHub - riophae/vue-treeselect: A multi-select component with nested options support for Vue.jshttps://github.com/riophae/vue-treeselect

Vue-TreeSelect 官网 🔗 :Vue-TreeselectA multi-select component with nested options support for Vue.jshttps://vue-treeselect.js.org/

A multi-select component with nested options support for Vue.js

一个支持 Vue.js 的嵌套选项的多选组件


Introduction 介绍

vue-treeselect is a multi-select component with nested options support for Vue.js.

treeselecte 是一个具有嵌套选项的多选择组件,支持 Vue.js。

  • Single & multiple select with nested options support ( 支持嵌套选项的单个和多个选项 )
  • Fuzzy matching ( 模糊匹配 )
  • Async searching ( 异步搜索 )
  • Delayed loading ( load data of deep level options only when needed )
  • ( 支持嵌套选项的单个和多个选择 )
  • Keyboard support ( navigate using Arrow Up & Arrow Down keys, select option using Enter key, etc. ) ( 支持嵌套选项的单个和多个选择,使用回车键等 )
  • Rich options & highly customizable ( 丰富的选项和高度可定制的 )
  • Supports a wide range of browsers ( 支持多种浏览器 )

Requires Vue 2.2+ ( 必须 Vue 2.2+ )

Getting Started 入门

It's recommended to install vue-treeselect via npm, and build your app using a bundler like webpack.

建议通过 npm 安装 vue-treeselect ,并使用类似 bundler 的 webpack 构建您的应用程序。

npm install --save @riophae/vue-treeselect

This example shows how to integrate vue-treeselect with your Vue SFCs.

这个示例展示了如何将 Vue 树选择与 Vue SFC 集成。

<!-- Vue SFC -->
<template>
  <div id="app">
    <treeselect v-model="value" :multiple="true" :options="options" />
  </div>
</template>

<script>
  // import the component
  import Treeselect from '@riophae/vue-treeselect'
  // import the styles
  import '@riophae/vue-treeselect/dist/vue-treeselect.css'

  export default {
    // register the component
    components: { Treeselect },
    data() {
      return {
        // define the default value
        value: null,
        // define options
        options: [ {
          id: 'a',
          label: 'a',
          children: [ {
            id: 'aa',
            label: 'aa',
          }, {
            id: 'ab',
            label: 'ab',
          } ],
        }, {
          id: 'b',
          label: 'b',
        }, {
          id: 'c',
          label: 'c',
        } ],
      }
    },
  }
</script>

If you just don't want to use webpack or any other bundlers, you can simply include the standalone UMD build in your page. In this way, make sure Vue as a dependency is included before vue-treeselect.

如果你只是不想使用 webpack 或任何其他捆绑器,你可以简单地在你的页面中包括独立的UMD 构建。通过这种方式,确保在 Vue 树选择之前包含 Vue 作为依赖项。

<html>
  <head>
    <!-- include Vue 2.x -->
    <script src="https://cdn.jsdelivr.net/npm/vue@^2"></script>
    <!-- include vue-treeselect & its styles. you can change the version tag to better suit your needs. -->
    <script src="https://cdn.jsdelivr.net/npm/@riophae/vue-treeselect@^0.4.0/dist/vue-treeselect.umd.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@riophae/vue-treeselect@^0.4.0/dist/vue-treeselect.min.css">
  </head>
  <body>
    <div id="app">
      <treeselect v-model="value" :multiple="true" :options="options" />
    </div>
  </body>
  <script>
    // register the component
    Vue.component('treeselect', VueTreeselect.Treeselect)

    new Vue({
      el: '#app',
      data: {
        // define the default value
        value: null,
        // define options
        options: [ {
          id: 'a',
          label: 'a',
          children: [ {
            id: 'aa',
            label: 'aa',
          }, {
            id: 'ab',
            label: 'ab',
          } ],
        }, {
          id: 'b',
          label: 'b',
        }, {
          id: 'c',
          label: 'c',
        } ],
      },
    })
  </script>
</html>


 个人实际项目所用 :

通过Treeselect组件的配置属性中添加"alwaysOpen": true 来让搜索栏默认展开下拉。 

API - Props

props: {
  /**
   * 即使有禁用的选定节点,是否允许重置值
   */
  allowClearingDisabled: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 选择/取消选择祖先节点时,是否应选择/取消选中其禁用的后代
   * 和 allowClearingDisabled 一起使用
   */
  allowSelectingDisabledDescendants: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 菜单是否应始终打开
   */
  alwaysOpen: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否将菜单加到body上
   */
  appendToBody: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否启用异步搜索模式
   */
  async: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否自动将组件集中在装载上?
   */
  autoFocus: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 装载时自动加载根选项。当设置为“false”时,打开菜单时将加载根选项。
   */
  autoLoadRootOptions: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 当用户取消选择一个节点时,会自动取消选择其祖先。仅适用于平面模式。
   */
  autoDeselectAncestors: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 当用户取消选择节点时,会自动取消选择其子节点。仅适用于平面模式。
   */
  autoDeselectDescendants: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 当用户选择一个节点时,会自动选择其祖先。仅适用于平面模式。
   */
  autoSelectAncestors: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 当用户选择一个节点时,会自动选择其子节点。仅适用于平面模式。
   */
  autoSelectDescendants: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 如果没有文本输入,按退格键是否删除最后一项。
   */
  backspaceRemoves: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 在清除所有输入字段之前进行处理的函数。
   * 返回“false”以防止清除值
   * @type {function(): (boolean|Promise<boolean>)}
   */
  beforeClearAll: {
    type: Function,
    default: constant(true),
  },
 
  /**
   * 在叶节点之前显示分支节点?
   */
  branchNodesFirst: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否应该缓存每个搜索请求的结果?
   */
  cacheOptions: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 是否显示重置值的“×”按钮?
   */
  clearable: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 清楚文本,multiple为true时
   */
  clearAllText: {
    type: String,
    default: 'Clear all',
  },
 
  /**
   * 选择后是否清除搜索输入。
   * 仅当“multiple”为“true”时使用。
   * 对于单选模式,无论道具值如何,它总是**在选择一个选项后清除输入。
   */
  clearOnSelect: {
    type: Boolean,
    default: false,
  },
 
  /**
   * “×”按钮的标题。
   */
  clearValueText: {
    type: String,
    default: 'Clear value',
  },
 
  /**
   * 选择选项后是否关闭菜单?
   * 仅当“multiple”为“true”时使用。
   */
  closeOnSelect: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 加载时应自动展开多少级别的分支节点。
   * 设置Infinity以使所有分支节点在默认情况下展开。
   */
  defaultExpandLevel: {
    type: Number,
    default: 0,
  },
 
  /**
   * 在用户开始搜索之前要显示的默认选项集。用于异步搜索模式。
   * 当设置为“true”时,将自动加载作为空字符串的搜索查询结果。
   * @type {boolean|node[]}
   */
  defaultOptions: {
    default: false,
  },
 
  /**
   * 如果没有文本输入,按delete键是否删除最后一项。
   */
  deleteRemoves: {
    type: Boolean,
    default: true,
  },
 
  /**
   * 用于连接隐藏字段值的多个值的分隔符。
   */
  delimiter: {
    type: String,
    default: ',',
  },
 
  /**
   * 仅显示与搜索值直接匹配的节点,不包括其祖先。
   *
   * @type {Object}
   */
  flattenSearchResults: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否阻止选择分支节点?
   */
  disableBranchNodes: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 禁用控制?
   */
  disabled: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 是否禁用模糊匹配功能?
   */
  disableFuzzyMatching: {
    type: Boolean,
    default: false,
  },
 
  /**
   *是否启用平面模式。非平面模式(默认)是指: 
   *   - 每当检查分支节点时,它的所有子节点也将被检查
   *   - 每当一个分支节点检查了所有子节点时,该分支节点本身也会被检查
   * 设置“true”以禁用此机制
   */
  flat: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 将以所有事件作为最后一个参数进行传递。
   * 有助于识别事件的起源。
  */
  instanceId: {
    // Add two trailing "$" to distinguish from explictly specified ids.
    default: () => `${instanceId++}$$`,
    type: [String, Number],
  },
 
  /**
   * Joins multiple values into a single form field with the `delimiter` (legacy mode).
   * 使用“分隔符”将多个值合并到一个表单字段中(传统模式)。
  */
  joinValues: {
    type: Boolean,
    default: false,
  },
 
  /**
   * 限制所选选项的显示。
   * 其余部分将隐藏在limitText字符串中。
   */
  limit: {
    type: Number,
    default: Infinity,
  },
 
  /**
   * Function that processes the message shown when selected elements pass the defined limit.
   * @type {function(number): string}
   */
  limitText: {
    type: Function,
    default: function limitTextDefault(count) { // eslint-disable-line func-name-matching
      return `and ${count} more`
    },
  },
 
  /**
   * Text displayed when loading options.
   */
  loadingText: {
    type: String,
    default: 'Loading...',
  },
 
  /**
   * Used for dynamically loading options.
   * @type {function({action: string, callback: (function((Error|string)=): void), parentNode: node=, instanceId}): void}
   */
  loadOptions: {
    type: Function,
  },
 
  /**
   * Which node properties to filter on.
   */
  matchKeys: {
    type: Array,
    default: constant(['label']),
  },
 
  /**
   * Sets `maxHeight` style value of the menu.
   */
  maxHeight: {
    type: Number,
    default: 300,
  },
 
  /**
   * Set `true` to allow selecting multiple options (a.k.a., multi-select mode).
   */
  multiple: {
    type: Boolean,
    default: false,
  },
 
  /**
   * Generates a hidden <input /> tag with this field name for html forms.
   */
  name: {
    type: String,
  },
 
  /**
   * Text displayed when a branch node has no children.
   */
  noChildrenText: {
    type: String,
    default: 'No sub-options.',
  },
 
  /**
   * Text displayed when there are no available options.
   */
  noOptionsText: {
    type: String,
    default: 'No options available.',
  },
 
  /**
   * Text displayed when there are no matching search results.
   */
  noResultsText: {
    type: String,
    default: 'No results found...',
  },
 
  /**
   * Used for normalizing source data.
   * @type {function(node, instanceId): node}
   */
  normalizer: {
    type: Function,
    default: identity,
  },
 
  /**
   * By default (`auto`), the menu will open below the control. If there is not
   * enough space, vue-treeselect will automatically flip the menu.
   * You can use one of other four options to force the menu to be always opened
   * to specified direction.
   * Acceptable values:
   *   - `"auto"`
   *   - `"below"`
   *   - `"bottom"`
   *   - `"above"`
   *   - `"top"`
   */
  openDirection: {
    type: String,
    default: 'auto',
    validator(value) {
      const acceptableValues = ['auto', 'top', 'bottom', 'above', 'below']
      return includes(acceptableValues, value)
    },
  },
 
  /**
   * Whether to automatically open the menu when the control is clicked.
   */
  openOnClick: {
    type: Boolean,
    default: true,
  },
 
  /**
   * Whether to automatically open the menu when the control is focused.
   */
  openOnFocus: {
    type: Boolean,
    default: false,
  },
 
  /**
   * Array of available options.
   * @type {node[]}
   */
  options: {
    type: Array,
  },
 
  /**
   * Field placeholder, displayed when there's no value.
   */
  placeholder: {
    type: String,
    default: 'Select...',
  },
 
  /**
   * Applies HTML5 required attribute when needed.
   */
  required: {
    type: Boolean,
    default: false,
  },
 
  /**
   * Text displayed asking user whether to retry loading children options.
   */
  retryText: {
    type: String,
    default: 'Retry?',
  },
 
  /**
   * Title for the retry button.
   */
  retryTitle: {
    type: String,
    default: 'Click to retry',
  },
 
  /**
   * Enable searching feature?
   */
  searchable: {
    type: Boolean,
    default: true,
  },
 
  /**
   * Search in ancestor nodes too.
   */
  searchNested: {
    type: Boolean,
    default: false,
  },
 
  /**
   * Text tip to prompt for async search.
   */
  searchPromptText: {
    type: String,
    default: 'Type to search...',
  },
 
  /**
   * Whether to show a children count next to the label of each branch node.
   */
  showCount: {
    type: Boolean,
    default: false,
  },
 
  /**
   * Used in conjunction with `showCount` to specify which type of count number should be displayed.
   * Acceptable values:
   *   - "ALL_CHILDREN"
   *   - "ALL_DESCENDANTS"
   *   - "LEAF_CHILDREN"
   *   - "LEAF_DESCENDANTS"
   */
  showCountOf: {
    type: String,
    default: ALL_CHILDREN,
    validator(value) {
      const acceptableValues = [ALL_CHILDREN, ALL_DESCENDANTS, LEAF_CHILDREN, LEAF_DESCENDANTS]
      return includes(acceptableValues, value)
    },
  },
 
  /**
   * Whether to show children count when searching.
   * Fallbacks to the value of `showCount` when not specified.
   * @type {boolean}
   */
  showCountOnSearch: null,
 
  /**
   * In which order the selected options should be displayed in trigger & sorted in `value` array.
   * Used for multi-select mode only.
   * Acceptable values:
   *   - "ORDER_SELECTED"
   *   - "LEVEL"
   *   - "INDEX"
   */
  sortValueBy: {
    type: String,
    default: ORDER_SELECTED,
    validator(value) {
      const acceptableValues = [ORDER_SELECTED, LEVEL, INDEX]
      return includes(acceptableValues, value)
    },
  },
 
  /**
   * Tab index of the control.
   */
  tabIndex: {
    type: Number,
    default: 0,
  },
 
  /**
   * The value of the control.
   * Should be `id` or `node` object for single-select mode, or an array of `id` or `node` object for multi-select mode.
   * Its format depends on the `valueFormat` prop.
   * For most cases, just use `v-model` instead.
   * @type {?Array}
   */
  value: null,
 
  /**
   * Which kind of nodes should be included in the `value` array in multi-select mode.
   * Acceptable values:
   *   - "ALL" - Any node that is checked will be included in the `value` array
   *   - "BRANCH_PRIORITY" (default) - If a branch node is checked, all its descendants will be excluded in the `value` array
   *   - "LEAF_PRIORITY" - If a branch node is checked, this node itself and its branch descendants will be excluded from the `value` array but its leaf descendants will be included
   *   - "ALL_WITH_INDETERMINATE" - Any node that is checked will be included in the `value` array, plus indeterminate nodes
   */
  valueConsistsOf: {
    type: String,
    default: BRANCH_PRIORITY,
    validator(value) {
      const acceptableValues = [ALL, BRANCH_PRIORITY, LEAF_PRIORITY, ALL_WITH_INDETERMINATE]
      return includes(acceptableValues, value)
    },
  },
 
  /**
   * Format of `value` prop.
   * Note that, when set to `"object"`, only `id` & `label` properties are required in each `node` object in `value` prop.
   * Acceptable values:
   *   - "id"
   *   - "object"
   */
  valueFormat: {
    type: String,
    default: 'id',
  },
 
  /**
   * z-index of the menu.
   */
  zIndex: {
    type: [Number, String],
    default: 999,
  }
}

项目代码 : 

<!-- Vue SFC -->
<template>
	<div id="app">
		<Treeselect
			v-model="selectedNodes"
			:maxHeight="400"
			:multiple="true"
			:always-open="true"
			:options="options"
			:normalizer="normalize"
			valueFormat="object"
			placeholder="请输入搜索关键字"
			noResultsText="未查询到您的搜索"
		/>
		<div class="tree-footer">
			<van-button round type="info" @click="addInstitution"
				>添加机构</van-button
			>
			<van-button round @click="closeAddInstitution">取消</van-button>
		</div>
	</div>
</template>

<script>
// import the component
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';

export default {
	// register the component
	components: { Treeselect },
	data() {
		return {
			// define the default selectedNodes
			selectedNodes: null,
			// define options
			options: [
				{
					id: '研发中心本部',
					label: '研发中心本部',
					children: [
						{
							id: '中心办公室',
							label: '中心办公室',
							children: [
								{ id: '张三', label: '张三' },
								{ id: '李四', label: '李四' },
								{ id: '王一一', label: '王一一' },
							],
						},
						{
							id: '中心技术二部',
							label: '中心技术二部',
							children: [
								{ id: '赵六', label: '赵六' },
								{ id: '七七', label: '七七' },
								{ id: '八八', label: '八八' },
							],
						},
					],
				},
				{
					id: '资源管理中心',
					label: '资源管理中心',
					children: [
						{
							id: '外部资源部1',
							label: '外部资源部1',
							children: [
								{
									id: '外部资源部1.1.1',
									label: '外部资源部1.1.1',
								},
								{
									id: '外部资源部1.1.2',
									label: '外部资源部1.1.2',
								},
								{
									id: '外部资源部1.1.3',
									label: '外部资源部1.1.3',
								},
							],
						},
						{
							id: '外部资源部2',
							label: '外部资源部2',
							children: [
								{
									id: '外部资源部2.1.1',
									label: '外部资源部2.1.1',
								},
								{
									id: '外部资源部2.1.2',
									label: '外部资源部2.1.2',
								},
								{
									id: '外部资源部2.1.3',
									label: '外部资源部2.1.3',
								},
							],
						},
					],
				},
				{
					id: '园区其他机构',
					label: '园区其他机构',
					children: [
						{
							id: '园区其他机构1',
							label: '园区其他机构1',
							children: [
								{
									id: '园区其他机构1.1.1',
									label: '园区其他机构1.1.1',
								},
								{
									id: '园区其他机构1.1.2',
									label: '园区其他机构1.1.2',
								},
								{
									id: '园区其他机构1.1.3',
									label: '园区其他机构1.1.3',
								},
							],
						},
						{
							id: '园区其他机构2',
							label: '园区其他机构2',
							children: [
								{
									id: '园区其他机构2.1.1',
									label: '园区其他机构2.1.1',
								},
								{
									id: '园区其他机构2.1.2',
									label: '园区其他机构2.1.2',
								},
								{
									id: '园区其他机构2.1.3',
									label: '园区其他机构2.1.3',
								},
							],
						},
					],
				},
			],
		};
	},
	methods: {
		// 自定义密钥名称
		normalize(options) {
			return {
				id: options.id,
				label: options.shortName,
				children: options.branchs,
			};
		},
		addInstitution() {
			if (!this.selectedNodes.length) {
				Notify('请先选择机构');
				return;
			}
			this.$emit('addInstitution', this.selectedNodes);
		},
		closeAddInstitution() {
			this.$emit('closeAddInstitution');
		},
	},
};
</script>

未完待续 。。。


推荐文章 🔗 : VueTreeselect_vue-treeselect_捡垃圾的小女孩的博客 

https://www.cnblogs.com/webSnow/p/16043117.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/29081.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java|golang】2611. 老鼠和奶酪

有两只老鼠和 n 块不同类型的奶酪&#xff0c;每块奶酪都只能被其中一只老鼠吃掉。 下标为 i 处的奶酪被吃掉的得分为&#xff1a; 如果第一只老鼠吃掉&#xff0c;则得分为 reward1[i] 。 如果第二只老鼠吃掉&#xff0c;则得分为 reward2[i] 。 给你一个正整数数组 reward1…

【TypeScript】枚举类型和泛型的详细介绍

目录 TypeScript枚举类型 TypeScript泛型介绍 &#x1f3b2;泛型的基本使用 &#x1f3b2;泛型接口的使用 &#x1f3b2;泛型类的使用 &#x1f3b2;泛型的类型约束 枚举类型 枚举类型是为数不多的TypeScript特有的特性之一, JavaScript是没有的&#xff1a; 枚举其实就…

【FPGA零基础学习之旅#8】阻塞赋值与非阻塞赋值讲解

&#x1f389;欢迎来到FPGA专栏~阻塞赋值与非阻塞赋值 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家…

解决elementUI弹出框关闭后再打开el-select下拉框无法选中的问题

文章目录 一、问题描述&#xff1a;二、问题解决 一、问题描述&#xff1a; 使用的前端UI框架为elementUI。 el-select组件在一个弹框中&#xff0c;打开该弹框&#xff0c;el-select可以正常选中&#xff0c;但是保存弹框中的表单信息关闭弹框后&#xff0c;再打开弹框&…

Spark大数据处理讲课笔记4.1 Spark SQL概述、数据帧与数据集

零、本讲学习目标 了解Spark SQL的基本概念掌握DataFrame的基本概念掌握Dataset的基本概念会基于DataFrame执行SQL查询 在很多情况下&#xff0c;开发工程师并不了解Scala语言&#xff0c;也不了解Spark常用API&#xff0c;但又非常想要使用Spark框架提供的强大的数据分析能力…

物联网Lora模块从入门到精通(二) LED灯泡闪烁与呼吸灯

目录 一、前言 二、实践与代码 1.电亮LED1 2.熄灭LED1 3.翻转LED电平 4.LED1与LED2交替闪烁 5.LED1呼吸灯 三、程序代码 一、前言 本篇内容属于新大陆物联网Lora模块开发&#xff0c;使用给定的Lora基础例程&#xff0c;并在其基础上开发完成&#xff0c;并可为其他版本的Lo…

亚马逊云科技Serverless构建的实时数仓解决方案,助力猎豹降低30%成本

也许你也听过这样一句话&#xff1a;“21世纪什么最贵&#xff1f;人才&#xff01;”当数字经济全面席卷而来&#xff0c;这个问题的答案不可置否地变为了“数据”。通过数据分析获取近乎实时的洞察&#xff0c;以驱动业务的全流程&#xff0c;是企业数字化转型的必经之路。借…

Linux操作系统学习——启动

概要 Linux操作系统内核是服务端学习的根基&#xff0c;也是提高编程能力、源码阅读能力和进阶知识学习能力的重要部分&#xff0c;本文开始将记录Linux操作系统中的各个部分源码学习历程。 1. 理解代码的组织结构 以Linux源码举例&#xff0c;首先你得知道操作系统分为哪几个部…

【SpringCloud入门】-- 初识Eureka注册中心

目录 1.SpringCloudEureka简介 2.什么是CAP原则&#xff1f; 3.注册中心的概念&#xff1f; 4.SpringCloud其他注册中心 5.搭建Eureka注册中心 6.eureka的配置(主要是server&#xff0c;instance&#xff0c;client) 7.eureka集群概念 8.eureka集群搭建 1.SpringCloudE…

基于R语言的物种气候生态位动态量化与分布特征模拟

目录 专题一 引言 专题二 数据获取与处理方法 专题三 组合物种分布模型&#xff08;Ensemble Species Distribution Model&#xff09;的原理与使用 专题四 拓展研究 专题五 结果分析与论文写作 专题六 案例分析 专题七 总结和展望 利用R语言进行物种气候生态位动态量化…

【蓝桥杯算法题】用java遍写税收计算

【蓝桥杯算法题】用java遍写税收计算 题目&#xff1a;劳务报酬税收计算&#xff1a;输入 m &#xff0c;输出税后收入。如果 m <800&#xff0c;不扣税&#xff0c; 如果800< m <4000&#xff0e;则 m 减去800后的金额扣除20&#xff05;所得税。如果 m >4000&…

【计算机网络详解】——运输层(学习笔记)

&#x1f4d6; 前言&#xff1a;两台主机的通信&#xff0c;实际上两台主机中的应用进程进行通信&#xff0c;而在一台计算机中&#xff0c;用不同的端口号标识不同的应用进程。本节将介绍传输层的相关内容&#xff0c;包括端口号的分配方法、端口号的复用与分用、以及传输层的…

编译tolua——3、以pbc为例子,添加第三方库

目录 1、编译工具和环境说明 2、基础编译tolua 3、以pbc为例子&#xff0c;添加第三方库 4、更新luaJit 大家好&#xff0c;我是阿赵。 之前分享过怎样正常编译基础版本的tolua。这次用添加pbc为例&#xff0c;看看怎样往tolua里面添加其他的第三方库。知道了方法之后&#xf…

本地项目托管到 Gitee

本地项目托管到 Gitee 1、创建远程仓库2、Git Bash Here第一步&#xff1a;初始化本地仓库 git init第二步&#xff1a;建立链接git remote add origin xxx第三步&#xff1a;将远程仓库中的文件推送至本地仓库中git pull --rebase origin master第四步&#xff1a;将本地项目放…

【利用AI让知识体系化】简要了解网络七层协议

文章目录 一、前言引言目的和意义 二、网络七层协议简介OSI参考模型七层协议分层结构和各层协议简介 三、物理层 - Layer 1物理层概述物理层的作用物理层标准和协议 四、数据链路层 - Layer 2数据链路层概述常见的协议 五、网络层 - Layer 3网络层概述网络层的作用IP地址的作用…

cool-admin框架后端使用-node版本,线上宝塔部署

版本6.x 宝塔新建一个文件夹和创建好数据库&#xff0c;记录账号和密码&#xff0c;自行创建&#xff0c;不做说明 特别注意&#xff0c;如果用宝塔node管理那里运行&#xff0c;如果按照到有pm2的&#xff0c;要先卸载&#xff0c;不可以共存&#xff0c;会有冲突 cool-vue前端…

爬虫数据采集需要什么样的代理ip以及遇到的反爬措施

随着互联网的快速发展&#xff0c;数据已经成为许多行业中的重要资源。网络爬虫作为一种数据采集工具&#xff0c;在许多领域中得到了广泛应用。但是现在很多网站都有非常多的限制&#xff0c;所以在爬取数据的时候&#xff0c;还需要借助代理ip来助力&#xff0c;才能更好的完…

谁说不可兼得,用scrcpy实现手机免流播放bilibili投屏电脑

目前的手机大额流量卡都是支持设备免流的&#xff0c;但是如何将这个流量用在其他设备&#xff0c;就相当麻烦。于是我查找了些相关Android投屏技术资料&#xff0c;发现了一个简单的USB投屏工具——scrcpy。 安装说明 Office&#xff1a;https://github.com/Genymobile/scrcp…

深度学习之卷积神经网络(CNN)

大家好&#xff0c;我是带我去滑雪&#xff01; 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种基于深度学习的前馈神经网络&#xff0c;主要用于图像和视频识别、分类、分割和标注等计算机视觉任务。它主要由卷积层、池化层、全连接…

手机技巧:安卓微信 8.0.38 内测版本功能一览

2023年6月14号安卓版本的微信8.0.38又开始内测了&#xff0c;今天就赶紧下载体验一下&#xff0c;下面就来给大家一一介绍&#xff0c;本次安卓微信内测版本功能更新&#xff0c;感兴趣的朋友可以文末下载体验一下&#xff01; 首先看一下官方的更新内容&#xff1a; 本次更新…