当前位置 博文首页 > 毛小星的博客:Vue中的$attrs和$listeners

    毛小星的博客:Vue中的$attrs和$listeners

    作者:[db:作者] 时间:2021-08-11 21:47

    Vue中的 $attrs 和 $listeners

    最近在研究 Vue 的组件库,之前也用过 $attrs 和 $listeners,官方文档描述的不太详细,也没有太好的例子,就没有深入的研究过这两个属性。最近生病在家,正好有时间好好研究一下 Vue 的高阶用法,写了几个 demo,下面我们来看看这两个属性到底有什么奥秘。

    $attrs

    我们先来看看官方文档的 api 描述是怎样描述 $attrs 的

    乍一看可能有点懵,下面我们结合下面的例子来看看 $attrs 的作用

    普通的 props 传值

    先来看看下面的例子,我自己写了一个双向绑定的 input 的组件,来验证一下。

    <!-- 父组件 -->
    <mxx-input v-model="user.username" type="text" foo="foo"></mxx-input>
    
    <!-- 子组件 -->
    <div>
      <input v-bind="$attrs" :type="type" :value="value">
    </div>
    
    // 子组件
    export default {
      name: 'MxxInput',
      props: {
        type: {
          type: String,
          default: 'text'
        },
        value: {
          type: String,
        }
      },
    }
    

    我们来看看子组件渲染的 DOM 结构

    我们会发现 foo 这个属性加在了 MxxInput 组件的最外层。
    如果你仔细看过 Vue 的官方文档的话,你会发现我们在使用 props 的方式向子组件传值的时候,子组件没有使用 props 作为接受的话,那么这个属性会自动设置在子组件的最外层的 HTML 标签上。如果是 class 和 style 的话,会合并最外层标签的 class 和 style。

    $attrs 的作用

    如果子组件中不想继承父组件传入的非 prop 属性,可以使用 inheritAttrs 禁用继承,然后通过 v-bind="$attrs" 把外部传入的非 prop 属性设置给希望的标签上。
    也就是你不想将没有设置 props 的属性自动继承到组件最外层的标签上那么你就需要将 inheritAttrs 这个属性设置为 false,但是这不会改变 class 和 style。

    // 子组件
    export default {
      name: 'MxxInput',
      inheritAttrs: false,
      props: {
        type: {
          type: String,
          default: 'text'
        },
        value: {
          type: String,
        }
      },
    }
    

    我们再来看看新的 DOM 结构

    我们可以看到最外层的 DOM 结构上没有 foo 这个属性了!
    而 $attrs 的值就是 { “foo”: “foo” },这样我们就可以利用这个特性实现组件的属性透传,更多有趣的用法,你可以自己去摸索一下。

    $listeners

    普通 $emit 传值

    我们先来看看如果我们想从一个组件向组件外传值,一种方法就是使用 $emit 向组件外暴露一个事件,然后通过事件方法的参数传值。

    <input
      type="text"
      v-bind="$attrs"
      @focus="$emit('focus', $event)"
      @input="$emit('input', $event)"
    >
    

    $listeners 的作用

    其实 $attrs 的一个作用就是可以批量向组件内传值,但是如果我们想批量向组件外传值怎么办呢,这个时候我们就可以使用 $listeners

    <input
      type="text"
      v-bind="$attrs"
      v-on="$listeners"
    >
    

    $listeners 实际就相当于上面的多个 $emit 了

    cs
    下一篇:没有了