angular模块库开发实例

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

下图是button组件的基础文件。

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

import {Component, Renderer2, ElementRef, AfterContentInit, ViewEncapsulation, Input} from '@angular/core';@Component({selector: '[nk-button]',templateUrl: './nk-button.component.html',encapsulation: ViewEncapsulation.None,styleUrls: ['./nk-button.component.scss']
})
export class NkButtonComponent implements AfterContentInit {_el: HTMLElement;_prefixCls = 'ky-btn';_type: string;_size: string;_shape: string;_classList: Array<string> = [];@Input()get nkType() {return this._type;}set nkType(value) {this._type = value;this._setClass();}@Input()get nkSize() {return this._size;}set nkSize(value: string) {this._size = value;this._setClass();}@Input()get nkShape() {return this._shape;}set nkShape(value: string) {this._shape = value;this._setClass();}constructor(private _elementRef: ElementRef, private _renderer: Renderer2) {this._el = this._elementRef.nativeElement;this._renderer.addClass(this._el, this._prefixCls);}ngAfterContentInit() {}/***设置class属性*/_setClass(): void {this._classList = [this.nkType && `${this._prefixCls}-${this.nkType}`,this.nkSize && `${this._prefixCls}-${this.nkSize}`,this.nkShape && `${this._prefixCls}-${this.nkShape}`].filter(item => {return item;});this._classList.forEach(_className => {this._renderer.addClass(this._el, _className);});}
}

针对核心概念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文件

let fs = require('fs');
let pathUtil = require('path');
let sass = require('node-sass');
let filePath = pathUtil.join(__dirname, 'src', 'temp_components');let fileArray = [];function fildFile(path) {if (fs.statSync(path).isFile()) {if (/\.component.ts/.test(path)) {fileArray[0] = path;}if (/\.html$/.test(path)) {fileArray[1] = readFile(path)}if (/\.component.scss$/.test(path)) {fileArray[2] = path;}} else if (fs.statSync(path).isDirectory()) {let paths = fs.readdirSync(path);if (fileArray.length === 3) {writeFile(fileArray);fileArray = [];}paths.forEach((p) => {fildFile(pathUtil.join(path, p));});}}function readFile(file) {return fs.readFileSync(file);
}function writeFile(fileArray) {let file = fileArray[0];let content = fileArray[1];let scssPath = fileArray[2];mergeContent(file, content, scssPath).then(result => {if (!result) return;fs.writeFile(file, result, function (err) {if (err) console.error(err);console.log('file merge success!');})});}/*** 转换scss* @param path* @returns {Promise}*/
function processScss(path) {return new Promise((resolve, reject) => {sass.render({file: path}, (err, result) => {if (!err) {resolve(result.css.toString())} else {reject(err);}})})
}function mergeContent(file, content, scssPath) {let componentContent = readFile(file);let htmlRegex = /(templateUrl *:\s*[\"|\'])(.*[\"|\']\,?)/g;let scssRegex = /(styleUrls *:\s*)(\[.*\]\,?)/g;let newContent = '';if (htmlRegex.test(componentContent) && scssRegex.test(componentContent)) {let contentArray = componentContent.toString().split(htmlRegex);contentArray[1] = 'template:`';contentArray[2] = content + '`,';contentArray.forEach(con => {newContent += con;})contentArray = newContent.toString().split(scssRegex);return new Promise((resolve, reject) => {processScss(scssPath).then(result => {newContent = '';contentArray[1] = 'styles:[`';contentArray[2] = result + '`],';contentArray.forEach(con => {newContent += con;})resolve(newContent)}, err => {reject(err);})});}
}fildFile(filePath);

ts编译(tsconfig-aot.json)

{"extends": "./tsconfig.json","compilerOptions": {"outDir": "./publish/src","baseUrl": "./","declaration": true,"importHelpers": true,"module": "es2015","sourceMap": false,"target": "es2015","types": ["node"]},"files": ["./src/temp_components/ng-kylin.module.ts"],"angularCompilerOptions": {"annotateForClosureCompiler": true,"strictMetadataEmit": true,"flatModuleOutFile": "index.js","flatModuleId": "ng-kylin","skipTemplateCodegen": true}
}

rollup打包 (rollup-config.js)

import resolve from 'rollup-plugin-node-resolve'
import replace from 'rollup-plugin-replace'const format = process.env.ROLLUP_FORMAT || 'es'let globals = {'@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',
}if (format === 'es') {globals = Object.assign(globals, {'tslib': 'tslib',})
}let input
let fileswitch (format) {case 'es':input = './publish/src/index.js'file = './publish/esm15/index.js'breakcase 'umd':input = './publish/esm5/index.js'file = './publish/bundles/ng-kylin.umd.js'breakdefault:throw new Error(`format ${format} is not supported`)
}export default {input,output: {file,format,},exports: 'named',name: 'ngKylin',plugins: [replace({ "import * as moment": "import moment" }), resolve()],external: Object.keys(globals),globals,
}

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

#!/usr/bin/env bashrm -rf ./publishcp -r src/app/components src/temp_componentsnode ./html.merge.jsecho 'Generating entry file using Angular compiler'
$(npm bin)/ngc -p tsconfig-aot.json
rm -rf src/temp_componentsecho 'Bundling to es module'
export ROLLUP_FORMAT=es
$(npm bin)/rollup -c rollup-config.js
rm -rf publish/src/*.js
rm -rf publish/src/**/*.js
sed -e "s/from '.\//from '.\/src\//g" publish/src/index.d.ts > publish/index.d.ts
sed -e "s/\":\".\//\":\".\/src\//g" publish/src/index.metadata.json > publish/index.metadata.json
rm publish/src/index.d.ts publish/src/index.metadata.jsonecho 'Transpiling es module to es5'
$(npm bin)/tsc --allowJs --importHelpers --target es5 --module es2015 --outDir publish/esm5 publish/esm15/index.jsecho 'Bundling to umd module'
export ROLLUP_FORMAT=umd
$(npm bin)/rollup -c rollup-config.jsecho 'Minifying umd module'
$(npm bin)/uglifyjs publish/bundles/ng-kylin.umd.js --output publish/bundles/ng-kylin.umd.min.jsecho 'Copying package.json'
cp package.json publish/package.json

至此,项目打包结束。

源码

angular模块库开发实例相关推荐

  1. vue2项目复习01-关闭elint检校,src文件别名,路由传参的对象写法,代理解决跨域问题,nprogress,vuex状态管理库,store的模块式开发,节流与防抖,编程式导航+事件委托路由跳转

    1.关闭elint语法校验 创建vue.config.js //关闭elint语法校验 {lintOnSave:false; } 2.src文件夹配置别名 jsconfig.json配置别名 @代表s ...

  2. 使用SharePoint Designer定制开发专家库系统实例!

    将近大半年都没有更新博客了,趁这段时间不忙,后续会继续分享一些技术和实际应用.对于Sharepoint的定制开发有很多种方式,对于一般的应用系统,可以使用Sharepoint本身自带的功能,如列表作为 ...

  3. php magento 开发,magento 2模块开发实例helloworld模块 hello world 程序 c语言hello world代码 c语言hello worl...

    data-id="1190000005008433" data-license="cc"> 1.在app/etc/config.php中添加自定义的模块( ...

  4. 8、合宙Air模块Luat开发:基于官方库的二次封装,使串口更加易用

    目录 点击这里查看所有博文 本系列博客,理论上适用于合宙的Air202.Air268.Air720x.Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持). 先不管支不支持,如果 ...

  5. 2021物联网国赛Lora模块通用库开发——A卷

    2021物联网国赛Lora模块通用库开发--A卷 1:声明全局变量和导入本次所使用到的包 #include "hal_oled.h" int Stat_key=0; //记录按键次 ...

  6. pb怎么封装com组件_从零开始构建 Angular 组件库

    NG-ZORRO 组件库官网地址:Ant Design Of Angular Github地址:NG-ZORRO/ng-zorro-antd 更新:视频已上传 谢亚东演讲视频_腾讯视频​v.qq.co ...

  7. Angular模块/服务/MVVM

    angular 与 jquery 共同点 都是一个前端的JS文件而已 不同点: angular 是一个框架 我们写的代码由框架调用,我们必须要按照特定的规则编写代码 jquery是一个库 我们调用库预 ...

  8. OpenCV android sdk配置OpenCV android NDK开发实例

    OpenCV android sdk配置OpenCV android NDK开发实例 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/det ...

  9. RDIFramework.NET-.NET快速信息化系统开发整合框架 【开发实例 EasyUI】之产品管理(MVC版)...

    RDIFramework.NET-.NET快速信息化系统开发整合框架 [开发实例 EasyUI]之产品管理(MVC版) RDIFramework.NET-.NET快速开发整合框架 [开发实例]之产品管 ...

最新文章

  1. 各种开发API文档+开发工具
  2. CreateInstall5.7.2 帮助文档翻译
  3. 西数硬盘刷新固件_玩4k如何选硬盘?究竟那些硬盘适合你
  4. 总结:JDK1.5-JDK1.8各个新特性
  5. [No0000FF]鸡蛋煮熟了蛋黄为什么发黑?
  6. Android 使用 DownloadManager 管理系统下载任务的方法,android管理系统
  7. linux centeros 操作系统
  8. 互联网靠什么赚钱和发展趋势
  9. 阿里巴巴产品经理面试主观题
  10. 苹果应用提审与NAT64
  11. U盘做系统时如何设置USB为第一启动盘
  12. 进程和线程的区别是什么?
  13. 匈牙利命名法、驼峰式命名法、帕斯卡命名法、下划线命名法
  14. MATLAB-中文乱码问题解决
  15. 01-初识 pygame 游戏开发
  16. Exchange Server 2016 部署
  17. 关于数据治理的读书笔记 - 数据治理路线图规划
  18. 万剑归宗—架构设计中的抽象思维与具象思维
  19. 免费ARP(Gratuitous ARP)的介绍
  20. Webpack 打包 Javascript 详细介绍

热门文章

  1. Android adb你真的会用吗?
  2. POJ-1094 Sorting it All Out
  3. 基本概念学习(9001)---指令系统
  4. SaltStack组件
  5. 数据库连接池DBPool分析(一):简介
  6. 组合数学(全排列)+DFS CSU 1563 Lexicography
  7. 使用组策略禁用注册表编辑工具
  8. 如何制作网线标签和贴标签
  9. linux重新安装mysql步骤_Linux下MySQL安装及相关操作过程
  10. dbForge Studio 2020 for MySQL中文版