对于一个组件,我们希望它的CSS只作用于当前组件内的元素,所以我们给每个组件的Vue单页面文件的style标签加上了scoped属性。编译后,HTML标签会被自动添加一个随机生成的唯一属性 (比如 data-v-f3f3eg9) ,同时对应的CSS选择器也会增加同名的属性选择器(如.example[data-v-f3f3eg9]),这样组件内的 CSS 便指定了作用域。
编译后:
通过scoped属性的确能达到给组件样式设置作用域的目的,基本能避免组件内的样式影响外部,但是它也带来了另外一个问题,就是给外部覆盖内部样式带来了不便。无论组件功能多么通用,接口多么灵活,只要涉及到UI,就难免无法满足所有项目样式需求,所以应该允许在具体的项目中根据需要覆盖组件部分甚至全部样式。而scoped随机生成属性名提高了覆盖样式的难度。
经过权衡,我们在组件里移除了scoped属性,改用class策略来避免组件内样式影响外部。当然,scoped属性也不是没有存在的意义,它更适合在具体应用中使用,对于复用性高的组件来说,不是最佳选择。
按需使用与自定义构建
随着项目推进,组件库里的组件越来越多,目前已超过40个,构建之后的文件也越来越大。如果某个应用只用到了库里的少数几个组件,完全没有必要使用完整的构建包,所以我们需要提供一种按需使用的方式。早期,我们是让用户通过私有npm安装组件库之后,根据应用自身需要直接引用src目录下组件源码的方式来实现按需加载。这种方式有较大局限性,因为引用的源码没有经过编译,需要用户自己去处理组件的依赖关系,ES6/SCSS/Vue模板等编译工作也需要用户在自己的项目里完成,繁琐、易出错,也难以支持webpack外的其他场景。 我们设想提供一种自定义构建的方式,来实现按需打包。首先让用户选择需要哪些组件,然后基于这些信息生成一个个性化的配置文件,再基于这个文件进行构建,最终只打包编译用户指定的这些组件。
那么,通过哪种方式与用户交互,收集用户指令呢?比较友好的方式是通过web,比如在项目主页中提供一个页面,让用户在线选择组件,然后下载构建之后的文件。而根据我们组件库目前的定位,推荐的使用方式是通过私有npm安装,所以我们首先推出的是通过命令行界面(CLI)方式来完成自定义构建。
用户只需要在终端执行命令“npm run custom”,即可得到全部组件的列表,通过键盘选择需要的组件,然后按下回车,脚手架便开始自动完成剩余的个性化构建工作。
片刻之后,只包含用户所选组件的构建包会出现在dist目录下,文件体积比完整版本小很多。
这种方式下,所选组件会经历组件库脚手架完整的构建流程,自动处理组件依赖关系,对ES6/SCSS/Vue等语法也进行了编译,构建出的文件也支持AMD/CMD/script标签直接引用等场景,能比较好的满足按需使用的需求。
图标
组件库UI组件难免会包含一些小图标,需要寻找一种合适的方式处理这些图标。
在应用开发中有时会把一些图片转成Base64编码放在代码里,这会使数据量增大30%左右,所以这种方式不适合较大图片。而对于小图标来说,增加的绝对数据量并不大,却能减少一个http请求,也不失为一种优化方案。不过,组件库较普通应用对数据量更为敏感,这种方式不是上策。
另一种处理小图标的经典方案是雪碧图(CSS Sprite),但这种基于精准位置信息的图标引用方式在移动端基于rem的布局中并不是那么受欢迎,因为rem布局自身就难以精确,如果用于组件库也会给按需引用带来一些不便。
对于小图标,在移动端更需要的是矢量方案,天然适配各种像素密度的屏幕。
在组件库中,比较流行的是采用基于CSS3字体(@font-face)的ICON FONT方案,也就是把图标放在一个自定义字体文件中。有很多优点,比如:
ICON在字体中是矢量存在,受移动端欢迎
良好的浏览器兼容性,web字体并非CSS3发明,更早之前的浏览器(包括IE6)也都事实上支持,虽有些许差异,终归是有办法兼容的
可通过CSS控制ICON颜色和透明度等样式,甚至可以实现颜色渐变效果
我们并没有选择ICON FONT方案,我们认为SVG方案更适合移动端组件库:
SVG虽在PC端个别古董浏览器中兼容较差,但在移动端兼容良好
ICON FONT被认为是文本,所以一些浏览器会对其进行抗锯齿处理,这可能导致图标不那么锐利,清晰度打折扣
SVG样式控制比ICON FONT更灵活,甚至可以控制图标各个部分的颜色,实现彩色图标。而这对ICON FONT来说是不可能实现的