Come menzionato da Chris Fritz (Vue.js Core Team Emeriti ) in VueCONF US 2019
se avessimo inserito Kia .native
e poi l'elemento radice dell'input di base fosse cambiato da un input a un'etichetta all'improvviso questo componente è rotto e non è ovvio e in effetti, potresti anche non prenderlo subito se non hai un test davvero buono. Invece, evitando l'uso del .native
modificatore che attualmente considero un anti-pattern verrà rimosso in Vue 3 , sarai in grado di definire esplicitamente che al genitore potrebbe interessare quali elementi listener sono aggiunti a ...
Con Vue 2
Utilizzando $listeners
:
Pertanto, se si utilizza Vue 2, un'opzione migliore per risolvere questo problema sarebbe quella di utilizzare una logica wrapper completamente trasparente . Per questo Vue fornisce una $listeners
proprietà contenente un oggetto di listener utilizzato sul componente. Per esempio:
{
focus: function (event) { /* ... */ }
input: function (value) { /* ... */ },
}
e quindi dobbiamo solo aggiungere v-on="$listeners"
al test
componente come:
Test.vue (componente figlio)
<template>
<div v-on="$listeners">
click here
</div>
</template>
Ora il <test>
componente è un wrapper completamente trasparente , il che significa che può essere utilizzato esattamente come un normale <div>
elemento: tutti gli ascoltatori funzioneranno, senza il .native
modificatore.
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>
Utilizzando il $emit
metodo:
Possiamo anche utilizzare il $emit
metodo per questo scopo, che ci aiuta ad ascoltare gli eventi dei componenti figlio nel componente padre. Per questo, dobbiamo prima emettere un evento personalizzato dal componente figlio come:
Test.vue (componente figlio)
<test @click="$emit('my-event')"></test>
Importante: utilizzare sempre il caso kebab per i nomi degli eventi. Per ulteriori informazioni e demo che registrano questo punto, controlla questa risposta: VueJS passa il valore calcolato dal componente al genitore .
Ora, dobbiamo solo ascoltare questo evento personalizzato emesso nel componente padre come:
App.vue
<test @my-event="testFunction"></test>
Quindi, fondamentalmente anziché v-on:click
o la stenografia @click
useremo semplicemente v-on:my-event
o semplicemente @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>
Con Vue 3
Utilizzando v-bind="$attrs"
:
Vue 3 renderà la nostra vita molto più semplice in molti modi. Uno degli esempi è che ci aiuterà a creare un wrapper trasparente più semplice con una configurazione molto minore semplicemente usando v-bind="$attrs"
. Usando questo sui componenti figlio non solo il nostro listener funzionerà direttamente dal genitore ma anche qualsiasi altro attributo funzionerà come se fosse un normale <div>
.
Quindi, rispetto a questa domanda, non avremo bisogno di aggiornare nulla in Vue 3 e il tuo codice continuerà a funzionare bene come <div>
l'elemento radice qui e ascolterà automaticamente tutti gli eventi figlio.
Demo n. 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>
Ma per componenti complessi con elementi nidificati in cui è necessario applicare attributi ed eventi a main <input />
anziché all'etichetta principale, possiamo semplicemente usarev-bind="$attrs"
Demo n. 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"