力争国内 Angular 5 第一篇轮子
最近轮子造的比较多,意在给初学者一个参考例子,目前反馈来看,如果技术栈不符,很少有人会点进来读,以后可以考虑转换博文类型了。
之前写过一篇 Angular2 从搭建环境到开发,在 segmentfault 上得到了 2016 年第四季度的 top writer 文章表里第四名,如今已经 angular 5
给大家的常规印象就是,大版本跳跃会带来 breaking change,因为 angular 从 1.x 到 2.x 简直是两个框架,不对,就是两个框架。
angular 1.x 叫 angular.js 而 angular 2.x 以后就叫 angular,两个版本分别托管在两个 github repo。
更让我比较惊讶的是 angular.js 的 star 近乎 angular 的 double,而且社区更繁荣,本文苦在找能配合 angular 5 使用的组件,因为框架刚升级,相应的组件都还未更新,下文会告诉大家一个小技巧。
angular 2 到 4 到 5,的组件数成幂指数递减,但是好在可以轻松向后扩展,如果熟悉 angular 2 那么本项目完全可以看懂。
其实写轮子看文档谁都会写,我尽量多说些坑点,让开发者少踩坑。
撸起袖子开整。
搭建开发环境
1 | npm install -g @angular/[email protected] |
这里直接把版本指向 1.5.0
1 | ng new PROJECT-NAME |
这时依赖已经安装完成,执行 ng -v
,可以看到如下
1 | ng serve |
默认 4200 端口,就可以看到初始化页面了。
安装过程可能较长,建议本地先安装 yarn,安装依赖的时候 cli 会自动使用 yarn 装依赖,会快不少。
到这就可以开发了。
开发
udao 词典的公开接口已经废弃,这里拿来的接口是非官方的,支持的功能有限
这里明确要用的 UI 库是 ng-bootstrap,loading 用的是 ngx-loading
安装时会有依赖版本不符的警告,如下
但是勉强能用,前面说想找到合适的组件库比较困难,这里讲个小技巧,去 google 搜 angular [some component]
基本都是 angular 1.x 的组件,那么根据历史分析组件命名有 ng-
ng2-
,到了 4 大家感觉心累所以干脆叫 ngx-
,搜索直接搜 ngx-[some component]
。
这里为什么是 ng-bootstrap
而没选 ngx-bootstrap
呢,这里真的有 ngx-bootstrap
,因为 ng-bootstrap
只支持 bootstrap4
,后者支持 3 和 4,为了避免版本纠纷,直接用了 ng-bootstrap
。
说到这远远不能证明 angular 5 可以用这个库,我的评判标准是 angular 4,如果支持 angular 4,那么 90% 支持 angular 5,因为改动确实不大。
路由
目前此项目只涉及到 4 个路由。
/
主页/translate
翻译/search
模糊搜索/detail/:word
单词详情
在 app.module.ts
下面定义路由
1 | const routes: Routes = [ |
这里说下路由跳转相关的问题,在 angular 5 里依然分为 a 标签的跳转和 js 跳转
- a 标签的写法
1 | @Directive({ selector: ':not(a)[routerLink]' }) |
本项目例子:
1 | <li class="nav-item"> |
这里注意一个坑,第一个
li
标签,多了[routerLinkActiveOptions]="{exact: true}"
,如果不加的话,会导致/
路由下,active 不触发的情况。
- js 写法
1 | class Router { |
本项目例子:
1 | gotoDetail ({ entry }) { |
两个例子相比文档的概览都是最简单的用法,有需要的话可以看下其它方法,基本可以满足所有的路由需求。
请求
这里不同于 vue 和 react,angular 提供了前端全栈的解决方案,包含了 http 模块,只需要在 app.module.ts
里面引入
1 | import { HttpClientModule } from '@angular/common/http' |
请求的语法也很简单,具体可以到 github 看代码。
这里说一个小坑,在实现 detail
路由的时候在 ngOnInit
钩子里拿到当前路由参数进行请求,改变路由时没有触发请求更新,最后改版如下。
代码如下
1 | ngOnInit () { |
之前无效是因为没写 this.route.params.subscribe((params) => {})
,所以每次不会触发监听
这里的 subscribe
会一直监听 this.route.params
的变化。
请求路径
如同 axios 的 baseURL,在请求时我们不希望每个请求都写完整路径,需要配置全局的 baseURL 来使得请求路径简短。
angular 里面需要一个 @Injectable
,熟悉的概念——依赖注入,关于细则有跟多文章介绍,这里说下针对此需求的解决方案
1 | @Injectable() |
这段代码解决了 baseURL 的问题。
请求转发
注意到上一节的这里 const url = 'https://proxy-oagpwnbkpe.now.sh'
,根路径不是有道的路径。
还是做了一层 node 的 proxy 处理。跨域问题还是要处理。
node 服务的代码也十分简单,这里使用了 fly 进行 node 端请求
代码如下
1 | const express = require('express') |
重点是在返回头 set 一个 Access-Control-Allow-Origin: *
,这样浏览器就不会拦截请求了。
数据流动
在 detail
页面,拆分了 5 个子组件,当然父子组件是十分简单的单向数据流
例:父组件的 html 如下
1 | <app-detail-phrs-list-tab [simple]="simple" [ec]="ec"></app-detail-phrs-list-tab> |
子组件的 component.ts
如下
1 | export class DetailPhrsListTabComponent { |
就可以使用 @Input
取到父组件传进来的值了,说到这里全局的状态管理怎么做,要看下项目的复杂度
简单的全局状态管理可以创建一个 global.ts
,再创建依赖注入,如下
1 | // globals.ts |
在组件中可以这样调用
1 | // hello.component.ts |
另一种方式是 SPA 开发者熟悉的全局状态管理库,如 flex, redux
angular 也提供了 angular-redux,复杂应用中建议使用。
打包上线
打包命令围绕 ng build
,提供几种配置参数,这里不赘述,
部署这里使用的是 surge
友情提示:不要将私有项目部署到此类公开服务,弊端很多。
总结
不论哪种前端框架,都有它的长处,由于此项目较小,到这里没机会释放 rxjs
的威力,angular-cli 默认装了这个库,处理复杂的异步数据流非常高效,写了好多轮子,毕竟还是样例,但是,折腾不能停。
相关文档
本次 angular 5 更新相关文档如下
官方文档:https://next.angular.io/docs
官方博客:https://blog.angular.io/version-5-0-0-of-angular-now-available-37e414935ced
官方cli:https://github.com/angular/angular-cli/releases/tag/v1.5.0
尽量翻墙查看,国内 https://angular.cn/ 文档还没更新。