面向设计的半封装web组件开发

2016年05月26日 源自:大神部落

前言

本文内容可谓是对大脑认知的一场洗礼。我们平常提到组件,就会想到重用,各个项目都能使用。而本文的组件,对于某具体项目而言是组件,但是,对于其他项目,就是个半封装的半吊子组件。面向设计、面向项目的web组件开发,就是本文要探讨的主旨。

一、人与组件

目前这个阶段,我们所使用的web组件都是人所编写的,因此,人这个个体在赋予组件生命的时候就扮演了至关重要的角色。人的技能背景,个人喜好,甚至世界观都可以从组件中得到体现。但人无完人,因此要想诞生一款完美的组件,需要上下游很多优秀的同事,把自己最棒的世界融入进去,协作完成,其中下面这4个职位参与度较高:

与web组件开发联系紧密的4个职位

注意到了没有,前端开发人员处于web组件开发流程的下游;这其实没什么,大家通力协作,组件弄好,项目做好,产品做好,皆大欢喜。然而实际上,由于大学没有前端专业,因此负责团队web组件开发的,大多是从与组件几乎不相干的后台开发转过来的,或带有明显的后台开发烙印的。也就是说,前端开发不仅处于下游,还有1/3的身子在web组件之外。

前端开发的背景

一个web组件的诞生,理想状态应该是需要设计、UI工程师、前端开发通力协作完成的。有句话怎么说来着,理想很丰满,现实很骨感。

现实是:大多数web组件都是前端开发人员一个或数人,按照业界约定俗成的套路实现的,超前于UI设计,游离于UI重构。什么意思呢?比方说一个弹出层组件,有标题、关闭按钮、主内容区域,底部确定/关闭按钮。这套结构是业界约定俗成的,开发人员在写这些组件的时候,会发挥自己的聪明才智,好好地封装,好好地设计API, 目的就是可以不用关心以后设计师设计的弹出层长什么样子,因为我预留了类名接口,UI工程师换个皮肤就好了;同时能保证组件的整站复用。也就是项目开始之前,成熟、封装良好、API丰富的web组件就已存在。

亲们,读到现在,你们是不是觉得没什么问题,挺好的啊!?对的,在iPhone出现之前,大家都觉得Nokia挺好的。

从人的角度讲,这种看似牛逼的路数最大的问题就是无视了分工,所谓术业有专攻,闻道有先后,开发再逆天,也是存在局限的,或者说是人性上很难避免的东西。

1. 位置与角色

大家应该都知道,设计师和程序员处于两个不同世界的,因此,当其中一个角色独自承担另外一个角色工作的时候,自然会存在诸多阻碍,其中很重要的一点就是设计重心。

前端开发写web组件,实际上也是一种代码的设计,此时,这些程序员气质浓郁的前端开发人员设计的重点自然是放在组件功能、通用性、扩展性以及易用性上,毕竟这一块是自己擅长的,至于UI,会预留API或其他接口,也能满足常规的设计需求。

如果交互设计师或UI设计师来写web组件, UI和交互可定制则是其设计的重心,发展得好的话,可以直接成为另外一种流派,直接和(开发背景前端的)面向功能的web组件流派相抗衡。但是,国内的现状是,设计师一般不参与直接的代码建设。

实际上,从职位上划分,UI开发应该是最适应构建web组件的角色,能兼顾设计之美,重构之美,以及代码之美。只可惜由于门槛低,水平良莠不齐,尤其JS方面的驾驭能力有限,于是,最后的结果是,组件的建设都落在了工程气息浓重的开发身上。

可以看到,虽然不合理,但是情非得已。有人可能要叫了:“啰哩吧嗦,狗皮膏药涂到现在,到底哪里不合理,你到是说啊!”

OK, 稍安勿躁。由于组件这东西只能开发实现,导致在组件的设计以及使用上,前端开发有了非常大的话语权,下游决定了上游,设计师以及CSSer在组件眼中就是个摆设。比方说设计师对dialog弹框进行了某些微创新,比方说下面这样的(无标题无关闭大背景色块):

一个提示框效果示意

去问开发可行性,结果,开发来了一句:“哎呀,这个功能我们的弹框组件目前不支持!”我相信这种场景很多同学都遇到过吧~最后,基本上都是设计师妥协,使用传统弹框交互或布局。所以,坊间才有“苦逼的设计师”的传闻。

苦逼的设计师这样苦逼地工作了很多年,还好,大家就这么过来了。然而,事物是不断发展的,技术是不断进步的,随着CSS3, SVG等现代web技术日趋成熟,我们在UI展现层能够做的事件就非常多,更新变化也更加快。在这种大环境背景下,还让开发来决定设计,显然这对产品是不负责任的。其他竞品在组件UI细节上不断闪现人性化、情感化的创新之处,交互也更加流畅与舒适;而你还抱着“我们这是成熟的弹框组件,不能随便改”的想法固步自封,使用”duang duang duang”生硬,机械,呆板的弹框组件,注定在现代web浪潮中被冲到沙滩上。

对于页面工程师,切图仔而言,其实也挺苦逼的。在部门没啥地位的页面仔们,苦学了一种新的布局,比传统实现少嵌套2层标签,且满足各种场景需求,好棒!结果交接的开发来了句“我们的选项卡组件不支持你这种结构,你需要调整下”。

具体项目的具体组件本来就应该是大家通力协作完成的,现在就因“组件是我写的,我就是发言人”的心态限制设计、重构的创造力。这就是不合理之处。

2. 扬长避短

组件的作用是什么呢?就是“偷懒”,来个新页面,“啪”一套;来个新项目,也是“啪”一套。功能棒棒哒,任务完成,老婆再也不用担心我加班晚归啦!

偷什么懒呢?主要是偷自己不擅长那块的懒。这是人之常情。设计师不懂代码,他希望的组件是,直接可视化操作就OK的;页面制作人员,他希望的组件是JS功能那块它不需要操心;前端开发们,则希望组件HTML布局那块不需要关心。

好了,现在组件都是开发背景的前端写的,所以呢,很多HTML布局啊,样式表现啊,都集成在了web组件中,一些动态的表现就使用洋洋洒洒的API控制。于是,开发使用的时候,只要按照特定的套路,自己不需要去写页面之类的,组件就棒棒哒了!

这样的例子很多的,比方说知名开源项目kissy中的选项卡组件,根据我的观察,其选项卡要么是要通过JS脚本动态创建,任何特异化的需求都是通过丰富的API接口或者回调实现的。总之,组件的使用只需要玩弄JS, 不需要把玩HTML; 要么就是套用固定的HTML结构以及className值。这比较符合JS造诣很深的前端开发的偷懒模式。

等等,篇幅原因,就不一一举例。

这并没有什么对错之分。有的企业就是功能为王,业务导向;有的企业就是产品为王,体验优先。不同的企业文化,不同的产品要求,不同的团队规模与技术能力,决定了web组件的表现形态、使用方式等。只要符合企业的生产与成长需要,都是很棒的web组件。因此,类似kissy这样的模块集合,是否适用于单兵作战的中小企业以及注重用户体验的创业团队,就需要执行者好好斟酌斟酌了!说不定,jQuery UI可能更合适一点。

至少对于我而言,绝不会去使用对HTML做过多限制的web组件的(例如要求节点必须如何如何…):

KISSY 1.4 srcNode 初始化组件时必须要求内容节点必须包含类名 ks-overlay-content (这里 ks- 为 prefixCls)…

“扬长避短”原本是个褒义词,显然,我放在这里讲,是要说其不好的。有句话讲的好,叫做术业有专攻。前端开发都会HTML/CSS, 毕竟相比程序开发,门槛很低,在相关领域也浸染了些年月,构建web组件的时候,感觉HTML/CSS方面的应用也是比较顺手的,功能也都能跑起来。但是,在HTML/CSS方面造诣很深的开发看来,前端开发web组件的HTML结构等设计不敢恭维。举个真实的例子:

要实现一个相对文本框定位的Autocomplete组件(相比绝对定位, resize时候无需JS重定位),前端开发是这么实现的,在文本框外面wrap包裹了一层标签,设置positionrelative, 然后Autocomplete主列表容器就在这个包裹里面,绝对定位于该, left/top值与文本框尺寸关联。

相对定位弹框实现反例演示

最后的实现,效果是有的,兼容性也是可以的,在前端开发看来应该是OK的,自我满意的。但是,在我看来是相当糟糕的!

这外面包裹的一层标签完全是多余的,我们无需包括标签就能实现我们想要的相对文本框定位效果,而且兼容IE6+. 目前的实现,这个包裹的看上去貌似起到了辅助剂的作用,实际上留下了超级隐患,让组件生命力(适用性)立马降低50%。

小隐患是,可能相邻父子选择器会失效,比方说.parent > input选择器,会因为莫名其妙爸爸变爷爷导致文本框样式失效,这个问题嘛,改改CSS就可以了;以及多了一个relative, 元素的z-index层级管理又更复杂了一步,维护成本增加了!

超级大隐患是,Autocomplete组件下拉框高度超出容器高度是很常见的,但是,由于你外层有了一个position:relative的父级,只要外面任意一个容器有overflow:hidden,你的Autocomplete下拉就会被拦腰斩断,部分内容不可见;如果是overflow:auto/scroll,则会出现讨厌的滚动条。这个组件基本上就废了!但是,如果没有外面这层讨厌的position:relative父级,overflow:hidden就干不掉下拉列表,Autocomplete组件就能长青不老,适用性提升了整整一个量级。

上面截图,仔细看会发现有个*-placeholder元素,先不说这个label元素没有for属性,要知道,企业产品近8成用户的浏览器都支持原生placeholder(包括颜色等自定义),对于这部分浏览器,我实在想不出任何需要自定义实现placeholder效果的理由。最大的可能性是前端开发童鞋不知道目前凡是支持placeholder属性的浏览器都可以CSS自定义吧。也就是前端开发本身的技术深度以及视野的局限。

我们对上面的絮叨总结下,就是想表达,人的局限性带来了web组件的局限性,唯有相互协作,告别单职挑大梁,才能让web组件有所突破。但是,目前这个阶段,这现实吗?优秀的前端如此匮乏,尤其能够上下游承接的,想寻求突破,我们是不是可以从别的地方入手?

二、组件的抽象与封装

我们在写web组件的时候,我们总是会尽可能地去抽象功能,封装API。 于是,当我们使用这些组件的时候,我们只需要针对一些常用API去做设置,就能满足我们日常的功能。

在很长一段时间里,我一直都是这么做的,业界几乎所有开源的web组件,包括团队内的web组件都是这样的设计思路。

然而,随着时间推移,在各种类型的项目中浸泡,我发现,尽可能地去通过JS的手段封装组件似乎不是未来的趋势,反而可能会成为一种制约。

1. 现代web技术发展

CSS3/HTML5等现代web技术不断发展,以及IE6浏览器的淘汰。浏览器自身能够完成的事情要比以前多很多很多。举个极端的例子(都是厂内现有的真实案例),模拟单复选框的web组件,如果按照传统的组件开发模式,API这块(events回调API缺省)可能就会是下面这样子:

一些API参数等

从代码的角度讲,还是很美的,对吧;功能上也是可以的,各类需求也能满足;API的抽象与封装也是没有不足。只是,恕我愚钝,这洋洋洒洒600+行的JS代码的价值在哪里?在IE9+浏览器下,单复选框的自定义效果是不需要一丁点一丝丝JS代码的,对于IE7-IE8浏览器,我们只需要关心input本身,全局委托click, 让单复选框input的类名和checked状态保持一致就可以了,其他的交给CSS选择器完成就好了。全部的代码量跟上面截图API参数代码量基本上一样,而且对设计师和页面重构人员更加友好。

工程化的思维方式,高度的逻辑思维与抽象能力,以及造物者的美妙感觉,似乎让开发热衷于设计与封装API, 熟不知,当新技术出现,或者发现有其他更简单的实现的时候。那些所谓的封装是显得那么的笨重与鸡肋。

“好了,你别说了,我改还不行吗?”组件这东西,由小变大很简单,可以向前兼容;你想从大变小,我只能呵呵。还是等下一个全新的版本,或者其他完全不相干的项目了,兄弟!

2. 变幻莫测的UI层

现代web技术的发展,让我们在UI表现上可以有更多的选择。这对web组件UI这块的抽象与封装带来了很大的挑战,来看看一些同行的言论吧:

关于UI逻辑抽象的言论

如果有组件自信对UI层进行了完美地抽象与封装,这表明,这个组件已经对UI层的表现有了很大的限制。这是毋庸置疑的,有些事物本身就是对立的矛盾体,工程化就是要讲求一致性,但是,个性化显然就是需要不一致,而UI表现就是一件很个性化的事情。So, …

当前的web组件面对新项目新的UI表现需求,采用的做法要么就是new一个新的封装进行二次封装,要么多些写代码做冗余处理。恩,都不是什么好做法,不过又没有办法。

3. 跨部门的合作

最新,我们完成了一个项目。这个项目质量非常高,无论是UI, 交互和体验,各方的评价也很好。后来我们要开始一个新的且比较大的项目,就希望把已有项目很多好的东西借鉴过来。设计还是同样的一批设计师,但是,前端团队却换了一拨人。理想的状态应该是这样的,新项目的前端团队,直接使用之前项目这边的前端UI组件(除了颜色,尺寸什么的都是一模一样的),less的变量文件颜色一改,分分钟无缝转移,多棒啊!

但是,最后的结果是,新的前端团队放弃了之前项目的前端解决方案,还是使用了自己的简洁派做法,seajs + jQuery + …

各位观众可能会疑问了,咦,为啥不使用现成的东西啊?主要原因就是上手成本和学习成本,企业这边的前端组件体系可以和kissy一拼了,面向对象、模块化、按需加载,API封装也是尽善尽美,走Grunt.js玩nodejs, 前后端分离,走得还挺超前的。但是,自己团队内部新人有人带,有人教,可以慢慢上手。但是,你这一套东西交给其他团队,考虑到其量级以及复杂度,以及项目的紧急程度;一看到你那洋洋洒洒N多的API参数,着实让人望而生畏。以及还有不可忽略的代码风格、模式等差异。

为什么会有那么多API?

这个问题很有意思:“为什么会有那么多API?” 这个问题可谓是问到点子上了。原本组件诞生的时候,API是没有这么多的,后来,现有的API不能满足某些UI层或交互层的使用场景,于是,前端开发就抽象一下,新增一个API, 满足这个需求。但是呢,这项目啊是一个接一个,需求呢,也是千变万化。没过多久,又来了个需求,开发据理力争,还是没能挡掉,结果,又在组件里新增一个API。 久而久之,就有了现在看到了很多API参数,此时,这个web组件就可以称为“成熟的web组件”,对外宣传“适合多种应用场景”。这其实很有意思,所谓的适应性居然是通过增加各种API,增加组件代码量实现的,然后还自我得意一番。我开始有些明白为啥小小的单选框模拟组件居然需要600多行的JS代码了。

归根结底,还是“尽可能对组件API进行抽象和封装”这样组件编写意识导致的,这种想法和意识实际上已经不符合发展的趋势了。

我们看来有必要转换思维。

三、转换思维,分离与半封装

大家都知道YUI已经停止维护有段时间,至于原因,不知道大家有没有好好体味下(参见下图言论):

关于YUI终止开发的言论

正如我所言,为了满足UI需求,讲求封装的设计理念,必然会导致web组件越来越大,越来越臃肿;同时,前端开发这个角色由于关注点和职位跨度原因,对于UI层的处理能力和其对JS语言本身的处理能力还是有不小差距的。

因此,考虑到未来发展,我们必须做出适当的改变。我个人觉得可以从这两方面寻求改变:分离半封装

1. 分离

实际上,目前的UI组件也是有分离的,很多样式都可以通过类名控制。然而,这些分离都是逼不得已的,比方说Autocomplete的列表样式,你总不可能每个列表都内联一段样式相同的style设置吧。但是,如果条件允许,样式控制都是尽可能在JS中完成的,例如Autocomplete的列表容器的尺寸、定位、层级等等;甚至有些组件直接内嵌完整的CSS代码。

这样的设计是奔着足够封装,调用方便去的。但是对UI的友好程度,恐怕就不是设计者的关注点了。

显然,这里要讲的“分离”要比传统的“不得已分离”要更进一步。包括两方面:

①. 样式控制从JS分离

即只要是静态样式控制,全部交给外部的CSS来完成。甚至包括组件的状态控制(尤其是只要支持IE9+的项目),例如显示,隐藏等等。

拿经典的弹框组件举例。至于absolute定位,还是fixed定位,背景色是黑色还是其他,透明度多少,弹框是否居中定位等等,组件都不管(目前这类全都JS API控制),组件要关注的是功能层面的东西。千万不要自己为是,使用JS计算让弹框居中显示(外带resize重计算)。UI需求不是你可控的,比方说我们这边几个项目的弹框的需求是上下2:3滚动跟随显示,CSS完全可以实现此效果,CSS才是最好的UI样式API。

说到这里,忍不住爆料下,由于各种错综复杂的原因,项目的弹框组件Overlay的透明度和颜色API目前是个酱油,自定义没效果。于是,最后还是使用CSS的!important重置了JS的

扫一扫

关注大神部落

长按二维码

关注大神部落

地址:深圳市龙华新区东环一路天汇大厦B座520室

电话:13530491906

Copyright © 2014 - 2019 大神部落 & 版权所有

粤ICP备15047144号