Компонент: скрипт Options API
Мы познакомились с устройством шаблона компонента. Теперь перейдём к блоку script — месту, где сосредоточена логика компонента.
Vue предоставляет два подхода к написанию компонентов:
- с помощью Options API,
- с помощью Composition API.
В этой статье мы рассмотрим первый подход.
Options API хорошо знаком разработчикам, работавшим с Vue 2. С его помощью логика компонента описывается через объект параметров, включающий такие свойства, как data, computed, methods и другие.
<script>
import Component1 from './component/Component1.vue'
export default {
name: 'TestComponent',
components: {
Component1
},
data () {
return {
tasks: [],
filters: {
status: '',
}
...
}
},
computed: {
filteredTasks () {
if (!this.filters.status) {
return this.tasks
} else {
return this.tasks.filter(task => task.status === this.filters.status)
}
}
},
watch: {
filters: {
immediate: true,
deep: true,
handler (newFilters, oldFilters) {
console.log('Filters have been changed!')
}
}
},
methods: {
getTasks () {
this.tasks = … // API call to get new tasks
}
}
}
</script>
name
Свойство name применяется при отладке приложения. Во Vue devtools компоненты отображаются в виде дерева, используя имена, указанные в name.
components
Свойство components служит для регистрации дочерних компонентов. Для этого нужно импортировать компонент, указать его в опции components и затем использовать в шаблоне.
Длинная нотация:
import Component1 from './component/Component1.vue'
export default {
components: {
Component1: Component1
}
}
Сокращённая запись:
import Component1 from './component/Component1.vue'
export default {
components: {
Component1
}
}
data
data — функция, возвращающая объект с данными экземпляра Vue. При создании экземпляра Vue все свойства из data включаются в систему реактивности — свойства верхнего уровня становятся доступны через this на экземпляре компонента.
В template нет необходимости использовать this, (кроме динамических свойств), так как шаблон по умолчанию ссылается на экземпляр компонента.
При изменении значений свойств данные в шаблоне обновляются автоматически благодаря реактивности.
Опция data в однофайловом компоненте Vue.js должна быть именно функцией, возвращающей объект. Благодаря этому каждый экземпляр компонента получает собственное независимое состояние. Если определить data как простой объект, все экземпляры будут разделять одни и те же данные.
Методы определения вычисляемых свойств и хуки жизненного цикла создаются единожды, но исполняются для каждого экземпляра компонента.
methods
methods — методы, которые подмешиваются к экземпляру Vue. Их можно вызывать напрямую из экземпляра или использовать в директивах.
this внутри методов указывает на экземпляр Vue. К методам можно обращаться из других методов, хуков жизненного цикла и шаблона. При вызове из методов и хуков используется this, например this.getTasks(). В шаблоне this не указывается, например @click="getTasks". При вызове метода без параметров круглые скобки в шаблоне тоже можно опустить.
computed
computed — вычисляемые свойства, являющиеся производными от других данных. В примере выше filteredTasks зависит от tasks и filters, обеспечивая постоянный доступ к отфильтрованным задачам.
Computed-свойства реактивны: при каждом обновлении массива задач или фильтров filteredTasks автоматически пересчитывается.
computed записывается как функция, однако используется как обычное свойство — this.filteredTasks — без круглых скобок.
Можно было бы оформить filteredTasks как метод, вызывая его с круглыми скобками. Однако помимо удобства записи без скобок у вычисляемых свойств есть ключевое преимущество перед методами: они кешируются на основе своих реактивных зависимостей. Если исходные данные не изменились, повторное обращение к computed-свойству вернёт закешированный результат без повторного выполнения функции.
Обратите внимание: следующее вычисляемое свойство никогда не обновится, поскольку Date.now() не является реактивной зависимостью:
computed: {
now: function () {
return Date.now()
}
}
Метод, напротив, будет выполняться заново при каждом обращении.
Зачем необходимо кеширование, и почему не использовать просто метод?
В примере с filteredTasks выполняется фильтрация задач по статусу — один проход по массиву. Но представьте ситуацию с тысячами задач и множеством фильтров. Вариантов усложнения вычислений масса, и операция может оказаться весьма затратной. В таких случаях кеширование становится мощным инструментом оптимизации.
Что использовать
Вычисляемые свойства — когда обновление значения требуется лишь при изменении реактивных зависимостей.
Метод — когда значение необходимо вычислять заново при каждом обращении.
Сеттеры вычисляемых свойств
По умолчанию вычисляемые свойства доступны только для чтения. Напрямую присвоить им новое значение нельзя — при создании свойства мы задаём логику вычисления и при использовании обращаемся к результату.
Если требуется возможность вручную обновлять вычисляемое свойство, для него можно определить сеттер. Рассмотрим на примере с задачами:
computed: {
filteredTasks () {
get () {
if (!this.filters.status) {
return this.tasks
} else {
return this.tasks.filter(task => task.status === this.filters.status)
}
},
set ({ tasks, filters }) {
this.tasks = tasks
this.filters = filters
}
}
}
В качестве параметра передаётся значение для обновления зависимостей вычисляемого свойства. Параметр меняется — свойство пересчитывается.
Обращение к сеттеру: this.filteredTasks = { tasks, filters }. Если сеттер не определён, подобное присвоение вызовет ошибку.
Важный момент о computed
Computed предназначен исключительно для получения результата вычислений. Внутри не должно быть побочных эффектов. Это всегда синхронная операция — она не изменяет другие свойства и не генерирует события. Только вычисление результата.
Как быть, если при изменении свойства нужно инициировать событие или вызвать определённые методы? Как справиться с асинхронными операциями? Для этого во Vue предусмотрен watch.
Watch
Watch — механизм наблюдения за изменениями указанного свойства, срабатывающий при каждом его обновлении. Это объект, ключами которого являются выражения для отслеживания, а значениями — колбэки, вызываемые при изменении. Значениями также могут быть строки с именами методов или объекты с дополнительными опциями.
Экземпляр Vue выполнит $watch() для каждого ключа объекта при своей инициализации. Ключи (выражения для наблюдения) — это имена свойств компонента, за которыми ведётся отслеживание.
Варианты записи watch
Наиболее распространённый вариант — запись в виде функции:
watch: {
filters (newFilters, oldFilters) {
console.log('Filters have been changed!')
}
}
Запись в виде объекта с опциями:
watch: {
filters: {
immediate: true,
deep: true,
handler (newFilters, oldFilters) {
console.log('Filters have been changed!')
}
}
}
Сокращённая запись с указанием имени метода (используется редко):
watch: {
filters: 'handleFilters' // указываем название метода-обработчика
}
Параметры функции
Функция принимает два параметра: новое значение после изменения и предыдущее значение — это удобно, когда необходимо сравнить данные до и после обновления.
Опция deep
Для отслеживания изменений во вложенных объектах необходимо указать deep: true в параметрах. Для массивов это не требуется.
Опция immediate
При значении immediate: true колбэк будет вызван сразу после начала наблюдения с текущим значением. Это полезно, когда нужно выполнить логику ещё до первого изменения свойства.
handler
Это имя метода, используемое при объектном синтаксисе. Он выступает в роли функции-наблюдателя.
Watch, в отличие от computed, может быть асинхронным. Поэтому в нём допускается использование конструкций
async/awaitиthen/catch.Watch — отличное место для запроса данных с сервера, например при изменении
idили других параметров.