Conforme mencionado por Chris Fritz (Vue.js Core Team Emeriti ) no VueCONF US 2019
se tivéssemos Kia .native
inserido e, em seguida, o elemento raiz da entrada base mudasse de uma entrada para uma etiqueta, de repente esse componente está quebrado e não é óbvio e, de fato, você pode nem mesmo pegá-lo imediatamente, a menos que tenha um teste realmente bom. Em vez disso, evitando o uso do .native
modificador que atualmente considero um antipadrão será removido no Vue 3, você poderá definir explicitamente que o pai pode se importar com o que os ouvintes de elemento são adicionados ...
Com o Vue 2
Usando $listeners
:
Portanto, se você estiver usando o Vue 2, uma opção melhor para resolver esse problema seria usar um lógica de invólucro totalmente transparente . Para isso, o Vue fornece uma $listeners
propriedade que contém um objeto de ouvintes sendo usados no componente. Por exemplo:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
e só precisamos adicionar v-on="$listeners"
aotest
componente como:
Test.vue (componente filho)
<template>
<div v-on="$listeners">
click here
</div>
</template>
Agora o <test>
componente é um invólucro totalmente transparente , o que significa que pode ser usado exatamente como um <div>
elemento normal : todos os ouvintes funcionarão sem o .native
modificador.
Demo:
Vue.component('test', {
template: `
<div class="child" v-on="$listeners">
Click here
</div>`
})
new Vue({
el: "#myApp",
data: {},
methods: {
testFunction: function(event) {
console.log('test clicked')
}
}
})
div.child{border:5px dotted orange; padding:20px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="myApp">
<test @click="testFunction"></test>
</div>
Usando $emit
método:
Também podemos usar o $emit
método para esse fim, o que nos ajuda a ouvir eventos de componentes filho no componente pai. Para isso, primeiro precisamos emitir um evento personalizado do componente filho, como:
Test.vue (componente filho)
<test @click="$emit('my-event')"></test>
Importante: Sempre use kebab-case para nomes de eventos. Para obter mais informações e demonstrações sobre esse ponto, consulte esta resposta: VueJS passando o valor calculado do componente para o pai .
Agora, precisamos apenas ouvir esse evento personalizado emitido no componente pai, como:
App.vue
<test @my-event="testFunction"></test>
Então, basicamente, em vez de v-on:click
ou a abreviação @click
, simplesmente usaremos v-on:my-event
ou apenas@my-event
.
Demo:
Vue.component('test', {
template: `
<div class="child" @click="$emit('my-event')">
Click here
</div>`
})
new Vue({
el: "#myApp",
data: {},
methods: {
testFunction: function(event) {
console.log('test clicked')
}
}
})
div.child{border:5px dotted orange; padding:20px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="myApp">
<test @my-event="testFunction"></test>
</div>
Com o Vue 3
Usando v-bind="$attrs"
:
O Vue 3 tornará nossa vida muito mais fácil de várias maneiras. Um dos exemplos disso é que ele nos ajudará a criar um invólucro transparente mais simples com muito menos configuração usando apenas v-bind="$attrs"
. Ao usar isso em componentes filhos, não apenas nosso ouvinte funcionará diretamente do pai, mas também qualquer outro atributo também funcionará como normalmente.<div>
.
Portanto, com relação a essa pergunta, não precisaremos atualizar nada no Vue 3 e seu código ainda funcionará bem, como <div>
é o elemento raiz aqui, e ele ouvirá automaticamente todos os eventos filhos.
Demo # 1:
const { createApp } = Vue;
const Test = {
template: `
<div class="child">
Click here
</div>`
};
const App = {
components: { Test },
setup() {
const testFunction = event => {
console.log("test clicked");
};
return { testFunction };
}
};
createApp(App).mount("#myApp");
div.child{border:5px dotted orange; padding:20px;}
<script src="//unpkg.com/vue@next"></script>
<div id="myApp">
<test v-on:click="testFunction"></test>
</div>
Mas para componentes complexos com elementos aninhados nos quais precisamos aplicar atributos e eventos ao main em <input />
vez do rótulo pai, podemos simplesmente usarv-bind="$attrs"
Demo # 2:
const { createApp } = Vue;
const BaseInput = {
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input v-bind="$attrs">
</label>`
};
const App = {
components: { BaseInput },
setup() {
const search = event => {
console.clear();
console.log("Searching...", event.target.value);
};
return { search };
}
};
createApp(App).mount("#myApp");
input{padding:8px;}
<script src="//unpkg.com/vue@next"></script>
<div id="myApp">
<base-input
label="Search: "
placeholder="Search"
@keyup="search">
</base-input><br/>
</div>
@click.native="testFunction"