VUE查漏补缺(一): $listener跟$attrs的使用

  • Post author:
  • Post category:vue


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吧….

逃了…



版权声明:本文为m0_38005587原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。