首页 > 解决方案 > 在 Vue 中悬停时向元素添加类,而不使用数据

问题描述

在 Vue 组件中,我有一个这样的菜单:

<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>

我想在悬停时将类添加hoveredli.has-children-elements ( mouseenter) (以便能够为该下拉列表的子项制作一些更好的动画。并在mouseleave.

我知道有一些选项可以使用纯 CSS 来做到这一点,但是控制延迟和软淡入是一件痛苦的事情(并且很快就会变得非常混乱,无需添加一些类)。

我想象做这样的事情:

  ...
  mounted(){
    let liWithChildren = document.querySelectorAll( '.menu-outer-wrapper > li.has-children' );
    liWithChildren.forEach( (event, window) => {
      // Somehow add the class to the hovered element here.
      // But I don't know how. Or if it's a good/bad idea (performance-wise). 
    } 
  }

但这是要走的路吗?我可以在不使用的情况下做到这一点吗data(因为菜单是由 CMS 系统动态生成的。


更新 1

我试图让我的降价代码可读。所以我想避免这样的事情:

<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>
...
...
...

两者都因为它不会与动态生成的菜单融为一体。而且因为它给降价添加了很多噪音。


更新 2

我简化了这个例子,使它更容易理解。但由于评论,我想我会详细说明动态生成的菜单。我正在做这样的事情:

<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>

标签: javascriptvue.js

解决方案


你只需要@mouseenterand@mouseleave事件。您需要做的就是在所有可能有子项的列表项上侦听适当的事件,然后如果目标元素具有“有子项”类,则执行您的类添加(或删除)。这是我的做法:

<template>
  <nav id="secondary-menu" v-if="secondaryMenu">
    <ul>
      <li
        :class="[{ 'has-children': r.children }]"
        v-for="(r, r_key, r_index) in secondaryMenu"
        :key="`${r_key}-${r_index}`"
        @mouseenter="addClass"
        @mouseleave="removeClass"
      >
        <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"
            :key="`${c1_key}-${c1_index}`"
          >
            <a :href="c1.url" :title="c1.title">
              {{ c1.title }}
            </a>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</template>
<script>
export default {
  name: "HoverNav",
  props: {
    secondaryMenu: {
      type: Array,
      required: true,
    },
  },
  methods: {
    addClass: function (e) {
      if (e.target.classList.contains("has-children")) {
        e.target.classList.add("hovered");
      }
    },
    removeClass: function (e) {
      if (e.target.classList.contains("has-children")) {
        e.target.classList.remove("hovered");
      }
    },
  },
};
</script>

这是一个非常不美观的沙箱。让我知道这是否适合你:)

https://codesandbox.io/s/headless-brook-ysq97?file=/src/components/HoverNav.vue:0-1169


推荐阅读