正如Chris Fritz(Vue.js核心团队Emeriti)在VueCONF US 2019中提到的那样
如果我们让Kia输入.native
,然后基本输入的根元素突然从输入更改为标签,则此组件损坏了,这并不明显,实际上,除非您进行了很好的测试,否则您可能不会立即抓住它。通过避免使用目前我认为反模式将在Vue 3中删除的.native
修饰符,您可以显式定义父级可能关心添加到哪些元素侦听器...
与Vue 2
使用$listeners
:
因此,如果您使用的是Vue 2,则解决此问题的更好选择是使用完全透明的包装器逻辑。为此,Vue提供了一个$listeners
属性,其中包含在组件上使用的侦听器的对象。例如:
{
focus: function (event) { }
input: function (value) { },
}
然后我们只需要添加v-on="$listeners"
到test
像这样组件:
Test.vue(子组件)
<template>
<div v-on="$listeners">
click here
</div>
</template>
现在,该<test>
组件是一个完全透明的包装器,这意味着它可以像普通<div>
元素一样完全使用:所有侦听器都可以工作,而无需使用.native
修饰符。
演示:
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>
我们也可以$emit
为此使用方法,它有助于我们侦听父组件中的子组件事件。为此,我们首先需要从子组件发出一个自定义事件,例如:
Test.vue(子组件)
<test @click="$emit('my-event')"></test>
重要说明:始终使用kebab-case作为事件名称。有关更多信息和演示,请查看以下答案:VueJS将计算值从组件传递给父对象。
现在,我们只需要在父组件中监听此发出的自定义事件,例如:
应用程序
<test @my-event="testFunction"></test>
因此,基本上将代替v-on:click
或速记,@click
我们将仅使用v-on:my-event
或@my-event
。
演示:
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>
与Vue 3
使用v-bind="$attrs"
:
Vue 3将在许多方面使我们的生活变得更加轻松。其中一个示例是,它将帮助我们仅通过使用很少的配置来创建一个更简单的透明包装器v-bind="$attrs"
。通过在子组件上使用此属性,不仅我们的侦听器将直接在父组件上工作,而且其他任何属性也将像正常情况<div>
下一样工作。
因此,关于这个问题,我们将不需要更新Vue 3中的任何内容,并且您的代码仍然可以正常工作,就像<div>
这里的root元素一样,它将自动侦听所有子事件。
演示#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>
但是对于带有嵌套元素的复杂组件,我们需要将属性和事件应用于main<input />
而不是parent标签,我们可以简单地使用v-bind="$attrs"
演示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"