primeng 是目前市面上一个比较优秀的 Angular 组件库,组件种类多且全,可定制化程度高,文档也写得通俗易懂。
本文将对 primeng 组件库进行简单分析,抛砖引玉,希望能对编写你自己的组件库有所帮助。
项目结构
进入项目目录后,运行 tree -L 1 .(如果没有安装 tree 命令,使用 brew install tree 安装),查看目录结构。
|
|
可以看出,primeng 项目结构也采用了 angular-cli 搭建,相比 angular-cli 初始化的项目,多了如下四个文件:
|
|
不过暂时没有看到 tsconfig-aot.json 和 tsconfig-release.json 两个编译配置文件用在何处。
再来看下 src 目录下的文件:
|
|
组件设计
组件的代码位于 src/app/components 目录中,组件的一些设计思路如下:
- 一个组件一个模块
这样可以很方便的按需引入组件,也利于组件的开发和维护。
另外,为了方便,在一个文件中定义了多个组件(一般是该组件的一些依赖组件),以及该包含该组件的模块。
- 组件样式全局引入
组件样式不在组件中单独引入,那样会给所有组件样式添加默认的 scope 限定(encapsulation = ViewEncapsulation.Emulated),如果外层需要覆盖内层组件样式,会很不方便。因此组件的样式全部在 src/styles.css 中引入。当然也可以将 encapsulation 设置成 ViewEncapsulation.None 来避免 scope 限定,这两种方式二选一即可。
styles.css 内容如下:
|
|
assets/showcase/css/primeng.css 文件引入了所有 components 的样式。
|
|
- 全部内联模板
primeng 全部将模板写成了内联模板,优点是文件内容紧凑,不会分散注意力;缺点就是缺乏语法高亮,编写HTML模板无法使用 emmet 等自动语法提示。
在组件库中,有两个文件夹值得特别注意。
common 文件夹
在 common.css 中定义了通用样式,例如 .ui-widget、.ui-helper-reset等,这些通用样式对于更换主题意义重大。
此外,其余大部分文件定义了组件库使用的一些全局性类型接口,例如广泛使用的 menuitem 结构。
|
|
另外,在 shared.ts 中,定义了一些通用的模板组件,例如 p-header、p-column、p-templateLoader 等。
|
|
dom 文件夹
尽管不推荐直接操作 dom,但是对于一个组件库来说,操作 dom 是无法避免的,因此 domhandler.ts 文件封装了大部分 dom 操作。
addClassaddMultipleClassesremoveClasshasClasssiblingsfindfindSingleindexrelativePositionabsolutePositiongetHiddenElementOuterHeightgetHiddenElementOuterWidthgetHiddenElementDimensionsscrollInViewfadeInfadeOutgetWindowScrollTopgetWindowScrollLeftmatchesgetOuterWidthgetHorizontalPaddinggetHorizontalMargininnerWidthwidthgetInnerHeightgetOuterHeightgetHeightgetWidthgetViewportgetOffsetgetUserAgentisIEappendChildremoveChildisElementcalculateScrollbarWidthinvokeElementMethodclearSelection
看到这么一大串方法列表,有人会疑惑,这不就是提取了 jQuery 的一部分功能吗,为什么不直接引入 jQuery 呢?
这里就涉及到一个库的设计原则:组件库的设计应该纯粹,能够拿来开箱即用,而不用再去配置组件库的一些依赖。
如果要引入 jQuery,如果使用 es2015 的模块按需引用,那么需要手动去配置 jQuery 依赖;如果采取全量引入,那就需要在构建时将 jQuery 代码打包到最终的构建输出中,这并不是一个很好的设计方案。
因此,这里自己实现了一个 jQuery 的 mini 集合来操作 dom。
组件例子
以组件 accordion 为例。
|
|
文件中定义了一个模块 AccordionModule,容器组件 p-accordion,以及面板组件 p-accordionTab。当然也可以分为三个文件去定义组件和模块,这两种代码组织方式也是仁者见仁,智者见智的问题。
主题样式
primeng 的主题样式采取了组件结构层样式(css)和表现层样式(scss)分离的策略,也即:
- 结构层样式:只定义组件的结构相关的属性,例如 box-model 相关属性
display,position,padding,margin等 - 表现层样式:定义组件展现的外观属性,例如
border,color,background,transition,outline,box-shadow等
以 Button 为例,在 src/app/components/button/button.css 中,定义了按钮结构层相关样式。
|
|
在 src/assets/components/themes/_theme.scss 中,定义了组件的一些基础表现层样式,例如所有的组件都包含有 ui-widget 类,该类定义如下:
|
|
这两个样式类定义了所有组件的通用表现样式,例如字体、边框、背景色、前景色、链接颜色等。
其中的变量,例如 $fontFamily,$contentBorderWidth 则在主题文件中去定义,primeng 提供了相当多的主题,你也可以很轻松的自定义自己的主题。
例如,看下主题 cruze 的样式实现。
|
|
你也可以写一个自己的主题配置文件来实现轻松换肤的要求。
文档
文档就是 src/app/showcase 模块,在该模块中引入了 src/app/components 中的组件,编写相应的帮助文档。
测试
primeng 暂时没有包含组件单元测试,只有在 e2e 文件夹有几个集成测试。
个人建议如果时间精力足够的话,每个组件还是需要写上单测。
后续有时间,会抽出几个有代表性的组件进行分析,敬请期待。