VueJS如何在v-for中使用计算属性


78

如何在列表中使用计算属性。我正在使用VueJS v2.0.2。

这是HTML:

<div id="el">
    <p v-for="item in items">
        <span>{{fullName}}</span>
    </p>
</div>

这是Vue代码:

var items = [
    { id:1, firstname:'John', lastname: 'Doe' },
    { id:2, firstname:'Martin', lastname: 'Bust' }
];

var vm = new Vue({
    el: '#el',
    data: { items: items },
    computed: {
        fullName: function(item) {
            return item.firstname + ' ' + item.lastname;
        },
    },
});

Answers:


85

您不能为每次迭代创建一个计算属性。理想情况下,每个组件items都是它们自己的组件,因此每个组件都可以具有自己的fullName计算属性。

如果不想创建user组件,可以做的是改用方法。您可以fullNamecomputed属性右移到methods,然后可以像这样使用它:

{{ fullName(user) }}

另外,请注意,如果发现自己需要将参数传递给a computed,则可能需要使用方法。


如果您需要多次使用fullName,并且fullName方法是一个复杂的函数,每次迭代要花10次,那该怎么办呢?我认为@PanJunie的解决方案在那种情况下会更好。
RichC

老实说,我会在州内做得更高。如果您正在处理项目的排序版本,则下面的计算方法会中断。我绝对是为了安全。对于我来说,使数据尽可能高地重用变得更加有意义。
比尔·克里斯威尔

我的问题是,该数组可以根据被选择和取消选择的其他项进行更改,这会触发该数组本身的反应性,所以我认为,除了可能创建过滤器之外,我无法真正在更高级别上进行操作并在那时向数组中的对象添加其他属性(这不是一个糟糕的主意,只会导致一个附加循环遍历数组来完成所有操作-我猜是两倍好于10倍)。
RichC

40

您在这里缺少的是您的items是一个数组,其中包含所有项目,但是thecomputed是一个单一的fullName,仅不能表示fullNamein中的所有items。试试这个:

var vm = new Vue({
    el: '#el',
    data: { items: items },
    computed: {
        // corrections start
        fullNames: function() {
            return this.items.map(function(item) {
                return item.firstname + ' ' + item.lastname;
            });
        }
        // corrections end
    }
});

然后在视图中:

<div id="el">
    <p v-for="(item, index) in items">
        <span>{{fullNames[index]}}</span>
    </p>
</div>

Bill引入的方式肯定可以工作,但是我们可以使用计算的道具做到这一点,我认为这是比method迭代更好的设计,尤其是当应用变得更大时。此外,computedmethod某些情况相比,它的性能有所提高:http : //vuejs.org/guide/computed.html#Computed-Caching-vs-Methods


我用它来突出显示:class指令中的行比方法更好。
hitautodestruct

3
这不太方便。如果要浏览的排序副本items并获取fullName,则此操作将失败。真正应该做的是一个“用户”组件,该组件带有一个具有fullName计算属性的用户对象。
比尔·克里斯威尔

为什么items排序失败?@BillCriswell
PanJunjie潘俊杰

1
如果您要这样做,v-for="item in sortedVersionOfItems"index将是关闭的。
比尔·克里斯威尔

3

我喜欢潘俊杰潘俊杰发布的解决方案。通过反复迭代this.items一次(在组件创建阶段),然后缓存结果,它成为问题的核心。当然,这是利用计算的道具代替方法的主要好处。

computed: {
    // corrections start
    fullNames: function() {
        return this.items.map(function(item) {
            return item.firstname + ' ' + item.lastname;
        });
    }
    // corrections end
}

<p v-for="(item, index) in items">
    <span>{{fullNames[index]}}</span>
</p>

我唯一不喜欢的是,在DOM标记中,fullNames列表索引可以访问它。我们可以通过使用改进的是.reduce(),而不是.map()在计算的道具创建与每一个键的对象item.idthis.items

考虑以下示例:

computed: {
    fullNames() {
        return this.items.reduce((acc, item) => {
            acc[item.id] = `${item.firstname} ${item.lastname}`;
            return acc;
        }, {});
    },
},

<p v-for="item in items" :key="`person-${item.id}`">
    <span>{{ fullNames[item.id] }}</span>
</p>

注意:上面的示例假定它item.id是唯一的,例如来自典型的数据库输出。


0

也许添加另一个v-for来迭代一个单项长的列表:

<div id="el">
    <p v-for="item in items">
        <template v-for="fullName in [item.firstName + ' ' + item.lastName]">
            <span>{{fullName}}</span>
        </template>
    </p>
</div>

不好,但这就是您要寻找的:该范围内的对象具有名为fullName的属性,其中包含该特定值。

这不仅仅是虚荣功能,因为我们可能需要在多个地方使用该值,例如:

<span v-if="...">I am {{fullName}}</span>
<span v-else-if="...">You are {{fullName}}</span>
<span v-else>Who is {{fullName}}?</span>

我的用例是我在v-for循环(是,另一个日历)中构造日期,例如:

<v-row v-for="r in 5">
    <v-col v-for="c in 7">
        <template v-for="day in [new Date(start.getTime() + 24*60*60*1000*((c-1) + 7*(r-1)))]">
            <span>
                Some rendering of a day like {{day.getYear()}} and
                {{day.getMonth()}} etc.
            </span>
        </template>
    </v-col>
</v-row>

(为简便起见,我省略了:key="whatever"设置)

我承认最好的方法是将其移动到一个单独的组件,但是如果我们为这样的每两个衬里创建一个新组件,并且仅在该位置使用该组件,那么我们只会污染另一个名称空间。

也许一个v-let="day as new Date(...)"指令对于这样的目的会很方便。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.