浅谈vue巧妙的组件封装($attrs,$listeners,插槽)

无论是使用element还是antd还是vuetify,大家都喜欢在它们的基础上去封装一些组件,去完成自己想要的效果,我们在封装组件的时候常常会遇到一些可变性,然后就需要我们去修改组件内的东西,以至于组件越改越乱,那么封装组件大家都会,这里我就想说一下我的小tip

$attrs,$listeners这是一个好东西哦 相信大家也都知道并且用过,它们分别可获取到上级中没有在props中声明过的属性和方法,下面我将依次举例来表达我的用法

来看一个基础的,当基于element封装一个按钮Btn.vue

<Btn />即可使用

<el-button 
  v-bind="$attrs" 
  v-on="$listeners" 
  type="primary" 
>
  按钮
</el-button>

当多层组件嵌套时,一层一层传参太过麻烦,这时可以给层级组件都绑定v-bind="$attrs",即可在最底层组件中使用到最高层组件的属性;其实通过inject,provide也可以实现多层传参,但是也是需要在js代码中定义才能使用,所以总觉得不方便

// one.vue
<div>
    这是第一个组件
    <two data="hello"/>
</div>


// two.vue
<div>
    这是第二个组件
    <three v-bind="$attrs"/>
</div>


// three.vue
<div>
    这是第三个组件{{$attrs.data}}
</div>

下面还要说一说如何巧用$listeners,这个是可以传递方法的,以下这种做法方法的传递就很清晰了

// one.vue
<div>
    这是第一个组件
    <two @changeOne="changeThree"/>
</div>
changeThree(val){
    console.log(val); // 第三个组件发生改变了
}

// two.vue
<div>
    这是第二个组件
    <three v-on="$listeners"/>
</div>


// three.vue
<div>
    这是第三个组件
</div>
this.$listeners.changeOne('第三个组件发生改变了')

父组件传递一个变量到子组件,子组件绑定事件,这样不需要动用子组件即可给子组件绑定事件,并且把子组件的this放出来,就可以操作子组件内的一切了

// Btn.vue
<el-button 
  v-bind="$attrs" 
  v-on="$attrs.listeners(this)"
  type="primary" 
>
  按钮
</el-button>


// Home.vue
<Btn :listeners="listeners"/>
listeners: function(self){
  console.log(self)
  return {
    click:function(data){
      console.log(data);
     }
  }
}

所以我们可以把所有要穿的属性方法统一定义,如下

param:{    
    getAttrs: ()=>{
      return {
        clearable:true,
        multiple:true
      }
    },
    getListeners: (data)=>{
      console.log(data)
      return {
        change:(value)=>{
          console.log(value);
        }
      }
    }
}

// 使用
v-bind="param.getAttrs"
v-on="param.getListeners(_self)"

说完了属性方法,接下来就说一说插槽,个人建议封装的组件都留个插槽出去,方便使用的人自定义

// Btn.vue
<el-button>
  <slot></slot>
</el-button>


// Home.vue
<Btn>新增</Btn>

具名插槽

// Btn.vue
<el-button>
  <slot name="btnName"></slot>
</el-button>


// Home.vue
<Btn>
    <template slot="btnName">
        按钮
    </template>
</Btn>

作用域插槽

// Btn.vue
<el-button>
  <slot name="btnName" :num="num"></slot>
</el-button>


// Home.vue
<Btn>
    <template  v-slot:btnName="{num}">
        按钮{{num}}
    </template>
</Btn>

// 当组件内没有传参时你还可以设置默认值
<Btn>
    <template  v-slot:btnName="{num = 1}">
        按钮{{num}}
    </template>
</Btn>


// 这样你就不用动组件里的内容就可以在外面自定义展示效果了

<todo-list :todos="todos">
  <template v-slot:item="{ item }">
    <span v-if="item.select">{{ todo.text }}</span>
  </template>
</todo-list>

动态插槽,如下举例可以很大程度的减少template的重复代码

    <el-table
      :columns="columns"
      :data="data"
		<template
		   v-for="item in templateSlot"
           :key="item"
		   v-slot:[item]="scope"
		 >
		   {{ scope.scope.row[item] }}
		 </template>
	</el-table>
	
	templateSlot: ['name', 'sex']

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值