VueJS Як я можу використовувати обчислене властивість за допомогою v-for


82

Як я можу використовувати обчислюване властивість у списках. Я використовую 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;
        },
    },
});

Відповіді:


87

Ви не можете створити обчислювану властивість для кожної ітерації. В ідеалі кожна з них itemsбула б власною складовою, тому кожна з них може мати свою fullNameобчислювану властивість.

Якщо ви не хочете створювати userкомпонент, можете замість цього використовувати метод. Ви можете перейти fullNameвід computedвласності до methods, тоді ви можете використовувати його, як:

{{ fullName(user) }}

Крім того, зауважте, якщо вам здається, що вам потрібно передати аргументи computedімовірно, замість цього вам потрібен метод.


Що робити, якщо вам потрібно використовувати fullName більше одного разу, а метод fullName - це складна функція, яку дійсно потрібно витратити 10 разів за кожну ітерацію? Я думаю, що рішення @ PanJunie було б набагато кращим у цій ситуації.
RichC

Я б чесно зробив це набагато вище в штаті. Обчислюваний підхід нижче зламається, якщо ви працюєте над відсортованою версією елементів. Я точно їхав заради безпеки тут. Для мене набагато більше сенсу робити дані настільки багаторазовими, наскільки це можливо, значно вище.
Білл

Моя проблема полягає в тому, що масив може змінюватися на основі інших елементів, які вибираються та скасовуються, що викликає реактивність самого масиву, тому я не можу це зробити на більш високому рівні, я не думаю, крім створення фільтра і додавання додаткових властивостей до об’єктів у масиві на той момент (що не є страшною ідеєю, а просто спричинює додавання, що циклічно перебирає масив, щоб зробити все це - в два рази краще, ніж у 10 разів).
RichC

43

Тут вам не вистачає того, що ваш items- це масив, який вміщує всі елементи, але computedце єдиний fullName, який просто не може виразити всі fullNames в 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>

Те, як Білл вводить, безумовно, працює, але ми можемо зробити це за допомогою обчислюваних реквізитів, і я думаю, що це кращий дизайн, ніж methodу ітераціях, особливо коли додаток стає більшим. Крім того, computedмає підвищення продуктивності порівняно methodз деякими обставинами: 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

Мені подобається рішення, розміщене PanJunjie 潘俊杰. Це стає суттю проблеми, лише повторюючись 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.idвходу this.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(...)"директива була б для цього зручною.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.