上一篇文章介绍了《怎样高效地利用第三方UI组件》,以Input
组件为例,介绍了一下怎么使用第三方的UI组件。
实话实话,Input
组件还是属于比较简单的组件,需要我们自己重写的东西还是比较少的。
如果是Tabs
组件呢?
怎么二次封装Tabs组件
我们先看一下element-ui
组件的使用方式(官方示例):
<template>
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane label="用户管理" name="first">用户管理</el-tab-pane>
<el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane>
<el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane>
<el-tab-pane label="定时任务补偿" name="fourth">定时任务补偿</el-tab-pane>
</el-tabs>
</template>
<script>
export default {
data() {
return {
activeName: 'second'
};
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
}
};
</script>
是不是有点难受了?
并不是我们简单的把参数传递过来,v-bind="$attrs"
,v-on="$listeners"
就能解决的了。
怎么办?
诉求
我们先看下,二次封装Tabs
的诉求是什么?
我肯定是不希望再写一堆el-tab-pane
的,再配上label
, name
,那没啥意义,根本没有达到减少代码的目的。
那就涉及到怎么把传递过来的$slots
转换成el-tab-pane
的内容的问题了。
如果没有写过react,也不太了解render
函数(确实基本上很少写render函数),那就有点困难了。
怎么封装?
事实上,我提供的方案,也是vue官方文档提供的,利用render
函数写jsx。
上代码吧!
<script>
let currentTab = null
export default {
name: "YvTabs",
model: {
prop: "value",
event: "change"
},
props: {
position: {
type: String,
default: "top",
validator: val => ["top", "right", "bottom", "left"].includes(val)
},
value: {
type: String,
default: ""
}
},
render(h) {
return (
<el-tabs
tab-position={this.position}
value={this.value}
onTab-click={this.handleClick}
>
{this.$slots.default.map(tab => {
const {
data: {
key,
attrs: { name, type = null }
}
} = tab
return (
<el-tab-pane key={key} name={name} lazy>
{type ? (
<template slot="label">
{type === "icon" ? (
<i class={"el-icon-" + key} />
) : (
<icon icon={key} />
)}
{name}
</template>
) : <template slot="label">{name}</template> }
{tab}
</el-tab-pane>
)
})}
</el-tabs>
)
},
methods: {
handleClick(vm) {
const { name = "" } = vm
if (name !== currentTab) {
currentTab = name
this.$emit("change", name)
}
}
}
}
</script>
需要注意的是,在render
函数内,是没有办法利用vue自定义的各种指令的,譬如v-model
,不过,别难受,不能写就不写,v-model
仅仅是语法糖,真没啥。
还有一个就是el-tabs
提供的事件tab-click
,刚开始我很天真的以为:在jsx内要改成驼峰式的事件名称,就使用了onTabClick
,我想很多人都可能跟我踩一样的坑的,然而,并不是,这里并不能用onTabClick
,而是需要写成onTab-click
,意不意外,惊不惊喜?
剩下的就是对$slots
的内容有点约束了,譬如每个DOM节点,需要传入key、 name、 type
等字段,这个可以依据各自需求进行各种自定义。我这里key和name是对应el-tab-pane
的属性label、name使用的,而type属性,纯粹是为了定义icon的,可以使用el-icon,也可以自定义各种图标字体,仅此而已。
当习惯了render
函数进行二次封装,也知道了v-bind="$attrs", v-on="$listeners"
,还有什么我们不可以进行封装的呢?
下面就是各种愉快的玩耍了。
只要在项目开始初期,按照设计图,自定义一遍各种组件的样式,剩下的就是各组件相互组合的问题了。