距離第一篇UI組件庫文章發佈已通過去3個月了,在此期間利用零零散散的時間持續更新owl-ui組件庫,目前owl-ui移動端組件庫已經更新3大類(基礎、表單、彈出層)9種組件(Button、Tabs、Input、Select、Switch、Drawer、Dialog、Picker、Toast)供使用。本篇文章主要講述我在這3個月內開發UI組件的我的心得。若是想了解項目結構能夠閱讀上一篇文章,若是想了解實現原理能夠閱讀源碼。全部鏈接在文章的結尾處。css
咱們從彈出層組件講起vue
前方多圖預警git
先看效果圖。github
我在選擇寫組件的時候,首先選擇作彈出層部分。爲何呢?我列出如下幾點。web
先說第一點:共性高、可複用api
由於本人很是笨,因此作事以前須要構思好久,這樣會減小以後重複性的工做。好比在作彈出層的時候,很多人會發現以上組件的共同點。沒錯,他們都是顯示或隱藏(廢話)。咱們接着往下分析,除了顯示或隱藏以外,他們大部分都有遮罩層部分。還有動畫效果也一致。咱們先根據這幾點把功能抽象出來,如何作呢?bash
在vue和less中都有mixins方式,根據mixins咱們很方便的將組件中的共性提取出來,達到代碼精簡的目的。如下代碼就是彈出層組件中顯示或隱藏功能的mixins文件。less
// src/common/mixins/visibility.js
const EVENT_TOGGLE = 'toggle'
export default {
model: {
prop: 'visible',
event: EVENT_TOGGLE
},
props: {
visible: {
type: Boolean,
default: false
},
zIndex: {
type: Number,
default: 100
},
maskStyle: {
type: Object,
default: () => {}
},
containerStyle: {
type: Object,
default: () => {}
}
},
data () {
return {
isVisible: false
}
},
methods: {
hide () {
this.isVisible = false
},
show () {
this.isVisible = true
}
},
watch: {
isVisible (val) {
this.$emit('update:visible', val)
this.$emit('callback', val)
if (this.lockScroll) {
document.body.style.overflow = val ? 'hidden' : ''
}
},
visible: {
handler (val) {
this.isVisible = val
}
}
},
beforeDestroy () {
this.lockScroll && (document.body.style.overflow = '')
}
}
複製代碼
上面主要作一件事,根據visible屬性判斷組件展現或隱藏。ide
使用方式以下:函數
// 組件文件
<script>
import visibilityMixin from 'mixins/visibility'
export default {
mixins: [ visibilityMixin ]
}
</script>
複製代碼
順便說一下項目中運用到less的mixins運用,好比1px問題。
// src/styles/common/border.less
.min-device-pixel-ratio(@scale2, @scale3) {
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
transform: @scale2;
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
transform: @scale3;
}
}
.border-1px(@color: #DDD, @radius: 2PX, @style: solid) {
&::before {
content: "";
pointer-events: none;
display: block;
position: absolute;
left: 0;
top: 0;
transform-origin: 0 0;
border: 1PX @style @color;
border-radius: @radius;
box-sizing: border-box;
width: 100%;
height: 100%;
@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
width: 200%;
height: 200%;
border-radius: @radius * 2;
transform: scale(.5);
}
@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
width: 300%;
height: 300%;
border-radius: @radius * 3;
transform: scale(.33);
}
}
}
.border-top-1px(@color: #DDD, @style: solid) {
&::before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
border-top: 1Px @style @color;
transform-origin: 0 0;
.min-device-pixel-ratio(scaleY(.5), scaleY(.33));
}
}
複製代碼
該函數能夠經過傳參改變線的顏色和類型。
使用方式以下:
// src/styles/packages/dialog.less
@import "../common/border";
@dialog-prefix-cls: ~"@{css-prefix}dialog";
.@{dialog-prefix-cls} {
...
&-btns {
...
.border-top-1px(); // Here
}
}
複製代碼
合理的運用mixins可使得項目結構清晰、減小冗餘代碼更利於後期維護。
優化方式有不少種,每一個人有不一樣的編碼習慣,因人而異。可是目標都是一致的,讓本身的代碼變得簡潔、精煉和易讀。
在彈出層中將公共部分抽象封裝,好比遮罩層
// src/common/components/popup-mask.vue
<template>
<div class="popup-mask"
:style="{ ...maskStyle, zIndex: zIndex - 1 }"
@click.stop.prevent="handleMask"></div>
</template>
<script>
export default {
props: {
name: String,
maskStyle: Object,
zIndex: Number
},
methods: {
handleMask (event) {
this.$emit('click', event)
}
}
}
</script>
複製代碼
第二點:兼容性高
我在工做中接觸的移動端需求比較多,PC端作過一些管理後臺。移動端與PC端的項目,給我最最直觀的感覺是,移動端要求UI極其嚴格,一像素都不能差,而PC端差很少就能夠了,UI設計師們也不會過多糾結PC端作出來的頁面是否跟原型圖徹底吻合。
在移動端,有的產品特別喜歡更改UI設計,特別是有表單部分的頁面,今天產品嫌棄字體小了,明天可能以爲字體又太大了;今天把輸入框改爲圓角,明天就喜歡直角。今天以爲橫向佈局好,沒準明天就要試試縱向佈局。產品以爲這麼改沒關係,卻不知若是項目中運用了UI組件庫,這麼修改完後,代碼冗餘太多。都是爲了更好的用戶體驗,慢慢也能理解。在那以後的幾個移動端項目裏,表單部分基本不會用到UI組件庫。可是彈出層部分沒有過多的限制,據我瞭解到的產品內部最統一的就是彈出層。若是有同窗想用owl-ui的彈出層部分的話,能夠放心用,支持按需加載。
第三點:快速出貨,提高成就感
我喜歡把長期計劃拆解成多個很小的事情來作,就是制定不少小目標。比如遊戲進度條同樣,使其量化。之因此這麼作的緣由是,我能週期性的看到個人工做成果,這樣能夠激勵本身,提高信心。
在彈出層組件中,mixins作好以後,像toast、dialog、drawer組件只剩下設計api部分而已。而picker組件是基於drawer組件來實現的內容部分而已。當picker組件實現完成,這時已經說明表單的select組件也已經完成了。提及來簡單,其實作起來也不難。
最後在使用彈出層組件時,我想用api調用的方式來使用它。這裏我借鑑了cube-ui的vue-create-api,可是由於部分方法不太適合我,因此我稍加改動,借鑑(抄)到本身的庫中。
好比Toast組件,官網給出的使用方式以下:
const toast = this.$createToast({
time: 1000,
txt: 'Toast time 1s'
})
toast.show()
複製代碼
我是個懶人,對我來講使用一個消息提醒要寫這麼多,我就以爲很煩惱,因此我在owl-ui中把vue-create-api稍加改造後,Toast使用方式以下:
this.$toast('歡迎光臨')
複製代碼
清爽了不少。
其餘類型組件使用狀況,有人喜歡整套使用,有人喜歡部分使用。而我屬於後者。
我寫組件庫的目的就兩點。第一點能夠幫助我從新梳理一遍vue的知識體系,瞭解到自身的不足,不斷的克服困難,讓本身成長。第二點結識更多圈內的朋友,提升見識。我會持續更新迭代owl-ui組件庫,歡迎喜歡技術的朋友多提建議。最後附上吳軍博士說過話,這句話讓我終身受益。
什麼事情從0分作到50分靠常識,從50分作到90分靠技術,從90分作到100分靠的是藝術。作到90分咱們能夠經過努力能達到,至因而否能作到更好,就依人而定了。
祝工做順利
鄧文斌
2019年5月20日