我的 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>
看来您需要查看演示和完整代码
是这样的:http://jsfiddle.net/vxLhbo5m/861/
从演示中看到类别危险活跃。如果我点击 morata 类别,它是不活动的。而我已经编写了代码
我该如何解决这个问题?
============================================= ============================
最佳答案
您必须将类别计算器移动到观察者(而不是 mount()
)并发出/监听从子级到父级的一些事件以更新类别和折叠 未选择的子树。
变化:
模板:
家长:
来自:
<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>
child :
来自:
<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(全部在 child 中):
更改
filterByCategory
以发出事件而不是改变属性:来自:
filterByCategory(id) { this.categoryId = id }
收件人:
filterByCategory(id) { this.$emit('category', id); }
删除
mounted
钩子(Hook)并添加 watcher:移除挂载:
mounted() { let isDataOpen = (d) => d.id === this.categoryId || d.children && d.children.some(isDataOpen); this.open = isDataOpen(this.data); },
当
category
在父级中发生变化时添加 watcher 以获取: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
}
}
})
.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" @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>
关于javascript - 如果元素单击 vue 组件,我如何添加类事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49473224/