曾经,我在封装ui库的组件时都是这样的:
然后为了能够使代码更简洁,同时能在父组件随意传入自定义的属性,我设想过使用jsx,因为我见过公司有react项目,里面使用了扩展运算符来传入元素的属性,可惜当时试了一下在vue的render里面这么用结果失败了。直到今天我在浏览文章的时候偶然发现了一个在vue里面我从未使用过的知识点:inheritAttrs,官方文档上是这样介绍的:
如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false
...这尤其适合配合实例的$attrs
property使用,该 property 包含了传递给一个组件的 attribute 名和 attribute 值,有了 inheritAttrs: false
和 $attrs
,你就可以手动决定这些 attribute 会被赋予哪个元素。
之后我查阅资料发现简单来说就是通过设置inheritAttrs: false
使得最终的html元素不会继承父组件传入的属性,然后再给子组件设置v-bind直接绑定父组件传入的属性,这样就可以做到父组件的属性直接绑定到ui库组件上,而不需要在子组件中周转一下,另外在子组件上使用v-on="$listeners"
也可以将ui组件的事件直接传入父组件,这样一来二去代码可以说是简洁多了。
附上基于iview二次封装的table组件的基础代码
<template>
<Table
:data="data"
:loading="status.loading"
v-bind="customAttrs"
v-on="$listeners"
>
</Table>
</template>
<script>
export default {
name: 'BaseTable',
inheritAttrs: false,
props: {
data: {
type: Array,
default: () => []
},
// table的props 以及其它自定义属性
config: {
type: Object,
default: () => {
return {
tableProps: {}, // iview-table的属性放入此对象(剔除了data和一些状态属性如loading)
};
}
},
status: {
type: Object,
default: () => {
return {
loading: false
};
}
}
},
data() {
return {
};
},
computed: {
// 获取从父组件直接传入iview的属性
customAttrs() {
return {
...this.config.tableProps
};
},
},
};
</script>
父组件调用这个组件之后只需在config.tableProps中按照ui库的文档写上自己的属性即可,另外我将loading状态和data单独抽离便于管理,然后ui组件的事件直接在父组件上监听就行。
之后我在此封装的基础上又过滤出了自定义列模板的项并进行处理,完整代码见
https://github.com/dwtom/vue2x-playground
其中的views/iview/TableComponent就是了。
参考内容
vue官网
一个透传技巧,治好了我的重度代码洁癖