angular模块库开发实例

前端之家收集整理的这篇文章主要介绍了angular模块库开发实例前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

angular模块库开发实例

随着前端框架的诞生,也会随之出现一些组件库,方便日常业务开发。今天就聊聊angular4组件库开发流程。

下图是button组件的基础文件

nk-button.component.ts为该组件的核心文件,看看代码

  1. import {Component,Renderer2,ElementRef,AfterContentInit,ViewEncapsulation,Input} from '@angular/core';
  2.  
  3. @Component({
  4. selector: '[nk-button]',templateUrl: './nk-button.component.html',encapsulation: ViewEncapsulation.None,styleUrls: ['./nk-button.component.scss']
  5. })
  6. export class NkButtonComponent implements AfterContentInit {
  7. _el: HTMLElement;
  8. _prefixCls = 'ky-btn';
  9. _type: string;
  10. _size: string;
  11. _shape: string;
  12. _classList: Array<string> = [];
  13.  
  14. @Input()
  15. get nkType() {
  16. return this._type;
  17. }
  18.  
  19. set nkType(value) {
  20. this._type = value;
  21. this._setClass();
  22. }
  23.  
  24. @Input()
  25. get nkSize() {
  26. return this._size;
  27. }
  28.  
  29. set nkSize(value: string) {
  30. this._size = value;
  31. this._setClass();
  32. }
  33.  
  34. @Input()
  35. get nkShape() {
  36. return this._shape;
  37. }
  38.  
  39. set nkShape(value: string) {
  40. this._shape = value;
  41. this._setClass();
  42. }
  43.  
  44. constructor(private _elementRef: ElementRef,private _renderer: Renderer2) {
  45. this._el = this._elementRef.nativeElement;
  46. this._renderer.addClass(this._el,this._prefixCls);
  47. }
  48.  
  49. ngAfterContentInit() {
  50. }
  51.  
  52. /**
  53. *设置class属性
  54. */
  55. _setClass(): void {
  56. this._classList = [
  57. this.nkType && `${this._prefixCls}-${this.nkType}`,this.nkSize && `${this._prefixCls}-${this.nkSize}`,this.nkShape && `${this._prefixCls}-${this.nkShape}`
  58. ].filter(item => {
  59. return item;
  60. });
  61. this._classList.forEach(_className => {
  62. this._renderer.addClass(this._el,_className);
  63. });
  64. }
  65. }

针对核心概念ElementRef、Renderer2、ViewEncapsulation做简要说明:

ElementRef

在应用层直接操作 DOM,就会造成应用层与渲染层之间强耦合,通过 ElementRef 我们就可以封装不同平台下视图层中的 native 元素 (在浏览器环境中,native 元素通常是指 DOM 元素),最后借助于 Angular 提供的强大的依赖注入特性,我们就可以轻松地访问到 native 元素。

参考链接

Renderer2

渲染器是 Angular 为我们提供的一种内置服务,用于执行 UI 渲染操作。在浏览器中,渲染是将模型映射到视图的过程。模型的值可以是 JavaScript 中的原始数据类型、对象、数组或其它的数据对象。然而视图可以是页面中的段落、表单、按钮等其他元素,这些页面元素内部使用DOM来表示。

参考链接

ViewEncapsulation

ViewEncapsulation 允许设置三个可选的值:

  • ViewEncapsulation.Emulated - 无 Shadow DOM,但是通过 Angular 提供的样式包装机制来封装组件,使得组件的样式不受外部影响。这是 Angular 的默认设置。
  • ViewEncapsulation.Native - 使用原生的 Shadow DOM 特性
  • ViewEncapsulation.None - 无 Shadow DOM,并且也无样式包装

参考链接

button组件创建思路:

  • 针对button我们只需修改其样式,因此在这里创建属性指令
  • 提供属性接口
  • 根据其传入的属性值动态渲染DOM

至此,最简单的button就开发结束。

模块打包流程

合并html、css到component文件

  1. let fs = require('fs');
  2. let pathUtil = require('path');
  3. let sass = require('node-sass');
  4. let filePath = pathUtil.join(__dirname,'src','temp_components');
  5.  
  6. let fileArray = [];
  7.  
  8. function fildFile(path) {
  9. if (fs.statSync(path).isFile()) {
  10. if (/\.component.ts/.test(path)) {
  11. fileArray[0] = path;
  12. }
  13. if (/\.html$/.test(path)) {
  14. fileArray[1] = readFile(path)
  15. }
  16. if (/\.component.scss$/.test(path)) {
  17. fileArray[2] = path;
  18. }
  19. } else if (fs.statSync(path).isDirectory()) {
  20. let paths = fs.readdirSync(path);
  21.  
  22. if (fileArray.length === 3) {
  23. writeFile(fileArray);
  24. fileArray = [];
  25. }
  26. paths.forEach((p) => {
  27. fildFile(pathUtil.join(path,p));
  28. });
  29. }
  30.  
  31. }
  32.  
  33. function readFile(file) {
  34. return fs.readFileSync(file);
  35. }
  36.  
  37. function writeFile(fileArray) {
  38. let file = fileArray[0];
  39. let content = fileArray[1];
  40. let scssPath = fileArray[2];
  41. mergeContent(file,content,scssPath)
  42. .then(result => {
  43. if (!result) return;
  44. fs.writeFile(file,result,function (err) {
  45. if (err) console.error(err);
  46. console.log('file merge success!');
  47. })
  48. });
  49.  
  50. }
  51.  
  52. /**
  53. * 转换scss
  54. * @param path
  55. * @returns {Promise}
  56. */
  57. function processScss(path) {
  58. return new Promise((resolve,reject) => {
  59. sass.render({
  60. file: path
  61. },(err,result) => {
  62. if (!err) {
  63. resolve(result.css.toString())
  64. } else {
  65. reject(err);
  66. }
  67. })
  68. })
  69. }
  70.  
  71. function mergeContent(file,scssPath) {
  72. let componentContent = readFile(file);
  73. let htmlRegex = /(templateUrl *:\s*[\"|\'])(.*[\"|\']\,?)/g;
  74. let scssRegex = /(styleUrls *:\s*)(\[.*\]\,?)/g;
  75.  
  76. let newContent = '';
  77. if (htmlRegex.test(componentContent) && scssRegex.test(componentContent)) {
  78. let contentArray = componentContent.toString().split(htmlRegex);
  79. contentArray[1] = 'template:`';
  80. contentArray[2] = content + '`,';
  81. contentArray.forEach(con => {
  82. newContent += con;
  83. })
  84. contentArray = newContent.toString().split(scssRegex);
  85.  
  86. return new Promise((resolve,reject) => {
  87. processScss(scssPath)
  88. .then(result => {
  89. newContent = '';
  90. contentArray[1] = 'styles:[`';
  91. contentArray[2] = result + '`],';
  92. contentArray.forEach(con => {
  93. newContent += con;
  94. })
  95. resolve(newContent)
  96. },err => {
  97. reject(err);
  98. })
  99. });
  100. }
  101. }
  102.  
  103. fildFile(filePath);

ts编译(tsconfig-aot.json)

  1. {
  2. "extends": "./tsconfig.json","compilerOptions": {
  3. "outDir": "./publish/src","baseUrl": "./","declaration": true,"importHelpers": true,"module": "es2015","sourceMap": false,"target": "es2015","types": [
  4. "node"
  5. ]
  6. },"files": [
  7. "./src/temp_components/ng-kylin.module.ts"
  8. ],"angularCompilerOptions": {
  9. "annotateForClosureCompiler": true,"strictMetadataEmit": true,"flatModuleOutFile": "index.js","flatModuleId": "ng-kylin","skipTemplateCodegen": true
  10. }
  11. }

rollup打包 (rollup-config.js)

  1. import resolve from 'rollup-plugin-node-resolve'
  2. import replace from 'rollup-plugin-replace'
  3.  
  4. const format = process.env.ROLLUP_FORMAT || 'es'
  5.  
  6. let globals = {
  7. '@angular/animations': 'ng.animations','@angular/cdk': 'ng.cdk','@angular/core': 'ng.core','@angular/common': 'ng.common','@angular/compiler': 'ng.compiler','@angular/forms': 'ng.forms','@angular/platform-browser': 'ng.platformBrowser','moment': 'moment','moment/locale/zh-cn': null,'rxjs/BehaviorSubject': 'Rx','rxjs/Observable': 'Rx','rxjs/Subject': 'Rx','rxjs/Subscription': 'Rx','rxjs/observable/fromPromise': 'Rx.Observable','rxjs/observable/forkJoin': 'Rx.Observable','rxjs/observable/fromEvent': 'Rx.Observable','rxjs/observable/merge': 'Rx.Observable','rxjs/observable/of': 'Rx.Observable','rxjs/operator/auditTime': 'Rx.Observable.prototype','rxjs/operator/catch': 'Rx.Observable.prototype','rxjs/operator/debounceTime': 'Rx.Observable.prototype','rxjs/operator/distinctUntilChanged': 'Rx.Observable.prototype','rxjs/operator/do': 'Rx.Observable.prototype','rxjs/operator/filter': 'Rx.Observable.prototype','rxjs/operator/finally': 'Rx.Observable.prototype','rxjs/operator/first': 'Rx.Observable.prototype','rxjs/operator/map': 'Rx.Observable.prototype','rxjs/operator/pluck': 'Rx.Observable.prototype','rxjs/operator/startWith': 'Rx.Observable.prototype','rxjs/operator/switchMap': 'Rx.Observable.prototype','rxjs/operator/takeUntil': 'Rx.Observable.prototype','rxjs/operator/throttleTime': 'Rx.Observable.prototype',}
  8.  
  9. if (format === 'es') {
  10. globals = Object.assign(globals,{
  11. 'tslib': 'tslib',})
  12. }
  13.  
  14. let input
  15. let file
  16.  
  17. switch (format) {
  18. case 'es':
  19. input = './publish/src/index.js'
  20. file = './publish/esm15/index.js'
  21. break
  22. case 'umd':
  23. input = './publish/esm5/index.js'
  24. file = './publish/bundles/ng-kylin.umd.js'
  25. break
  26. default:
  27. throw new Error(`format ${format} is not supported`)
  28. }
  29.  
  30. export default {
  31. input,output: {
  32. file,format,},exports: 'named',name: 'ngKylin',plugins: [replace({ "import * as moment": "import moment" }),resolve()],external: Object.keys(globals),globals,}

shell脚本定义执行流程(build.sh)

  1. #!/usr/bin/env bash
  2.  
  3. rm -rf ./publish
  4.  
  5. cp -r src/app/components src/temp_components
  6.  
  7. node ./html.merge.js
  8.  
  9. echo 'Generating entry file using Angular compiler'
  10. $(npm bin)/ngc -p tsconfig-aot.json
  11. rm -rf src/temp_components
  12.  
  13. echo 'Bundling to es module'
  14. export ROLLUP_FORMAT=es
  15. $(npm bin)/rollup -c rollup-config.js
  16. rm -rf publish/src/*.js
  17. rm -rf publish/src/**/*.js
  18. sed -e "s/from '.\//from '.\/src\//g" publish/src/index.d.ts > publish/index.d.ts
  19. sed -e "s/\":\".\//\":\".\/src\//g" publish/src/index.Metadata.json > publish/index.Metadata.json
  20. rm publish/src/index.d.ts publish/src/index.Metadata.json
  21.  
  22. echo 'Transpiling es module to es5'
  23. $(npm bin)/tsc --allowJs --importHelpers --target es5 --module es2015 --outDir publish/esm5 publish/esm15/index.js
  24.  
  25. echo 'Bundling to umd module'
  26. export ROLLUP_FORMAT=umd
  27. $(npm bin)/rollup -c rollup-config.js
  28.  
  29. echo 'Minifying umd module'
  30. $(npm bin)/uglifyjs publish/bundles/ng-kylin.umd.js --output publish/bundles/ng-kylin.umd.min.js
  31.  
  32. echo 'Copying package.json'
  33. cp package.json publish/package.json

至此,项目打包结束。

源码

猜你在找的Angularjs相关文章