# Примеси

# Основы

Примеси (mixins) — инструмент повторного использования кода в компонентах Vue. Объект примеси может содержать любые опции компонентов. При использовании примеси в компоненте все её опции «подмешиваются» к опциям компонента.

Пример:

// определяем объект примеси
const myMixin = {
  created() {
    this.hello()
  },
  methods: {
    hello() {
      console.log('привет из примеси!')
    }
  }
}

// определяем приложение, которое использует примесь
const app = Vue.createApp({
  mixins: [myMixin]
})

app.mount('#mixins-basic') // => "привет из примеси!"
1
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" }
  }
})
1
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('вызван хук из компонента')
  }
})

// => "вызван хук из примеси"
// => "вызван хук из компонента"
1
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() // => "из самого компонента"
1
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!"
1
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')

// => "привет!"
// => "привет из компонента!"
1
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) => {
  // возвращаем объединённое значение
}
1
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) // => "привет!"
  }
})
1
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) // => "пока!"
  }
})
1
2
3
4
5
6
7
8
9
10
11
12

# Предостережения

Во Vue 2 примеси были основным инструментов для абстрагирования части логики компонентов в многократно переиспользуемые куски. Но у них есть несколько проблем:

  • Примеси приводят к конфликтам: поскольку свойства каждой примеси объединяются в одном компоненте, всё равно потребуется знать обо всех свойствах для избежания конфликта имён свойств и в целях отладки.

  • Возможность переиспользования ограничена: примесям нет возможности передавать какие-либо параметры для управления логикой её работы, что снижает гибкость с точки зрения абстрагированной логики.

Для решения этих проблем был добавлен новый способ организации кода: Composition API.

Deployed on Netlify.
Последнее обновление: 2020-10-31, 22:14:13 UTC