Мотивация
Я хочу создать дерево меню с панелью поиска для выделения пунктов меню.Я придумал следующую реализацию:
const treeConfig = [
{
label: 'User',
children: [
{
label: 'User group'
},
{
label: 'Permissions'
}
]
},
{
label: 'Tests',
children: [
{
label: 'Unit tests'
},
{
label: 'Visual regression tests'
}
]
},
{
label: 'Other stuff'
}
];
Vue.component('tree', {
template: '#tree',
props: ['nodes'],
data() {
return {
showChildren: true
};
},
methods: {
toggleChildren() {
this.showChildren = !this.showChildren;
}
}
});
const vm = new Vue({
el: '#app',
data: {
quicksearch: ''
},
computed: {
nodes() {
const self = this;
function getTree(nodes) {
return nodes.map((node) => {
node.label_ = node.label;
node.label_ = node.label.replace(new RegExp(self.quicksearch, 'gi'), '<mark>$&</mark>');
if (node.children) {
node.children = getTree(node.children);
}
return node;
});
}
return getTree(treeConfig);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<input type="search" placeholder="Quick search" v-model="quicksearch">
<tree :nodes="nodes"></tree>
</div>
<template id="tree">
<ul>
<li
v-for="node in nodes"
>
<span
v-if="node.children"
@click="toggleChildren()"
>
<i v-show="!showChildren">+</i>
<i v-show="showChildren">-</i>
</span>
<span v-html="node.label_"></span>
<tree
v-if="node.children"
v-show="showChildren"
:nodes="node.children"
></tree>
</li>
</ul>
</template>
Задача
С кодом выше поддеревья не могут быть свернуты независимо.Щелчок по одному из +
или -
сворачивает каждое поддерево.
Второй подход
Поэтому я попытался использовать компонент tree-item
вместо компонента tree
:
const treeConfig = [
{
label: 'User',
children: [
{
label: 'User group'
},
{
label: 'Permissions'
}
]
},
{
label: 'Tests',
children: [
{
label: 'Unit tests'
},
{
label: 'Visual regression tests'
}
]
},
{
label: 'Other stuff'
}
];
Vue.component('tree-item', {
template: '#tree-item',
props: ['node'],
data() {
return {
showChildren: true
};
},
methods: {
toggleChildren() {
this.showChildren = !this.showChildren;
}
}
});
const vm = new Vue({
el: '#app',
data: {
quicksearch: '',
title: 'Hello filtered tree!'
},
computed: {
nodes() {
const self = this;
function getTree(nodes) {
return nodes.map((node) => {
node.label_ = node.label;
node.label_ = node.label.replace(new RegExp(self.quicksearch, 'gi'), '<mark>$&</mark>');
if (node.children) {
node.children = getTree(node.children);
}
return node;
});
}
return getTree(treeConfig);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<input type="search" placeholder="Quick search" v-model="quicksearch">
<ul>
<tree-item
v-for="node in nodes"
:node="node"
></tree-item>
</ul>
</div>
<template id="tree-item">
<li>
<span
v-if="node.children"
@click="toggleChildren()"
>
<i v-show="!showChildren">+</i>
<i v-show="showChildren">-</i>
</span>
<span v-html="node.label_"></span>
<ul
v-if="node.children"
v-show="showChildren"
>
<tree-item
v-for="node in node.children"
:node="node"
></tree-item>
</ul>
</li>
</template>
Проблема
Теперь можно свернуть каждое поддерево отдельно, но быстрый фильтр не работает.Кажется, что объект nodes
не реагирует.
Где моя ошибка мышления?Любые предложения приветствуются.