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 操作。
addClass
addMultipleClasses
removeClass
hasClass
siblings
find
findSingle
index
relativePosition
absolutePosition
getHiddenElementOuterHeight
getHiddenElementOuterWidth
getHiddenElementDimensions
scrollInView
fadeIn
fadeOut
getWindowScrollTop
getWindowScrollLeft
matches
getOuterWidth
getHorizontalPadding
getHorizontalMargin
innerWidth
width
getInnerHeight
getOuterHeight
getHeight
getWidth
getViewport
getOffset
getUserAgent
isIE
appendChild
removeChild
isElement
calculateScrollbarWidth
invokeElementMethod
clearSelection
看到这么一大串方法列表,有人会疑惑,这不就是提取了 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 文件夹有几个集成测试。
个人建议如果时间精力足够的话,每个组件还是需要写上单测。
后续有时间,会抽出几个有代表性的组件进行分析,敬请期待。