繁体   English   中英

如何在 Vue 3 中的 div 计算数组上重新应用事件监听器?

[英]How to reapply eventlistener on a computed array of divs in Vue 3?

我想显示一个 div 数组,目的是在悬停 div 时在 div 本身和子元素上添加一个 class。

div 数组是计算 function 的结果。代码如下:


 <article
    v-for="(article, index) in filteredArticles"
    :key="article.id"
    ref="articleRefs"
    :ref-key="index"
    @mouseenter="handleClass(index, 'add')"
    @mouseleave="handleClass(index, 'remove')"
>
    <!-- Content -->
</article
const articleRefs = ref<HTMLDivElement[]>([])
const articleList = ref([] as Article[])

const filteredArticles = computed(() => {
    return activeTag.value !== ''
        ? articleList.value.filter((a) => a.tags.some((t) => t.Tag_id.title === activeTag.value))
        : articleList.value
})

watch(
    filteredArticles.value,
    () => articleRefs.value = []
)

const handleClass = (index: number, action: 'add'|'remove') => {
    const hoveredArticle = articleRefs.value[index]
    hoveredArticle.classList[action]('animate')
    hoveredArticle.querySelector('h2')?.classList[action]('glitch')
}

当页面加载时,一切正常,只要我更改标签以显示未被过滤掉的文章,我的handleClass方法就会工作/被调用。

但是,如果过滤掉的文章再次显示,悬停时不会发生任何事情。

我错过了什么?

先感谢您

如果您使用循环遍历文章的数组索引并尝试将 map 指向 refs 的索引,则会出现问题。 如果您查看vue 文档,您会发现项目的顺序不能保证与数据数组的顺序相同

需要注意的是,ref 数组不保证与源数组顺序相同。

这将导致问题,即当使用 for 循环的索引时,您的 refs 数组中可能有不同的索引。

解决方案

这个想法是用一个新的SingleArticle Vue 组件将您的数据逻辑与表示逻辑分开(命名可能会有所不同,具体取决于您的上下文,但建议至少有两个单词的组件名称。)。 如果你按如下方式构建它,Vue 框架将确保你的更新逻辑有效,你不需要关心它。

1. 单条组件

  • 根据 hover state 从框架应用根 class animated
  • 正如我从上下文中理解的那样,文章的内容作为 HTML 字符串传递,因此您需要使用querySelector获取内容中的元素并对其应用 class。
<!-- vue sfc template: -->
<article
  ref="articleRef"
  :class="{ animated: isHover }"
  v-html="content"
  @mouseenter="isHover = true"
  @mouseleave="isHover = false"
/>
// vue sfc script (or script setup)
import { ref, defineComponent } from 'vue';

export default defineComponent({
  name: 'SingleArticle',
  props: {
    // what ever is in your article props
    // but I add some example props to showcase the idea
    content: String,
    // ...
  },
  setup(props) {
    var articleRef = ref<HTMLElement>(null);
    var isHover = ref<boolean>(false);

    watch(isHover, (currIsHover) => {
      const action = currIsHover ? 'add' : 'remove';
      articleRef.value?.querySelector('h2')?.classList[action]('glitch');
    });
    
    return {
      articleRef,
      isHover,
    }
  }
});

2. 在v-for使用新组件

<!-- inside the vue sfc template -->
<single-article
 v-for="(article, index) in filteredArticles"
 :key="article.id"
 :content="article.content"
/>

// the main component only contains the logic for the
// filtering and the hovering logic is completely done
// inside the new single article component.
export default defineComponent({
  setup() {
    const articleList = ref<Article[]>([]);

    const filteredArticles = computed(() => {
      if (!activeTag.value) return articleList.value;

      return articleList.value.filter(
        (a) => a.tags.some((t) => t.Tag_id.title === activeTag.value)
      );
    }
    
    return {
      filteredArticles,
    };
  }
})

最后的想法和评论

我没有测试实现,这只是根据我的想法写下来的。

该解决方案会将过滤器逻辑与文章的呈现逻辑分开,这将为您提供两个干净的组件,它们易于测试且易于理解。 更新将开箱即用,因为 vue 会响应式地迎合它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM