距离第一篇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日