Vue通用下拉树组件@riophae/vue-treeselect的使用
admin 阅读: 2024-04-02
后台-插件-广告管理-内容页头部广告(手机) |
这个是在若依框架无意中发现的一个下拉树通用组件。@riophae/vue-treeselect 是一个基于 Vue.js 的树形选择器组件,可以用于选择树形结构的数据。它支持多选、搜索、异步加载等功能,可以自定义选项的样式和模板。该组件易于使用和扩展,适用于各种类型的项目。
npm:https://www.npmjs.com/package/@riophae/vue-treeselect
首先安装:
使用自己习惯使用的包管理器安装就可以了
pnpm add @riophae/vue-treeselect引入注册:
- import Treeselect from '@riophae/vue-treeselect'
- import '@riophae/vue-treeselect/dist/vue-treeselect.css'
- export default {
- components: { Treeselect }
- }
基本使用:
- <div id="app">
- <treeselect v-model="value" :multiple="true" :options="options" />
- div>
- <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>
里面可配置的属性很多,下面是在源码中看到的:
部分注释百度翻译成中文了,但太多了,懒得挨个翻译了,直接看也大概知道啥意思
- 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
)} - */
- 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 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,
- }
- }
然后我简单看了一下好像一共向外暴露了6个方法如下:
- @input // // 选中触发(第一次回显的时候会触发,清除值的时候会触发, value值为undefined) input事件用于v-model双向绑定组件更新父组件值
- @select // 选中触发(清除值的时候不会触发)
- @deselect // 移除选项时触发 当设置multiple为true时生效 raw为当前移除的对象
- @search-change // 搜索触发(输入框输入 值改变时)
- @open // 展开时触发
- @close // 关闭时触发
下面是我测试的一个例子,一般的需求应该足够了
字体样式简单调了一下
- <div class="main">
- <div class="tree">
- <Treeselect
- v-model="value"
- :options="options"
- :placeholder="'请选择人员'"
- :normalizer="tenantIdnormalizer"
- :multiple="true"
- @input="treeSelectInput"
- @select="treeSelectChange"
- @deselect="treeSelectDeselect"
- @search-change="treeSelectSearch"
- @open="treeSelectOpen"
- @close="treeSelectClose"
- />
- div>
- div>
- <script>
- import Treeselect from '@riophae/vue-treeselect'
- import '@riophae/vue-treeselect/dist/vue-treeselect.css'
- import treeData from './data/tree'
- export default {
- data() {
- return {
- value: null,
- options: []
- }
- },
- components: { Treeselect },
- mounted(){
- // 延迟模拟请求数据
- setTimeout(() => {
- this.options = treeData
- this.value = [111, 113] // 测试回显操作
- }, 300)
- },
- methods:{
- // 选中触发(第一次回显的时候会触发,清除值的时候会触发, value值为undefined) input事件用于v-model双向绑定组件更新父组件值
- treeSelectInput(value, instanceId) {
- console.log(value, 'input事件')
- console.log(this.value, 'this.value -- input') // 这个不需要 延迟
- },
- // 选中触发(清除值的时候不会触发)
- treeSelectChange(raw, instanceId) {
- console.log(raw, '当前的对象')
- setTimeout(() => { // 如果用到this.value 需要setTimeout延迟一下拿到最新的值
- console.log(this.value, 'this.value -- select')
- })
- },
- // 移除选项时触发 当设置multiple为true时生效 raw为当前移除的对象
- treeSelectDeselect(raw, instanceId) {
- console.log(raw, 'deselect-->>')
- },
- // 搜索
- treeSelectSearch(searchQuery, instanceId) {
- console.log(searchQuery, '当前搜索的值')
- },
- // 展开触发
- treeSelectOpen(instanceId) {
- console.log('展开了')
- },
- // 关闭触发
- treeSelectClose(value, instanceId) {
- console.log(value, '当前的value值')
- },
- // 字段默认 id label 用于规范化数据源
- tenantIdnormalizer(node, instanceId) {
- if (node.children && !node.children.length) {
- delete node.children
- }
- return {
- id: node.id,
- label: node.title,
- children: node.children
- }
- }
- }
- }
- script>
- <style scoped>
- .main {
- width: 100%;
- height: 100%;
- padding: 60px 0 0 200px;
- }
- .main .tree {
- width: 240px;
- height: 40px;
- }
- ::v-deep .vue-treeselect__label {
- color: #606266;
- }
- style>
测试数据:
- export default [
- {
- "title": "系统管理",
- "parentId": 0,
- "id": 1,
- "children": [
- {
- "title": "菜单管理",
- "parentId": 1,
- "id": 11,
- "children": [
- {
- "title": "菜单新增",
- "parentId": 11,
- "id": 111
- },
- {
- "title": "菜单编辑",
- "parentId": 11,
- "id": 112
- },
- {
- "title": "菜单删除",
- "parentId": 11,
- "id": 113
- }
- ]
- },
- {
- "title": "角色管理",
- "parentId": 1,
- "id": 22,
- "children": [
- {
- "title": "角色编辑",
- "parentId": 22,
- "id": 222
- },
- {
- "title": "角色新增",
- "parentId": 22,
- "id": 221
- },
- {
- "title": "角色删除",
- "parentId": 22,
- "id": 223
- }
- ]
- }
- ]
- },
- {
- "title": "用户管理",
- "parentId": 0,
- "id": 33,
- "children": [
- {
- "title": "用户新增",
- "parentId": 33,
- "id": 331
- },
- {
- "title": "用户编辑",
- "parentId": 33,
- "id": 332
- },
- {
- "title": "用户删除",
- "parentId": 33,
- "id": 333
- }
- ]
- }
- ]
效果如下:
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。
在线投稿:投稿 站长QQ:1888636
后台-插件-广告管理-内容页尾部广告(手机) |