Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Computed в Vue
Основное назначение
Computed (вычисляемые свойства) - это функции в Vue, которые автоматически пересчитываются когда меняются их зависимости. Главный плюс - они кешируют результат и не пересчитываются, если зависимости не изменились. Это мощный инструмент для производительности и чистого кода.
Проблема без Computed
// ПЛОХО - пересчитывается при КАЖДОМ render-е
<template>
<div>
<input v-model="firstName">
<input v-model="lastName">
<!-- Вызывается функция при каждом render-е! -->
<p>{{ firstName + ' ' + lastName }}</p>
<p>{{ (firstName + ' ' + lastName).toUpperCase() }}</p>
<p>{{ (firstName + ' ' + lastName).length }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const firstName = ref('Иван');
const lastName = ref('Петров');
// Логика повторяется 3 раза!
// Не очень читаемо
// Пересчитывается при КАЖДОМ render-е
</script>
Решение с Computed
Vue 3 (Composition API)
<template>
<div>
<input v-model="firstName">
<input v-model="lastName">
<!-- Используем computed, пересчитывается только если deps изменились -->
<p>{{ fullName }}</p>
<p>{{ fullNameUpper }}</p>
<p>{{ fullNameLength }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const firstName = ref('Иван');
const lastName = ref('Петров');
// Только читаемое свойство
const fullName = computed(() => {
console.log('fullName пересчитана'); // Выполнится только при изменении
return firstName.value + ' ' + lastName.value;
});
const fullNameUpper = computed(() => fullName.value.toUpperCase());
const fullNameLength = computed(() => fullName.value.length);
</script>
Vue 2 (Options API)
<template>
<div>
<input v-model="firstName">
<input v-model="lastName">
<p>{{ fullName }}</p>
<p>{{ fullNameUpper }}</p>
</div>
</template>
<script>
export default {
data() {
return {
firstName: 'Иван',
lastName: 'Петров'
};
},
computed: {
fullName() {
console.log('fullName пересчитана');
return this.firstName + ' ' + this.lastName;
},
fullNameUpper() {
return this.fullName.toUpperCase();
}
}
};
</script>
Ключевые преимущества
1. Кеширование (Memoization)
const expensiveComputation = computed(() => {
// Эта функция вызывается только если dependencies изменились!
console.log('Дорогостоящий расчет...');
let sum = 0;
for (let i = 0; i < 1000000; i++) {
sum += i; // Тяжелый расчет
}
return sum;
});
// Выполнение:
// 1. expensiveComputation.value → логирует, вычисляет
// 2. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш
// 3. expensiveComputation.value → логирует НЕ вычисляет, возвращает кеш
// Логируется только один раз!
2. Чистота кода
// ПЛОХО - inline логика в template
<div v-if="user && user.profile && user.profile.verified">Verified</div>
<span>{{ user && user.profile && user.profile.name }}</span>
// ХОРОШО - используем computed
const isVerified = computed(() => user.value?.profile?.verified ?? false);
const userName = computed(() => user.value?.profile?.name ?? 'Unknown');
<div v-if="isVerified">Verified</div>
<span>{{ userName }}</span>
3. Реактивность
const price = ref(100);
const quantity = ref(5);
const taxRate = ref(0.1);
const total = computed(() => {
// Автоматически пересчитывается при изменении price, quantity или taxRate
return price.value * quantity.value;
});
const totalWithTax = computed(() => {
// Зависит от total, которая зависит от других переменных
return total.value * (1 + taxRate.value);
});
// При изменении price:
price.value = 200; // total автоматически пересчитается
// totalWithTax автоматически пересчитается
4. Фильтрация и сортировка списков
const items = ref([ { name: 'Apple', price: 100 },
{ name: 'Banana', price: 50 },
{ name: 'Cherry', price: 80 }
]);
const searchQuery = ref('');
const sortBy = ref('price'); // 'name' или 'price'
// Фильтруем и сортируем
const filteredItems = computed(() => {
return items.value
.filter(item => item.name.includes(searchQuery.value))
.sort((a, b) => {
if (sortBy.value === 'name') return a.name.localeCompare(b.name);
return a.price - b.price;
});
});
// Template
<div>
<input v-model="searchQuery" placeholder="Search...">
<select v-model="sortBy"><option>name</option><option>price</option></select>
<ul>
<li v-for="item in filteredItems" :key="item.name">
{{ item.name }} - {{ item.price }}
</li>
</ul>
</div>
Computed vs Methods
// COMPUTED - кешируется
const fullName = computed(() => {
console.log('computed triggered');
return firstName.value + ' ' + lastName.value;
});
// METHOD - вызывается каждый раз
const getFullName = () => {
console.log('method triggered');
return firstName.value + ' ' + lastName.value;
};
// Template
<p>{{ fullName }}</p> <!-- computed: логирует 1 раз -->
<p>{{ fullName }}</p> <!-- computed: логирует НЕ выполняется -->
<p>{{ getFullName() }}</p> <!-- method: логирует каждый раз -->
<p>{{ getFullName() }}</p> <!-- method: логирует каждый раз -->
Вывод: используйте computed для данных, methods для действий.
Writable Computed (с setter)
const firstName = ref('Иван');
const lastName = ref('Петров');
const fullName = computed({
// Getter
get() {
return firstName.value + ' ' + lastName.value;
},
// Setter - вызывается когда меняете computed свойство
set(newValue) {
[firstName.value, lastName.value] = newValue.split(' ');
}
});
// Использование
console.log(fullName.value); // "Иван Петров"
fullName.value = 'Петр Сидоров'; // Вызывает setter
console.log(firstName.value); // "Петр"
console.log(lastName.value); // "Сидоров"
Практический пример: Todo фильтр
<template>
<div>
<input v-model="newTodo" @keyup.enter="addTodo">
<button @click="addTodo">Add</button>
<div>
<button
@click="filter = 'all'"
:class="{ active: filter === 'all' }"
>
All ({{ allTodos.length }})
</button>
<button
@click="filter = 'active'"
:class="{ active: filter === 'active' }"
>
Active ({{ activeTodos.length }})
</button>
<button
@click="filter = 'completed'"
:class="{ active: filter === 'completed' }"
>
Completed ({{ completedTodos.length }})
</button>
</div>
<ul>
<li v-for="todo in filteredTodos" :key="todo.id">
<input
type="checkbox"
v-model="todo.completed"
>
<span :class="{ completed: todo.completed }">{{ todo.text }}</span>
</li>
</ul>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
const todos = ref([
{ id: 1, text: 'Learn Vue', completed: true },
{ id: 2, text: 'Build app', completed: false }
]);
const newTodo = ref('');
const filter = ref('all');
const allTodos = computed(() => todos.value);
const activeTodos = computed(() => {
return todos.value.filter(t => !t.completed);
});
const completedTodos = computed(() => {
return todos.value.filter(t => t.completed);
});
const filteredTodos = computed(() => {
switch (filter.value) {
case 'active': return activeTodos.value;
case 'completed': return completedTodos.value;
default: return allTodos.value;
}
});
const addTodo = () => {
if (!newTodo.value) return;
todos.value.push({
id: Math.max(...todos.value.map(t => t.id), 0) + 1,
text: newTodo.value,
completed: false
});
newTodo.value = '';
};
</script>
<style scoped>
.active {
font-weight: bold;
color: blue;
}
.completed {
text-decoration: line-through;
color: gray;
}
</style>
Computed vs Watch
const firstName = ref('Иван');
const lastName = ref('Петров');
const fullName = ref('');
// COMPUTED - использует для трансформаций данных
const computedFullName = computed(() => {
return firstName.value + ' ' + lastName.value;
});
// WATCH - использует для side effects (API запросы, логирование)
watch([firstName, lastName], ([first, last]) => {
console.log(`Пользователь изменил имя на ${first} ${last}`);
// Отправляем на сервер
updateUserProfile(first, last);
});
Важные правила
- Не изменяйте состояние в computed!
// ПЛОХО
const badComputed = computed(() => {
count.value++; // Побочный эффект!
return count.value;
});
- Не делайте async операции в computed!
// ПЛОХО
const badComputed = computed(async () => {
const data = await fetch('/api/data');
return data;
});
// ПРАВИЛЬНО - используйте watch
const data = ref(null);
watch(searchTerm, async (newSearch) => {
data.value = await fetch(`/api/search?q=${newSearch}`);
});
- Зависимости должны быть явными
// Vue автоматически отслеживает зависимости
const fullName = computed(() => {
// Vue видит что используются firstName и lastName
return firstName.value + ' ' + lastName.value;
}); // Пересчитается при изменении любого из них
Заключение
Computed в Vue - это:
- Кешированные вычисляемые свойства
- Автоматически пересчитываются при изменении зависимостей
- Идеальны для трансформаций и фильтрации данных
- Улучшают производительность (за счет кеша)
- Делают код чище и понятнее
- Альтернатива методам для данных (не для действий)
Используйте computed для всех вычислений данных - это best practice во Vue!