我想创建一个带有搜索栏的菜单树,以突出显示菜单项。我想出了以下实现:
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>
现在可以分别折叠每个子树,但是quickfilter不起作用。看来nodes
对象不是反应性的。
我的思维错误在哪里?任何建议表示赞赏。
答案 0 :(得分:1)
您应该看一下:Reactivity in Depth 当您通过快速搜索值的更改重新计算出您的计算值时,它不会触发其他组件(在本例中为树项目)的重构,因为它不会深入观察对象。
这里简单的解决方法是,完全影响新的数组映射结果。
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;
}
},
watch : {
node(n) {
console.log(n)
}
},
created() {
console.log(this.node);
}
});
const vm = new Vue({
el: '#app',
data: {
quicksearch: '',
title: 'Hello filtered tree!',
nodes : []
},
methods : {
getNodes() {
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);
}
},
created(){
this.nodes = this.getNodes();
},
watch : {
quicksearch(q) {
this.nodes = this.getNodes();
}
}
});
<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>
答案 1 :(得分:1)
似乎是数组的问题。只需将:key="node.label_"
添加到模板中的tree-item
标记中即可。