单击使用 v-for 创建的组件时,将类添加到特定的父 div

Posted

技术标签:

【中文标题】单击使用 v-for 创建的组件时,将类添加到特定的父 div【英文标题】:add class to a specific parent div when click a component created with v-for 【发布时间】:2019-09-21 23:11:41 【问题描述】:

我是 vuejs 的新手,这就是我想做的: 我有一个组件列表,每个组件都在一个 div 中。现在,如果我对组件做某事(即单击它)。我想向父 div 添加一个类。这是我到目前为止所做的,代码被简化了,只是为了展示我想用一个简单的案例来做什么。

我的 app.vue:

<div class="toggle-box" v-for="(name, index) in names" :class="classActive" :key="index">
    <app-comp :myName="name" :myIndex="index" @someEvent="doSomething"></app-counter>
</div>
data() 
    classActive: '',
    names: ['alpha', 'beta', 'gamma']
,
methods: 
    doSomething() 
        this.classActive === '' ? this.classActive = 'is-active': this.classActive='';
    

组件:

<div>
    <button @click="toggle"> myName  -  myIndex </button>
</div>

props: ['myName', 'myIndex'],
methods: 
    toggle() 
        this.$emit('someEvent', index);
    

这是做什么的:它创建了 3 个带有“toggle-box”类的 div,其中有一个标签为“name - index”的按钮。当我单击一个按钮时,它会发出带有索引的“someEvent”事件。父级侦听此事件并使用“toggle-box”类在 div 上切换“is-active”类。问题是,现在,当我单击一个按钮时,它会将类添加到所有 3 个 div。可能是因为 vuejs 的 3 个 div 之间没有区别。我知道我可以将索引附加到事件并在父级中使用 $event 调用它,但是我该如何使用它呢?还是有更好的方法来实现我想要的?

感谢您的帮助。

【问题讨论】:

不知道为什么要把classActive 设置为应用程序的属性,而不是组件。 什么意思?我知道这可能不是最好的方法,请随时更改:-) 【参考方案1】:

有几种不同的方法可以解决这个问题,但我认为出发点是考虑您希望如何将其表示为数据,而不是它在 UI 中的显示方式。所以先建模再看。

大概你会想要在这些活动项目被选中后做一些事情。我会专注于这一点,而不是突出它们的问题。然后突出显示会相对轻松地消失。

为了便于讨论,我们假设一组活动项目是适合您要实现的目标的模型。它可能不是,但它是一个简单的例子。

所以:

data() 
    return 
        activeNames: [],
        names: ['alpha', 'beta', 'gamma']
    
,

这里没有提到类,因为我们不担心 UI 问题,我们正在尝试对基础数据进行建模。

对于toggle 方法,我更倾向于发出name 而不是index,但您可以更好地判断哪个更好地代表数据。对于我的示例,它将是 name:

methods: 
    toggle() 
        this.$emit('someEvent', this.myName);
    

然后在父组件中,我们将在事件发出时从数组中添加/删除name。其他数据结构可能会更好,我会在最后再谈。

methods: 
    doSomething(name) 
        if (this.activeNames.includes(name)) 
            this.activeNames = this.activeNames.filter(item => item !== name);
         else 
            this.activeNames.push(name);
        
    

现在我们有了一个包含活动名称的数组,我们可以使用它来为这些包装器 div 派生类。

<div
    class="toggle-box"
    v-for="(name, index) in names"
    :class="'is-active': activeNames.includes(name)"
    :key="index"
>

完成。

按照承诺,我现在将回到您可以使用的其他数据结构。

我们可以使用具有布尔值的对象来代替数组:

data() 
    return 
        names: ['alpha', 'beta', 'gamma'],
        activeNames: 
            alpha: false,
            beta: false,
            gamma: false
        
    

在许多方面,对于这个特定的示例来说,这是一个更容易使用的结构,但我们最终将名称复制为属性键。如果我们不这样预填充它,我们最终可能会遇到反应性问题(尽管可以使用$set 解决这些问题)。

另一种选择是首先使用对象来表示名称:

data() 
    return 
        names: [
            name: 'alpha', active: false,
            name: 'beta', active: false,
            name: 'gamma', active: false
        ]
    

我无法真正判断这种数据结构对您的用例是否有意义。


更新:

根据您在 cmets 中所说的内容,我倾向于创建另一个组件来表示切换框。它们中的每一个都可以存储自己的active 状态,而不是试图将它们全部保存在父组件上。然后您的v-for 将直接创建这个新组件的实例。根据具体情况,这个新组件可能会合并到您的原始组件中。

这里有各种各样的其他考虑因素,很难给出明确的答案。如果需要在切换框组件之外知道活动状态,那么如果它只是内部状态,情况就完全不同了。如果一次只能打开一个切换框(如手风琴),那么这同样很棘手,因为内部状态是不够的。

【讨论】:

首先。感谢您的回答。在我的项目中,组件要复杂得多。让我们说一个显示一些信息的“框”。通过单击组件,该框打开,再次单击时关闭。我只想为切换框 div 添加一些样式以显示该框当前处于打开状态。就像我说的,我是 vuejs 的新手,所以我不知道是否有更好的方法来做到这一点,我的想法是添加一个 'is-active' 类。但是很难预先填充对象,因为切换框的数量是动态的。 this.activeNames = this.activeNames.filter(item => item !== name);是一个很大的帮助。 我已经更新了我的答案,但问题的核心仍然是以正确的方式存储数据。一旦你得到正确的数据形状和位置,剩下的就很容易了。根据您的评论,听起来也许绕过组件边界可能是比复杂数据结构更好的选择。

以上是关于单击使用 v-for 创建的组件时,将类添加到特定的父 div的主要内容,如果未能解决你的问题,请参考以下文章

单击内部复选框时,使用jQuery将类添加到包含li

将类添加到元素

将类组件转换为功能组件

仅当子容器具有内容时,如何将类添加到特定的父元素

当包含特定文件扩展名时,如何将类添加到超链接?

Vue.js - 将类添加到单击的按钮