vue中提供了很多很好用的语法糖给我们使用,其中获取原生事件.native就是一种很好的方式:
但是,正如VUE官方文档所说的:
不过在你尝试监听一个类似
<input>
的非常特定的元素时,这并不是个好主意。比如上述
<base-input>
组件可能做了如下重构,所以根元素实际上是一个
<label>
元素
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
那么怎么解决这个问题呢,由于文档介绍的不是很清晰,首先我们来看看$listeners到底是个什么:
$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=”$listeners” 传入内部组件——在创建更高层次的组件时非常有用。
$attrs
包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建更高层次的组件时非常有用。
接下来,我们研究怎么用;
在Vue中,父子组件通信有三种方式:
1. props , $emit 跟v-on方法的绑定;适合简单的父子组件的通信;
关于如何理解$emit跟v-on的问题,说白了是一个发布订阅者模式;不明白去官网:
https://github.com/vuejs/vue/blob/11b7d5dff276caa54da3ef5b52444c0e2c5bbf41/src/core/instance/events.js
2.vue中的bus传值;
import Vue from "vue"
// 将bus挂载到原型上
const bus = {
install(Vue,options){
Vue.prototype.$bus = new Vue()
}
};
Vue.use(bus);
值得一提的是,bus也是一个Vue实例;
挂载后,如何使用起来呢?
监听者:
created(){
this.$bus.$on("test",function () {
alert(1)
})
}
发布者:
handleClick(){
this.$bus.$emit("test");
}
第三个是使用Vuex方式了,去官网看看
第四个,使用$attrs跟$listeners;
例如,我有三个组件Father,Me,Son,两两之间是父子关系,Father想直接跟Son说话啊,但是必须要经过Me这个中间人;
这个时候,$attrs就起作用了,你可以直接在Me它自己的子组件Son中将Father传给Me非props值,原封不动地再次传给Son,具体怎么操作呢?
这是Father组件,传了一个placeholder值,注意不是props的形式来传递:
<div id="app">
{{value}}
<wrapper v-on:focus="onFocus" v-bind:value="value" v-on:input="onFocus" placeholder="请输入">
</wrapper>
</div>
这是Me组件
Vue.component("Wrapper",{
template:`
<div>
<son v-bind="$attrs" v-on="$listeners"></son>
</div>
`
});
它将父组件传给它的非props值原封不动的传给了子组件,记住是v-on=”$listeners”,而不是v-on:的方法哦;
接下来我们来看Son组件:
Vue.component("son",{
template:`
<div>
<button @click="handleClick">333</button>
<input type="text" v-bind="$attrs" v-on="rewriteListener">
</div>
`,
...
也是直接用$attrs值来获取Me给它传的值,不信你看此时的place-holder:
好了,可以直接爷爷给孙子传值了,但是孙子如何通知爷爷呢?
首先还是照葫芦画猫,让Me将$listeners原封不动的传给Son
<son v-bind="$attrs" v-on="$listeners"></son>
由于爷爷绑定的值是绑定v-on:input的形式去绑定的,这样子孙子继承下来也触发不了事件,我们需要在son组件改造一下;
写法如下:
computed: {
rewriteListener() {
const vm = this;
return Object.assign({},
this.$listeners,
{
input: function (event) {
vm.$emit("input", event.target.value)
}
}
)
}
}
重写了$listeners,最后用v-bind绑定到原生事件去,让孙子去触发爷爷的事件了;
<input type="text" v-bind="$attrs" v-on="rewriteListener">
这种方法,一般使用于不那么大型的项目,但是又不想被$emit跟props搞到头晕脑胀;
当然bus方法也是不错的;
实在省麻烦还是用Vuex吧….
逃了…