# Примеси
# Основы
Примеси (mixins) — инструмент для повторного использования кода в компонентах Vue. В объекте примеси могут содержаться любые опции компонентов. При использовании примеси в компоненте все её опции будут «подмешиваться» к опциям компонента.
Пример:
// объявляем объект примеси
const myMixin = {
created() {
this.hello()
},
methods: {
hello() {
console.log('привет из примеси!')
}
}
}
// объявляем приложение, которое использует примесь
const app = Vue.createApp({
mixins: [myMixin]
})
app.mount('#mixins-basic') // => "привет из примеси!"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Слияние опций
В случаях, когда примесь и компонент содержат одинаковые опции, они будут объединяться определённым образом.
Например, каждая примесь может иметь свою собственную функцию data
. Каждая из них будет вызвана, а возвращённые объекты объединены. Свойства из data
компонента при этом будут иметь приоритет в случае конфликта.
const myMixin = {
data() {
return {
message: 'hello',
foo: 'abc'
}
}
}
const app = Vue.createApp({
mixins: [myMixin],
data() {
return {
message: 'goodbye',
bar: 'def'
}
},
created() {
console.log(this.$data) // => { message: "goodbye", foo: "abc", bar: "def" }
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Функции хуков жизненного цикла объединяются в массив и все они будут вызваны. Причём хуки примеси будут вызываться перед хуками самого компонента.
const myMixin = {
created() {
console.log('вызван хук из примеси')
}
}
const app = Vue.createApp({
mixins: [myMixin],
created() {
console.log('вызван хук из компонента')
}
})
// => "вызван хук из примеси"
// => "вызван хук из компонента"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Опции, значения которых будут объектами, такие как methods
, components
и directives
будут объединены. В случае конфликтов приоритет будет у опций компонента:
const myMixin = {
methods: {
foo() {
console.log('foo')
},
conflicting() {
console.log('из примеси')
}
}
}
const app = Vue.createApp({
mixins: [myMixin],
methods: {
bar() {
console.log('bar')
},
conflicting() {
console.log('из самого компонента')
}
}
})
const vm = app.mount('#mixins-basic')
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "из самого компонента"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Глобальные примеси
Примесь можно добавить глобально для всего Vue приложения:
const app = Vue.createApp({
myOption: 'hello!'
})
// внедрение обработчика для пользовательской опции `myOption`
app.mixin({
created() {
const myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
app.mount('#mixins-global') // => "hello!"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Используйте данную возможность с ОСТОРОЖНОСТЬЮ! Глобальная примесь оказывает влияние на все экземпляры компонентов, создаваемые в дальнейшем в этом приложении (например, во всех дочерних компонентах):
const app = Vue.createApp({
myOption: 'привет!'
})
// внедрение обработчика для пользовательской опции `myOption`
app.mixin({
created() {
const myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})
// добавляем myOption также в дочерний компонент
app.component('test-component', {
myOption: 'привет из компонента!'
})
app.mount('#mixins-global')
// => "привет!"
// => "привет из компонента!"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
В большинстве случаев стоит их использовать только для обработки пользовательских опций, как в примере выше. Хорошей идеей будет их вынесение в виде плагинов, что позволит избежать дублирования кода.
# Пользовательские стратегии слияния опций
При слиянии пользовательских опций по умолчанию применяется стратегия, в которой одни значения просто заменяются другими. Если нужно применить пользовательскую логику при слиянии, то потребуется переопределить функцию app.config.optionMergeStrategies
:
const app = Vue.createApp({})
app.config.optionMergeStrategies.customOption = (toVal, fromVal) => {
// возвращаем значение после слияния
}
2
3
4
5
Стратегия слияния получает значения опции из родительского и дочернего экземпляров, в качестве первого и второго аргументов соответственно. Посмотрим, что приходит в этих параметрах при использовании примеси:
const app = Vue.createApp({
custom: 'привет!'
})
app.config.optionMergeStrategies.custom = (toVal, fromVal) => {
console.log(fromVal, toVal)
// => "пока!", undefined
// => "привет!", "пока!"
return fromVal || toVal
}
app.mixin({
custom: 'пока!',
created() {
console.log(this.$options.custom) // => "привет!"
}
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Как можно увидеть, в консоли выводятся значения toVal
и fromVal
сначала из примеси, а затем из app
. Сейчас при наличии будет возвращаться fromVal
, поэтому в результате this.$options.custom
будет со значением привет!
. Переделаем стратегию слияния на «всегда возвращать значение дочернего экземпляра»:
const app = Vue.createApp({
custom: 'привет!'
})
app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal
app.mixin({
custom: 'пока!',
created() {
console.log(this.$options.custom) // => "пока!"
}
})
2
3
4
5
6
7
8
9
10
11
12
# Недостатки
Во Vue 2 примеси были основным инструментом для абстрагирования кусков логики компонентов в переиспользуемые части. Но у них есть несколько серьёзных проблем:
Примеси приводят к конфликтам: поскольку свойства каждой примеси объединяются в одном компоненте, всё равно потребуется знать обо всех примесях во избежание конфликта имён свойств и в целях отладки.
Будет казаться, что свойства появляются из ниоткуда: если компонент использует несколько примесей, то не всегда очевидно из какой примеси какие свойства пришли.
Возможность переиспользования ограничена: примесям нет возможности передавать какие-либо параметры для управления логикой её работы, что снижает гибкость с точки зрения абстрагированной логики.
В целях их решения был представлен новый способ организации кода: Composition API.