上一篇文章介紹了《怎樣高效地利用第三方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"
,還有什么我們不可以進行封裝的呢?
下面就是各種愉快的玩耍了。
只要在項目開始初期,按照設計圖,自定義一遍各種組件的樣式,剩下的就是各組件相互組合的問題了。