這個(gè)是在若依框架無(wú)意中發(fā)現(xiàn)的一個(gè)下拉樹(shù)通用組件。@riophae/vue-treeselect 是一個(gè)基于 Vue.js 的樹(shù)形選擇器組件,可以用于選擇樹(shù)形結(jié)構(gòu)的數(shù)據(jù)。它支持多選、搜索、異步加載等功能,可以自定義選項(xiàng)的樣式和模板。該組件易于使用和擴(kuò)展,適用于各種類型的項(xiàng)目。
npm:https://www.npmjs.com/package/@riophae/vue-treeselect?
首先安裝:?
?使用自己習(xí)慣使用的包管理器安裝就可以了
pnpm add @riophae/vue-treeselect
引入注冊(cè):?
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
components: { Treeselect }
}
基本使用:
<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>
里面可配置的屬性很多,下面是在源碼中看到的:?
部分注釋百度翻譯成中文了,但太多了,懶得挨個(gè)翻譯了,直接看也大概知道啥意思?
props: {
/**
* 即使有禁用的選定節(jié)點(diǎn),是否允許重置值
*/
allowClearingDisabled: {
type: Boolean,
default: false,
},
/**
* 選擇/取消選擇祖先節(jié)點(diǎn)時(shí),是否應(yīng)選擇/取消選中其禁用的后代
* 和 allowClearingDisabled 一起使用
*/
allowSelectingDisabledDescendants: {
type: Boolean,
default: false,
},
/**
* 菜單是否應(yīng)始終打開(kāi)
*/
alwaysOpen: {
type: Boolean,
default: false,
},
/**
* 是否將菜單加到body上
*/
appendToBody: {
type: Boolean,
default: false,
},
/**
* 是否啟用異步搜索模式
*/
async: {
type: Boolean,
default: false,
},
/**
* 是否自動(dòng)將組件集中在裝載上?
*/
autoFocus: {
type: Boolean,
default: false,
},
/**
* 裝載時(shí)自動(dòng)加載根選項(xiàng)。當(dāng)設(shè)置為“false”時(shí),打開(kāi)菜單時(shí)將加載根選項(xiàng)。
*/
autoLoadRootOptions: {
type: Boolean,
default: true,
},
/**
* 當(dāng)用戶取消選擇一個(gè)節(jié)點(diǎn)時(shí),會(huì)自動(dòng)取消選擇其祖先。僅適用于平面模式。
*/
autoDeselectAncestors: {
type: Boolean,
default: false,
},
/**
* 當(dāng)用戶取消選擇節(jié)點(diǎn)時(shí),會(huì)自動(dòng)取消選擇其子節(jié)點(diǎn)。僅適用于平面模式。
*/
autoDeselectDescendants: {
type: Boolean,
default: false,
},
/**
* 當(dāng)用戶選擇一個(gè)節(jié)點(diǎn)時(shí),會(huì)自動(dòng)選擇其祖先。僅適用于平面模式。
*/
autoSelectAncestors: {
type: Boolean,
default: false,
},
/**
* 當(dāng)用戶選擇一個(gè)節(jié)點(diǎn)時(shí),會(huì)自動(dòng)選擇其子節(jié)點(diǎn)。僅適用于平面模式。
*/
autoSelectDescendants: {
type: Boolean,
default: false,
},
/**
* 如果沒(méi)有文本輸入,按退格鍵是否刪除最后一項(xiàng)。
*/
backspaceRemoves: {
type: Boolean,
default: true,
},
/**
* 在清除所有輸入字段之前進(jìn)行處理的函數(shù)。
* 返回“false”以防止清除值
* @type {function(): (boolean|Promise<boolean>)}
*/
beforeClearAll: {
type: Function,
default: constant(true),
},
/**
* 在葉節(jié)點(diǎn)之前顯示分支節(jié)點(diǎn)?
*/
branchNodesFirst: {
type: Boolean,
default: false,
},
/**
* 是否應(yīng)該緩存每個(gè)搜索請(qǐng)求的結(jié)果?
*/
cacheOptions: {
type: Boolean,
default: true,
},
/**
* 是否顯示重置值的“×”按鈕?
*/
clearable: {
type: Boolean,
default: true,
},
/**
* 清楚文本,multiple為true時(shí)
*/
clearAllText: {
type: String,
default: 'Clear all',
},
/**
* 選擇后是否清除搜索輸入。
* 僅當(dāng)“multiple”為“true”時(shí)使用。
* 對(duì)于單選模式,無(wú)論道具值如何,它總是**在選擇一個(gè)選項(xiàng)后清除輸入。
*/
clearOnSelect: {
type: Boolean,
default: false,
},
/**
* “×”按鈕的標(biāo)題。
*/
clearValueText: {
type: String,
default: 'Clear value',
},
/**
* 選擇選項(xiàng)后是否關(guān)閉菜單?
* 僅當(dāng)“multiple”為“true”時(shí)使用。
*/
closeOnSelect: {
type: Boolean,
default: true,
},
/**
* 加載時(shí)應(yīng)自動(dòng)展開(kāi)多少級(jí)別的分支節(jié)點(diǎn)。
* 設(shè)置Infinity以使所有分支節(jié)點(diǎn)在默認(rèn)情況下展開(kāi)。
*/
defaultExpandLevel: {
type: Number,
default: 0,
},
/**
* 在用戶開(kāi)始搜索之前要顯示的默認(rèn)選項(xiàng)集。用于異步搜索模式。
* 當(dāng)設(shè)置為“true”時(shí),將自動(dòng)加載作為空字符串的搜索查詢結(jié)果。
* @type {boolean|node[]}
*/
defaultOptions: {
default: false,
},
/**
* 如果沒(méi)有文本輸入,按delete鍵是否刪除最后一項(xiàng)。
*/
deleteRemoves: {
type: Boolean,
default: true,
},
/**
* 用于連接隱藏字段值的多個(gè)值的分隔符。
*/
delimiter: {
type: String,
default: ',',
},
/**
* 僅顯示與搜索值直接匹配的節(jié)點(diǎn),不包括其祖先。
*
* @type {Object}
*/
flattenSearchResults: {
type: Boolean,
default: false,
},
/**
* 是否阻止選擇分支節(jié)點(diǎn)?
*/
disableBranchNodes: {
type: Boolean,
default: false,
},
/**
* 禁用控制?
*/
disabled: {
type: Boolean,
default: false,
},
/**
* 是否禁用模糊匹配功能?
*/
disableFuzzyMatching: {
type: Boolean,
default: false,
},
/**
*是否啟用平面模式。非平面模式(默認(rèn))是指:
* - 每當(dāng)檢查分支節(jié)點(diǎn)時(shí),它的所有子節(jié)點(diǎn)也將被檢查
* - 每當(dāng)一個(gè)分支節(jié)點(diǎn)檢查了所有子節(jié)點(diǎn)時(shí),該分支節(jié)點(diǎn)本身也會(huì)被檢查
* 設(shè)置“true”以禁用此機(jī)制
*/
flat: {
type: Boolean,
default: false,
},
/**
* 將以所有事件作為最后一個(gè)參數(shù)進(jìn)行傳遞。
* 有助于識(shí)別事件的起源。
*/
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).
* 使用“分隔符”將多個(gè)值合并到一個(gè)表單字段中(傳統(tǒng)模式)。
*/
joinValues: {
type: Boolean,
default: false,
},
/**
* 限制所選選項(xiàng)的顯示。
* 其余部分將隱藏在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,
}
}
然后我簡(jiǎn)單看了一下好像一共向外暴露了6個(gè)方法如下:
@input // // 選中觸發(fā)(第一次回顯的時(shí)候會(huì)觸發(fā),清除值的時(shí)候會(huì)觸發(fā), value值為undefined) input事件用于v-model雙向綁定組件更新父組件值
@select // 選中觸發(fā)(清除值的時(shí)候不會(huì)觸發(fā))
@deselect // 移除選項(xiàng)時(shí)觸發(fā) 當(dāng)設(shè)置multiple為true時(shí)生效 raw為當(dāng)前移除的對(duì)象
@search-change // 搜索觸發(fā)(輸入框輸入 值改變時(shí))
@open // 展開(kāi)時(shí)觸發(fā)
@close // 關(guān)閉時(shí)觸發(fā)
下面是我測(cè)試的一個(gè)例子,一般的需求應(yīng)該足夠了
字體樣式簡(jiǎn)單調(diào)了一下?
<template>
<div class="main">
<div class="tree">
<Treeselect
v-model="value"
:options="options"
:placeholder="'請(qǐng)選擇人員'"
:normalizer="tenantIdnormalizer"
:multiple="true"
@input="treeSelectInput"
@select="treeSelectChange"
@deselect="treeSelectDeselect"
@search-change="treeSelectSearch"
@open="treeSelectOpen"
@close="treeSelectClose"
/>
</div>
</div>
</template>
<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(){
// 延遲模擬請(qǐng)求數(shù)據(jù)
setTimeout(() => {
this.options = treeData
this.value = [111, 113] // 測(cè)試回顯操作
}, 300)
},
methods:{
// 選中觸發(fā)(第一次回顯的時(shí)候會(huì)觸發(fā),清除值的時(shí)候會(huì)觸發(fā), value值為undefined) input事件用于v-model雙向綁定組件更新父組件值
treeSelectInput(value, instanceId) {
console.log(value, 'input事件')
console.log(this.value, 'this.value -- input') // 這個(gè)不需要 延遲
},
// 選中觸發(fā)(清除值的時(shí)候不會(huì)觸發(fā))
treeSelectChange(raw, instanceId) {
console.log(raw, '當(dāng)前的對(duì)象')
setTimeout(() => { // 如果用到this.value 需要setTimeout延遲一下拿到最新的值
console.log(this.value, 'this.value -- select')
})
},
// 移除選項(xiàng)時(shí)觸發(fā) 當(dāng)設(shè)置multiple為true時(shí)生效 raw為當(dāng)前移除的對(duì)象
treeSelectDeselect(raw, instanceId) {
console.log(raw, 'deselect-->>')
},
// 搜索
treeSelectSearch(searchQuery, instanceId) {
console.log(searchQuery, '當(dāng)前搜索的值')
},
// 展開(kāi)觸發(fā)
treeSelectOpen(instanceId) {
console.log('展開(kāi)了')
},
// 關(guān)閉觸發(fā)
treeSelectClose(value, instanceId) {
console.log(value, '當(dāng)前的value值')
},
// 字段默認(rèn) id label 用于規(guī)范化數(shù)據(jù)源
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>
測(cè)試數(shù)據(jù):?
export default [
{
"title": "系統(tǒng)管理",
"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
}
]
}
]
效果如下:?文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-793459.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-793459.html
到了這里,關(guān)于Vue通用下拉樹(shù)組件@riophae/vue-treeselect的使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!