# Mixins

# Fundamentos

Mixins distribuem funcionalidades reutilizáveis ​​para componentes Vue. Um objeto mixin pode conter quaisquer opções de componente. Quando um componente usa um mixin, todas as opções do mixin serão "misturadas" com as opções do próprio componente.

Exemplo:

// define um objeto mixin
const myMixin = {
  created() {
    this.hello()
  },
  methods: {
    hello() {
      console.log('olá do mixin!')
    }
  }
}

// definir um aplicativo que usa este mixin
const app = Vue.createApp({
  mixins: [myMixin]
})

app.mount('#mixins-basic') // => "olá do mixin!"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Mesclagem de Opções

Quando um mixin e o próprio componente contêm opções se sobrepondo, elas serão "mescladas" usando estratégias apropriadas.

Por exemplo, cada mixin pode ter sua própria função data. Cada uma delas será chamada, com os objetos retornados sendo mesclados. As propriedades dos próprios dados do componente terão prioridade em caso de conflitos.

const myMixin = {
  data() {
    return {
      message: 'olá',
      foo: 'abc'
    }
  }
}

const app = Vue.createApp({
  mixins: [myMixin],
  data() {
    return {
      message: 'Tchau',
      bar: 'def'
    }
  },
  created() {
    console.log(this.$data) // => { message: "Tchau", 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

Gatilhos de funções com o mesmo nome são mesclados em um Array para que todos sejam chamados. Os gatilhos do Mixin serão chamados antes dos próprios gatilhos do componente.

const myMixin = {
  created() {
    console.log('gatilho do mixin chamado')
  }
}

const app = Vue.createApp({
  mixins: [myMixin],
  created() {
    console.log('gatilho do componente chamado')
  }
})

// => "gatilho do mixin chamado"
// => "gatilho do componente chamado"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Opções que esperam valores em objeto, por exemplo methods, components e directives, serão mescladas no mesmo objeto. As opções do componente terão prioridade quando houver chaves conflitantes nestes objetos:

const myMixin = {
  methods: {
    foo() {
      console.log('foo')
    },
    conflicting() {
      console.log('do mixin')
    }
  }
}

const app = Vue.createApp({
  mixins: [myMixin],
  methods: {
    bar() {
      console.log('bar')
    },
    conflicting() {
      console.log('de si mesmo')
    }
  }
})

const vm = app.mount('#mixins-basic')

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "de si mesmo"
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

# Mixin Global

Você também pode aplicar um mixin globalmente para um aplicativo Vue:

const app = Vue.createApp({
  myOption: 'Olá!'
})

// injetar um manipulador para a opção personalizada `myOption`
app.mixin({
  created() {
    const myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

app.mount('#mixins-global') // => "Olá!"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Use com cuidado! Depois de aplicar um mixin globalmente, ele afetará cada instância de componente criada posteriormente no aplicativo fornecido (por exemplo, componentes filhos):

const app = Vue.createApp({
  myOption: 'Olá!'
})

// injetar um manipulador para a opção personalizada `myOption`
app.mixin({
  created() {
    const myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

// adicione myOption também ao componente filho
app.component('test-component', {
  myOption: 'Olá do componente!'
})

app.mount('#mixins-global')

// => "Olá!"
// => "Olá do componente"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Na maioria dos casos, você só deve usá-lo para manipulação de opções personalizadas, conforme demonstrado no exemplo acima. Também é uma boa ideia entregá-los como Plugins para evitar aplicação duplicada.

# Estratégias de Mesclagem de Opções Personalizadas

Quando as opções personalizadas são mescladas, elas usam a estratégia padrão que substitui o valor existente. Se você deseja que uma opção personalizada seja mesclada usando uma lógica personalizada, você precisa anexar uma função à app.config.optionMergeStrategies:

const app = Vue.createApp({})

app.config.optionMergeStrategies.customOption = (toVal, fromVal) => {
  // retorna valorMesclado (mergedVal)
}
1
2
3
4
5

A estratégia de mesclagem recebe o valor dessa opção definida nas instâncias pai e filho como o primeiro e segundo argumentos, respectivamente. Vamos tentar verificar o que temos nesses parâmetros quando usamos um mixin:

const app = Vue.createApp({
  custom: 'Olá!'
})

app.config.optionMergeStrategies.custom = (toVal, fromVal) => {
  console.log(fromVal, toVal)
  // => "Tchau!", undefined
  // => "Olá", "Tchau!"
  return fromVal || toVal
}

app.mixin({
  custom: 'Tchau!',
  created() {
    console.log(this.$options.custom) // => "Olá!"
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Como você pode ver, no console temos toVal e fromVal impresso primeiro no mixin e depois no app. Nós sempre retornamos fromVal se existir, é por isso que this.$options.custom está configurado para hello! no final. Vamos tentar mudar uma estratégia para sempre retornar um valor da instância filha:

const app = Vue.createApp({
  custom: 'Olá!'
})

app.config.optionMergeStrategies.custom = (toVal, fromVal) => toVal || fromVal

app.mixin({
  custom: 'Tchau!',
  created() {
    console.log(this.$options.custom) // => "Tchau!"
  }
})
1
2
3
4
5
6
7
8
9
10
11
12

# Desvantagens

No Vue 2, os mixins eram a principal ferramenta para abstrair partes da lógica de componentes em blocos reutilizáveis. No entanto, eles têm alguns problemas:

  • Mixins são propensos à conflitos: como as propriedades de cada mixin são mescladas no mesmo componente, você ainda precisa conhecer todos os outros mixins para evitar conflitos de nome de propriedade e para depuração.

  • As propriedades parecem surgir do nada: se um componente usa vários mixins, não é necessariamente óbvio quais propriedades vieram de cada mixin.

  • Reutilização é limitada: não podemos passar nenhum parâmetro ao mixin para alterar sua lógica, o que reduz sua flexibilidade em termos de abstração da lógica.

Para resolver esses problemas, adicionamos uma nova maneira de organizar o código por questões lógicas: A API de Composição.