While there are many examples of toggling classes in Vuejs, I am yet to find one that toggles a class narrowing down the scope of the element. If I define a global variable like this:
data: {
toggle: false
}
I will run into a problem when I have an element, like this navigation bar:
<ul class="menu">
<li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
Foo
<ul class="dropdown">
<li>Dropdown Item 1</li>
<li>Dropdown Item 2</li>
</ul>
</li>
<li class="has-dropdown" v-bind:class="{ 'is-open': toggle }" @click="toggle = !toggle">
Bar
<ul class="dropdown">
<li>Dropdown Item 1</li>
<li>Dropdown Item 2</li>
</ul>
</li>
</ul>
See what happens here? If I click in one of these two elements, both are going to toggle the class at the same time, because it's changing a global variable. Now, how would I toggle the class of only the element that is clicked?
It boggles my mind that something so simple requires so much code using modern frameworks, and it's a reason why JavaScript development is becoming so complex. I resorted to using a plain-old JavaScript listener to solve the matter.
<li class="has-dropdown" @click="toggle">
...
</li>
...
methods: {
toggle: function( event ) {
event.target.classList.toggle('is-open')
}
}
...
This is just a small example of what @SLaks mentioned in his answer. Essentially turn the list elements into their own components so they can have their own state.
Vue.component("clicktoggle", {
template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
data() {return {toggle: false}}
})
And here is how it's used.
console.clear()
Vue.component("clicktoggle", {
template:`<li :class="{ 'is-open': toggle }" @click="toggle = !toggle"><slot></slot></li>`,
data() {return {toggle: false}}
})
new Vue({
el:"#app"
})
.has-dropdown {
cursor: pointer;
}
.has-dropdown:not(.is-open) ul {
display: none
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
<ul class="menu">
<li class="has-dropdown" is="clicktoggle">
Foo
<ul class="dropdown">
<li>Dropdown Item 1</li>
<li>Dropdown Item 2</li>
</ul>
</li>
<clicktoggle class="has-dropdown">
Bar
<ul class="dropdown">
<li>Dropdown Item 1</li>
<li>Dropdown Item 2</li>
</ul>
</clicktoggle>
</ul>
</div>
Vue makes it incredibly simple to knock out little components like this. One quick possible enhancement would be to add a property to specify what class you wanted to toggle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With