3👍
You’re kind of HTML-oriented in your approach, here, and the Vue approach is to be model-oriented. So instead of laying out your model structure in the HTML, you should make a data model with the hierarchy you want, and have your components render it.
I made my app the section level, since you’re concerned with what happens below that level. I created a data model like the first section of your example.
The trick to select-only-one behavior is that there should be one variable to hold the currently selected value. That value is owned by the parent. Each child gets a prop telling it whether it is the selected value.
When a child becomes selected, it emits an event, which the parent processes (this is the Vue way of child-to-parent communication).
Vue.component('nav-child', {
template: '#nav-child-template',
props: ['name', 'url']
});
Vue.component('nav-item', {
template: '#nav-item-template',
props: ['name', 'children', 'isActive'],
methods: {
toggleClass() {
this.$emit('activate', this.isActive ? null : this.name);
}
}
});
new Vue({
el: '#nav-section',
data: {
activeItem: null,
items: [{
name: 'Home',
children: [{
name: 'Dashboard 1',
url: '#'
},
{
name: 'Dashboard 2',
url: '#'
}
]
},
{
name: 'Settings',
children: [{
name: 'Setting 1',
url: '#'
},
{
name: 'Setting 2',
url: '#'
}
]
}
]
},
methods: {
activate(name) {
this.activeItem = name;
}
}
});
.active {
border: thin solid red;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<template id="nav-child-template">
<li>
<a :href="url">{{ name }}</a>
</li>
</template>
<template id="nav-item-template">
<li>
<a @click="toggleClass">{{ name }}</a>
<ul :class="{ 'active': isActive}">
<li is="nav-child" v-for="child in children" :name="child.name" :url="child.url"></li>
</ul>
</li>
</template>
<ul id="nav-section">
<li is="nav-item" v-for="item in items" :name="item.name" :is-active="activeItem === item.name" :children="item.children" @activate="activate"></li>
</ul>