阅读 298

Vue封装三方库的运用: $attrs + $listeners

分类是学习的本质,时间分类是时间管理,知识分类是知识管理,资源分类是项目管理~~

是什么

在封装一个插件时,大家往往会先从使用插件者能传递的数据,开始设计插件的入口,封装vue组件同理。vue中封装一个组件,组件上dom绑定传递的各种东西,除class style外,在vue里本质上只有以下三种

  • Prop:子组件内声明了接受props,父传的属性就是Prop
  • $attrs:除Prop外,所有传递的属性 (v-bind监听)
  • $listeners:除上面两者,剩下的就是事件啦~ (v-on监听)

如何用

下面简单demo封装一个三方组件,我们希望首先是继承这个三方组件的所有事件,然后再通过控制数据流入口,可以自定义各种功能。下面看看如何使用$attrs ,$listeners完整继承

  • 可以先用inheritAttrs: false关闭自动继承1,从而可以获得父级传下来的所有数据分配权。可以简单理解为父级传下来的数据为如下结构
    {
    	$props:{},
    	$attrs:{},
    	$listeners:{}
    }复制代码
  • props我们声明时会对其中属性进行分配,那么就剩下分配$listeners和$attrs
  • 投砖引玉:下面demo,我直接把所有属性、事件沉淀到三方库组件上,这样就变相继承了所有三方的配置
    // 使用组件代码
    <AntButton type="danger" @click="test"  size="large" msg="Welcome to Your Vue.js App"/>复制代码
    //封装AntButton,a-button为ant-design-vue三方库中组件
    <template lang="html">
        <div class="button-wrap">
            <a-button v-bind="$attrs" v-on="$listeners">{{msg}}</a-button>
        </div>
    </template>
    
    <script>
    export default {
      inheritAttrs: false,
      props: {
        msg: {
          type: String,
          default: '输入内容'
        }
      },
      created () {
        console.log(this.$attrs, 'button-$attrs')
        console.log(this.$listeners, 'button-$listeners')
      }
    }
    </script>复制代码

处理 v-model

v-model本质是传递一个prop + 监听表单事件2。我们可以用如下方式进行向下沉淀数据

<template lang="html">
    <div class="input-wrap">
         <a-input  v-bind="$attrs" v-on="inputListeners"  placeholder="Basic usage"/>
    </div>
</template>

<script>
export default {
  inheritAttrs: false,
  props: ['value'],
  computed: {
    inputListeners: function () {
      var vm = this
      return Object.assign({},
        // 我们从父级添加所有的监听器
        this.$listeners,
        // 然后我们添加自定义监听器,
        // 或覆写一些监听器的行为
        {
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            // 默认会把整个event冒泡上去,也是v-model实现成功
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  }
}
</script>
	复制代码

当然如果去掉自定义的表单事件监听,也是可以实现的,父级将会得到整个InputEvent

//注释这段 
{
          // 这里确保组件配合 `v-model` 的工作
          input: function (event) {
            // 默认会把整个event冒泡上去,也是v-model实现成功
            vm.$emit('input', event.target.value)
          }
  }复制代码


关于 $attrs + $listeners的运用场景,这里只能简单抛转引玉一下。不过明晰一个v-model,v-on , v-bind其实本质是在做什么,是件很有必要的事。在数据驱动视图的逻辑里,我们应该始终盯住我们的数据流,一切皆对象,哪个对象哪个key变了,在IT的世界里,清晰本质,将会更有创造力。(以上只谈运用精通,不谈理论精通~)

  1. inheritAttrs ↩︎
  2. 自定义组件v-model ↩︎




关注下面的标签,发现更多相似文章
评论