首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

未来样式篇:组件化推进下的样式与逻辑

未来不近不远,前端稍纵即逝

✎摘要

当下的开发模式中,Webcomponent的气味越来越浓郁了,无论是否真的支持Webcomponent的标准接口,都会在设计上或者是概念上去靠近他。这里将会探讨下在当下各种技术下的样式与逻辑处理,这又是一个看似并不太受开发者关注的话题。

组件化下的样式

组件化,前端发展到一定阶段的产物,为简化开发带来的优势毋庸置疑,快速复用,极大的提升了开发效率,因此对组件的封装与抽象也成了项目中很重要的一部分。(这里的组件不仅仅指通用组件,还有每个企业自己的业务抽象组件)

正因为组件的重要,W3C也迅速将webcomponent标准推上日程。为了让组件更加原生化,更加个性化,像Google Chrome也是早早就进行了布局,早几年前就已经推出了基于webcomponent标准的框架Polymer。虽然他还没有大火,但他走在来这个未来标准的主路上。我们会在后面的文章中单独来展示webcomponent的技术,这里先提一下。

那么回归正题,组件化下的样式该怎么写?从现状来看,大概有几种:

全局统一,然后借助于ITCSS、BEM、SMACSS或OOCSS之类的设计和命名规范来进行严格的开发。

采用模块化规范,所有组件的类名都将唯一。

采用作用域,使所有类名仅在某一作用域下生效。

整体来看后两种方案目前都只能算是一种workround,在各个框架或者类库中的实现都或多或少又差异。比如vue和css-loader的模块化都是给唯一的ID来进行区分,又比如vue的scope和Riot的scoped实现是不同的,vue是通过唯一ID的属性来作为类查询条件实现的,而Riot采用的是未被列入标准的style scoped属性。

其实在webcomponent的shadow DOM中,组件的css都是scoped的,在很多情况下可以很好的控制他的作用域。

好吧,说了这么多样式的情况,跟本文的主题有什么关系呢?

其实关系说大不大,说小也不小,请接着看。

组件化样式与逻辑

上面提到了组件化与样式的的一些现状,那么接下来我们要说的是当我们对组件进行抽象的时候,一定会遇到交互效果与逻辑相关联的问题。

举个例子,我们封装组件的时候需要定制一系列按钮,如下:

按钮的size有small/medium/large三种,type有primary/info等等,接着我用vue来简单实现下。

这里的实现方案肯定会有人有异议,我只是以这样的一个方案为例。这种方案最大的好处是我们逻辑上比较直观,我要添加某一个class, 这个class的名字由传进来的值所决定,看上去没问题,单class的高效率,语义化的代码结构。

好,那么我们都知道vue的class是可以从定义的组件上传给组件内部的根节点上的,所以我们来进行下小的改造,让其看上去是这样的:

代码看上去少了一些,而逻辑看上去并没有差别。那么就会有人说,不就是css属性选择器嘛。没错,就是简单的一个属性选择器,让我们抛弃了丑陋的class拼接逻辑,他仍然是单class,虽然多了属性选择器之后性能上会稍显逊色,但实际上线运行的情况是几乎没感受到差别(这里没有benchmark测试结果)。当然这里不能像下面这样的来写样式:

再往下看,由于vue的自定义组件最终会编译为你定义的dom结构,所以在编译完之后浏览器中实际呈现的是这样的代码:

一眼看去一个div标签有两个属性size和type,如果不是有个class大概的描述了一下他是一个button外开发者肯定很懵圈。

以上所说的情况在现有的很多组件库中都很常见。这样的代码正好在我最近的开发中遇到了,而且相当多,比如vue的elementUI组件库的sidemenu中就有这么一段:

虽然源码对于开发者来说并不重要,但是对于需要进行改造定制化开发或者说自己项目组件的话,虽然说不管语意还是逻辑都还算清晰,但始终不尽如人意,也许把上述代码转变成如下的形式会舒服点?

总之我是更喜欢后面这种

好,那么我们再接着最早的案例接着来看下以Polymer为例的webcomponent会怎么表示:

是不是跟编译前一样?语义化的标签以及合理的描述属性,这是一种开发者友好的表示。那再来看看Polymer内部怎么实现的:

到这里为止,展示了一个比较简单完整的逻辑与样式分离的代码,这是一个简单的事例,因为实际情况中会存在其他复杂的情况,比如需要根据得到的属性进行二次计算之类的,那就要适当调整了。

小进阶

在实际情况中,我们可能还有一些其他复杂的逻辑在样式中,比如列表第一个或最后一个怎么怎么处理啊,比如一个标签内非某class的元素应该如何如何啊,再比如第一个非某class的元素该如何如何啊之类的。

我们在开发中非常重要的一个主旨就是能用css写的绝不用js。所以在以上简单的应用的基础上也许可以根据需求合理的利用如下的逻辑:

这里的代码可能逻辑不一定是最合理的,但是这只是一个示例,这个示例可以理解为一个导航栏的tab样式管理,这里的省略了循环li的逻辑,省略了计算tab是否active的逻辑,只是想展示下逻辑与样式的一个小进阶例子。

那么这个例子中可以看到,导航栏有7个tab项,其中当前页面激活的选项卡带有属性active,另外中间有两个样式特殊的的选项卡,如果我们继续使用v-class之类的来动态拼接或者计算class出来,在dom上会有一些个人认为本不该属于dom的代码。

特别是在动态产生dom的情况中,如果还要因为拼接class名来增加逻辑开销,始终不是那么优雅,更觉得始终不应该做这个多余的事。

因此逻辑与样式想要表达的主题是:我们的逻辑应该计算的是组件是否符合某属性,而不是在计算符合属性后,还要计算符合属性的class

一些其他的框架

React中的class的计算通常会借助classnames这个第三方工具包,所以React的代码看上去会是这样:

这里就是像我说的,明明我们已经计算好了属性,却还要再根据属性额外进行一次class的计算,如果可以的话直接像下面的写法不是更好吗?

甚至说如果属性像vue那样直接又组件传递至内部根结点上的话可以直接简化成一行代码:

当然,这么写的话还需要组件干什么直接用div不就好了~,这只是个例子,实际场景中肯定会遇到类似的情况。

总结

结论呢,当然还是离不开我们的未来理念了!这里不吹捧哪个技术好,但是利用了webcomponent之后,组件化的进程中对类似于逻辑样式的处理也许这篇文章可以作为一个参考点。

还是那个强调,这里所展示的东西都是标准化的内容,它与现有框架技术并不冲突!

现有的技术框架都是当前标准技术的扩展,而我所展示的都是标准化的内容,都是可以兼容这些技术扩展的。所以像React这样的框架,也会在自己的官方文档中提供结合webcomponent的示例。

合理选择合理利用,创造无限!

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180512G0KYX100?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券