我的vue组件是这样的:
Vue.component('list-category', {
template: "#lc",
props: ['data', 'category', 'search'],
data() {
return {
open: false,
categoryId: this.category
}
},
mounted() {
let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
this.open = isDataOpen(this.data);
},
computed: {
icon() {
return {
'fa-plus': !this.open,
'fa-minus': this.open,
}
},
isFolder() {
return this.data.children && this.data.children.length
},
isShow() {
return this.open ? 'show' : 'hide'
}
},
methods: {
toggle() {
this.open = !this.open
},
filterByCategory(id) {
this.categoryId = id
}
}
})
new Vue({
el: '#app',
data() {
return {
categories: [{
id: 1,
name: 'England',
children: [{
id: 3,
name: 'Chelsea',
children: [{
id: 7,
name: 'Hazard'
},
{
id: 8,
name: 'Morata'
}
]
},
{
id: 4,
name: 'Manchester United',
children: [{
id: 9,
name: 'Pogba'
},
{
id: 10,
name: 'Lukaku'
}
]
}
]
},
{
id: 2,
name: 'Spain',
children: [{
id: 5,
name: 'Real Madrid',
children: [{
id: 11,
name: 'Ronaldo'
},
{
id: 12,
name: 'Bale'
}
]
},
{
id: 6,
name: 'Barcelona',
children: [{
id: 13,
name: 'Messi'
},
{
id: 14,
name: 'Suarez'
}
]
},
]
}
],
category: 7
}
}
})

.active {
background: yellow;
}
.pd-search-filter > .panel-body ul.filter-category {
padding-left: 0;
list-style: none;
margin: 0 -15px 0;
}
.pd-search-filter > .panel-body ul.filter-category > li a {
display: block;
padding: 10px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pd-search-filter > .panel-body ul.filter-category > li a:last-child {
padding-left: 45px;
}
.pd-search-filter > .panel-body ul.filter-category > li a:focus, .pd-search-filter > .panel-body ul.filter-category > li a:hover {
background-color: #eeeeee;
text-decoration: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul {
padding-left: 0;
list-style: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul > li > a {
padding-left: 30px;
}
.show {
display: block !important;
}
.hide {
display: none !important;
}

<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="app">
<div class="panel panel-default pd-search-filter">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-circle-o"></i> By Category</h3>
</div>
<div class="panel-body">
<ul class="filter-category" v-for="list in categories">
<list-category :data="list" :category="category"></list-category>
</ul>
</div>
</div>
</div>
<template id="lc">
<li>
<!--parent-->
<a v-if="isFolder" href="javascript:" @click="toggle">
<span class="fa fa-fw" :class="icon"></span> {{data.name}}
</a>
<!--if not folding, we do not need an binding event-->
<a v-else href="javascript:" :title="data.name" :class="{active: data.id === categoryId}" @click="filterByCategory(data.id)"><span class="fa fa-fw fa-circle-o"></span> {{data.name}}</a>
<!--children-->
<ul v-if="isFolder" :class="isShow">
<list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId"></list-category>
</ul>
</li>
</template>
&#13;
似乎您需要查看演示和完整代码
它是这样的:http://jsfiddle.net/vxLhbo5m/861/
从演示中看到的类别危险活跃。如果我点击morata类别,它就不活跃了。虽然我已经制作了代码
我该如何解决这个问题?
=============================================== ============================
答案 0 :(得分:1)
你必须将类别计算器移动到观察者(而不是mount()
)并发出/收听从孩子到父母的一些事件来更新类别并且崩溃非选定的子树。
<强> Updated JSFiddle here 强>
的变化:
模板:
父:
自:
<div id="app">
...
<list-category :data="list" :category="category"></list-category>
添加监听category
事件并更新父级的category
属性:
<div id="app">
...
<list-category :data="list" :category="category" @category="category = $event"></list-category>
子:
自:
<template id="lc">
...
<list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId"></list-category>
收听category
事件并将其发送给父母:
<template id="lc">
...
<list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId" @category="$emit('category', $event)"></list-category>
JavaScript(所有孩子):
将filterByCategory
更改为发出事件而不是改变属性:
自:
filterByCategory(id) {
this.categoryId = id
}
要:
filterByCategory(id) {
this.$emit('category', id);
}
删除mounted
挂钩并添加观察者:
删除已安装:
mounted() {
let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
this.open = isDataOpen(this.data);
},
添加观察者,以便在父级category
更改时选择
watch: {
category: {
handler() {
this.categoryId = this.category
let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
this.open = isDataOpen(this.data);
},
immediate: true
}
}
演示:
Vue.component('list-category', {
template: "#lc",
props: ['data', 'category', 'search'],
data() {
return {
open: false,
categoryId: this.category
}
},
computed: {
icon() {
return {
'fa-plus': !this.open,
'fa-minus': this.open,
}
},
isFolder() {
return this.data.children && this.data.children.length
},
isShow() {
return this.open ? 'show' : 'hide'
}
},
methods: {
toggle() {
this.open = !this.open
},
filterByCategory(id) {
this.$emit('category', id);
}
},
watch: {
category: {
handler() {
this.categoryId = this.category
let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
this.open = isDataOpen(this.data);
},
immediate: true
}
}
})
new Vue({
el: '#app',
data() {
return {
categories: [{
id: 1,
name: 'England',
children: [{
id: 3,
name: 'Chelsea',
children: [{
id: 7,
name: 'Hazard'
},
{
id: 8,
name: 'Morata'
}
]
},
{
id: 4,
name: 'Manchester United',
children: [{
id: 9,
name: 'Pogba'
},
{
id: 10,
name: 'Lukaku'
}
]
}
]
},
{
id: 2,
name: 'Spain',
children: [{
id: 5,
name: 'Real Madrid',
children: [{
id: 11,
name: 'Ronaldo'
},
{
id: 12,
name: 'Bale'
}
]
},
{
id: 6,
name: 'Barcelona',
children: [{
id: 13,
name: 'Messi'
},
{
id: 14,
name: 'Suarez'
}
]
},
]
}
],
category: 7
}
}
})
&#13;
.active {
background: yellow;
}
.pd-search-filter > .panel-body ul.filter-category {
padding-left: 0;
list-style: none;
margin: 0 -15px 0;
}
.pd-search-filter > .panel-body ul.filter-category > li a {
display: block;
padding: 10px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pd-search-filter > .panel-body ul.filter-category > li a:last-child {
padding-left: 45px;
}
.pd-search-filter > .panel-body ul.filter-category > li a:focus, .pd-search-filter > .panel-body ul.filter-category > li a:hover {
background-color: #eeeeee;
text-decoration: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul {
padding-left: 0;
list-style: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul > li > a {
padding-left: 30px;
}
.show {
display: block !important;
}
.hide {
display: none !important;
}
&#13;
<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="app">
<div class="panel panel-default pd-search-filter">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-circle-o"></i> By Category</h3>
</div>
<div class="panel-body">
<ul class="filter-category" v-for="list in categories">
<list-category :data="list" :category="category" @category="category = $event"></list-category>
</ul>
</div>
</div>
</div>
<template id="lc">
<li>
<!--parent-->
<a v-if="isFolder" href="javascript:" @click="toggle">
<span class="fa fa-fw" :class="icon"></span> {{data.name}}
</a>
<!--if not folding, we do not need an binding event-->
<a v-else href="javascript:" :title="data.name" :class="{active: data.id === categoryId}" @click="filterByCategory(data.id)"><span class="fa fa-fw fa-circle-o"></span> {{data.name}}</a>
<!--children-->
<ul v-if="isFolder" :class="isShow">
<list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="categoryId" @category="$emit('category', $event)"></list-category>
</ul>
</li>
</template>
&#13;
答案 1 :(得分:0)
您无法控制子组件中父元素的数据。为了更改父母的数据,您需要将更改发送到父级,然后更改父级的数据。
请查看以下内容,了解如何使用this.$emit
。我知道我必须更改json数据以避免对同一模板的递归调用,但现在您已了解如何更改父数据元素。
Vue.component('list-category', {
template: "#lc",
props: ['data', 'category', 'search'],
data() {
return {
open: false,
categoryId: this.category
}
},
mounted() {
let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen);
this.open = isDataOpen(this.data);
},
computed: {
icon() {
return {
'fa-plus': !this.open,
'fa-minus': this.open,
}
},
isFolder() {
return this.data.children && this.data.children.length
},
isShow() {
return this.open ? 'show' : 'hide'
}
},
methods: {
toggle() {
this.open = !this.open
},
filterByCategory: function(id){
this.$emit('update-active-category', id);
console.log('Emitting: ' + id);
}
}
})
new Vue({
el: '#app',
data() {
return {
categories: [{
id: 1,
name: 'England',
children: [{
id: 3,
name: 'Chelsea',
children: [{
id: 7,
name: 'Hazard'
},
{
id: 8,
name: 'Morata'
}
]
},
{
id: 4,
name: 'Manchester United',
children: [{
id: 9,
name: 'Pogba'
},
{
id: 10,
name: 'Lukaku'
}
]
}
]
},
{
id: 2,
name: 'Spain',
children: [{
id: 5,
name: 'Real Madrid',
children: [{
id: 11,
name: 'Ronaldo'
},
{
id: 12,
name: 'Bale'
}
]
},
{
id: 6,
name: 'Barcelona',
children: [{
id: 13,
name: 'Messi'
},
{
id: 14,
name: 'Suarez'
}
]
},
]
}
],
category: 7
}
},
methods: {
updateActiveCategory: function(id) {
this.category = id;
}
}
})
&#13;
.active {
background: yellow !important;
}
.pd-search-filter > .panel-body ul.filter-category {
padding-left: 0;
list-style: none;
margin: 0 -15px 0;
}
.pd-search-filter > .panel-body ul.filter-category > li a {
display: block;
padding: 10px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.pd-search-filter > .panel-body ul.filter-category > li a:last-child {
padding-left: 45px;
}
.pd-search-filter > .panel-body ul.filter-category > li a:focus, .pd-search-filter > .panel-body ul.filter-category > li a:hover {
background-color: #eeeeee;
text-decoration: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul {
padding-left: 0;
list-style: none;
}
.pd-search-filter > .panel-body ul.filter-category > li a + ul > li > a {
padding-left: 30px;
}
.show {
display: block !important;
}
.hide {
display: none !important;
}
&#13;
<script src="https://unpkg.com/vue"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="app">
<div class="panel panel-default pd-search-filter">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-circle-o"></i> By Category</h3>
</div>
<div class="panel-body">
<ul class="filter-category" v-for="list in categories">
<list-category :data="list" :category="category" @update-active-category="updateActiveCategory">
</list-category>
</ul>
</div>
</div>
</div>
<template id="lc">
<li>
<!--parent-->
<a v-if="isFolder" href="javascript:" @click="toggle">
<span class="fa fa-fw" :class="icon"></span> {{data.name}}
</a>
<!--if not folding, we do not need an binding event-->
<a v-else href="javascript:" :title="data.name" :class="{active: data.id === category}" @click="filterByCategory(data.id)" @update-active-category="filterByCategory"><span class="fa fa-fw fa-circle-o"></span> {{data.name}}</a>
<!--children-->
<ul v-if="isFolder" :class="isShow">
<list-category v-for="(data, index) in data.children" :key="index" :data="data" :search="search" :category="category" @update-active-category="filterByCategory"></list-category>
</ul>
</li>
</template>
&#13;