How to apply a CSS class to an element when hovering in Vue, without the need for data

Within a Vue component, there exists a menu structured as follows:

<ul class="menu-outer-wrapper">
  <li><a href="/foo-1">Foo 1</a></li>
  <li class="has-children">
    <a href="/foo-2">Foo 2</a>
    <ul>
      <li><a href="/child-1">Child 1</a></li>
      <li><a href="/child-2">Child 2</a></li>
      <li><a href="/child-3">Child 3</a></li>
    </ul>
  </li>
  <li><a href="/foo-5">Foo 5</a></li>
  <li class="has-children">
    <a href="/foo-6">Foo 6</a>
    <ul>
      <li><a href="/child-1">Child 1</a></li>
      <li><a href="/child-2">Child 2</a></li>
    </ul>
  </li>
  <li><a href="/foo-7">Foo 7</a></li>
  <li><a href="/foo-8">Foo 8</a></li>
</ul>

The objective is to apply the hovered class to li.has-children elements when hovered over (mouseenter) in order to facilitate smoother animations for the children within that dropdown. The class should be removed upon mouseleave.

Although CSS can achieve this, controlling delays and fade-ins becomes complex without adding classes.

A possible approach involves the below code implementation:

  ...
  mounted(){
    let liWithChildren = document.querySelectorAll( '.menu-outer-wrapper > li.has-children' );
    liWithChildren.forEach((event) => {
      // Code to add class to hovered element
    }); 
  }

Is this considered best practice? Can it be implemented without using data, given that the menu is dynamically generated via a CMS?


Update 1

An effort is made to maintain readability by avoiding approaches like:

<ul class="menu-outer-wrapper">
  <li :class="[ { 'hovered' : someVar } ]">
    <a href="/foo-1">Foo 1</a>
  </li>
  <li :class="[ { 'hovered' : someVar }, 'has-children' ]">
    <a href="/foo-2">Foo 2</a>
    <ul>
      <li><a href="/child-1">Child 1</a></li>
      <li><a href="/child-2">Child 2</a></li>
      <li><a href="/child-3">Child 3</a></li>
    </ul>
  </li>
  <li :class="[ { 'hovered' : someVar } ]">
    <a href="/foo-3">Foo 2</a>
  </li>
...
...
...

This method does not align with the dynamically generated menu and introduces unnecessary complexity to the markdown.


Update 2

To simplify comprehension, the example was condensed. However, due to feedback, further insight regarding the dynamically generated menu is addressed:

<nav id="secondary-menu" v-if="secondaryMenu">
  <ul>
    <li
      :class="[ { 'has-children': r.children } ]"
      v-for="(r, r_key, r_index) in secondaryMenu">
      <a :href="r.url" :title="r.title">
        {{ r.title }}
      </a>
      <ul class="children" v-if="r.children">
        <li v-for="(c1, c1_key, c1_index) in r.children">
          <a :href="c1.url" :title="c1.title">
            {{ c1.title }}
          </a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

Answer №1

To achieve this functionality, you can utilize the @mouseenter and @mouseleave events in your code. By listening for these events on list items that may have children, you can dynamically add or remove a class based on whether the target element contains the class "has-children". Here is a sample implementation:

<template>
  <nav id="secondary-menu" v-if="secondaryMenu">
    <ul>
      <li
        :class="[{ 'has-children': item.children }]"
        v-for="(item, index) in secondaryMenu"
        :key="index"
        @mouseenter="onMouseEnter"
        @mouseleave="onMouseLeave"
      >
        <a :href="item.url" :title="item.title">
          {{ item.title }}
        </a>
        <ul class="children" v-if="item.children"&glt;
          <li
            v-for="(child, childIndex) in item.children"
            :key="childIndex"
          >
            <a :href="child.url" :title="child.title">
              {{ child.title }}
            </a>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</template>
<script>
export default {
  name: "HoverNav",
  props: {
    secondaryMenu: {
      type: Array,
      required: true,
    },
  },
  methods: {
    onMouseEnter: function (event) {
      if (event.target.classList.contains("has-children")) {
        event.target.classList.add("hovered");
      }
    },
    onMouseLeave: function (event) {
      if (event.target.classList.contains("has-children")) {
        event.target.classList.remove("hovered");
      }
    },
  },
};
</script>

You can see a basic demo of this functionality in action using this sandbox link: https://codesandbox.io/s/headless-brook-ysq97?file=/src/components/HoverNav.vue:0-1169

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Store the position of a draggable object using JQuery into an SQL database

Because of the current crisis, my friends and I are unable to meet up in person. To stay connected, I've come up with a little game for us to play online. Each of us can move an object on my website, and when the page is refreshed, we'll see the ...

Refresh HTML with JSON/AJAX

Ever since I discovered JSON for handling AJAX functionality in my rails applications, I've been hooked. Using RJS to render HTML just didn't sit right with me as it felt like it was violating the MVC pattern. My first project that heavily utiliz ...

Tips on using Bootstrap 4 containers within a container-fluid and ensuring text stays within a container at all times

What is the best way to incorporate a Bootstrap 4 container within a container-fluid? how can we ensure that text is always contained within the blue section? ...

What steps can I take to avoid Vuetify's v-navigation-drawer from truncating text content?

Is there a way to stop the v-navigation-drawer component in Vuetify from automatically shortening text? Whenever I add text to the drawer, it gets cut off and looks like "gobbled...". My goal is to have the content display smoothly, without being shortened ...

Having difficulty replicating the sorting process in Vue.js for the second time

I need assistance with implementing sorting functionality in a Vue.js table component. Currently, the sorting mechanism is working fine on the first click of the th item, but it fails to sort the items on subsequent clicks. const columns = [{ name: &ap ...

I'm looking for recommendations on the best method to develop reusable components using JavaScript and jQuery in an elegant way

I'm interested in finding user-friendly tools in JavaScript to easily create small, reusable components. I envision a component builder with a simple API that can generate HTML output for specified data, allowing for seamless embedding on websites. Co ...

Load the audio file, pause it, and begin playing it after a few seconds have passed

After 8 seconds, I want to use setTimeout to play an audio file: setTimeout(function() { document.getElementById('delayed_play').style.display = 'block'; }, 8 * 1000); <div id="delayed_play"> The issue is that ...

Unable to access file due to permission denial in command #yo Angular

I recently started using the #yo angular command and encountered an error message. Any suggestions on what I should do next? #yo angular /usr/lib/node_modules/yo/node_modules/update-notifier/node_modules/configstore/node_modules/graceful-fs/polyfill ...

Streamline uploading files with AngularJS using Selenium

I am utilizing Powershell to operate .NET Selenium with a FirefoxDriver in order to automate certain tasks. One of these tasks involves file uploads, and the website I am working with appears to have been built using AngularJS. After some experimentation, ...

selecting a radio button and saving its value into a JavaScript variable

How can I assign the return value from a JavaScript script function to a variable inside the HTML body? The function will return the selected variable, but how can I assign it to a variable within my HTML body? <body> <form action="somepage.php ...

What is the best way to use jQuery to smoothly transition the current scroll position to a desired target scroll position?

I am looking to incorporate scroll animation into my block. The goal is for the block to smoothly scroll from its current position on the page to a specific target position. I am familiar with the .animate() method in jQuery, but I have not come across ...

Verify if an element with a specific index exists within an array

$.each(constructions, function(i,v) { if ($.inArray(v.name, map[ii].buildings) == -1) {//do something} }; In this scenario, the constructions array consists of unique objects with a name attribute. On the other hand, map[ii].buildings is an array contain ...

Storing map tiles offline in React-Leaflet

One common method I have come across for storing tiles offline with Leaflet involves using localforage. Here's an example: const map = L.map("map-id"); const offlineLayer = L.tileLayer.offline('https://server.arcgisonline.com/ArcGIS/res ...

Tips on displaying a spinner only when data is retrieved from an Http service

How can I ensure that a spinner is only shown during an HTTP service call and dismissed when my component receives data? To address this issue, I implemented a cache service to store data fetched from the HTTP service for future use. However, I want to sh ...

Adjust the width of a container as its children expand

My current project involves creating a dynamic gallery using JavaScript and jQuery, where full-sized images slide out from the right side. I have successfully implemented this functionality, but now I am facing a new challenge. I need the parent block of t ...

Order of callback execution in jQuery's ready function

When two JavaScript functions on a page need to be called once the document load is complete, is there a possibility that one function could be executed before the other, or will it always be the same order? For example, using jQuery with the following co ...

Tips for altering attributes in a child element produced through v-for in VueJs 3

In my coding setup, the parent component generates child components using the v-for directive: <div class="planlist"> <ul id="planOl"> <PlanLego v-for="action in store.plan" :v-if="actio ...

Issue with Ajax post redirection back to original page

I'm facing an issue with my ajax call where I send multiple checkbox values to a php file for processing and updating the database. The post request and database updates are successful, but the page doesn't return to the calling php file automati ...

Tips for transferring data to the next page with JavaScript AJAX

I am working on a webpage that includes an html select element <pre> $query = mysql_query("select * from results"); echo "<select id='date' onchange='showdata()' class='form-control'>"; while ($arr = mysql_fetch_a ...

Identify specific terms within a webpage using an iframe that is integrated onto the same page

Is there a way to implement word highlighting on a webpage containing an iframe with a search field? The concept involves allowing a user to input search terms within the iframe, which would then send a command to highlight those words on the main page. ...