Angular.dev 新文档站,看着不错。
signals 感觉不如 vue 那种方便,示例好像也没提到包裹对象的实践。
]]> addrLength = computed(() => { const user = this.dataService.user(); return user.addresses.length; });
使用 computed 重新构建新的数组,视图也不会更新
addresses = computed(() => { const user = this.dataService.user(); // transform data 后页面不会更新 // return user.addresses.map(addr => ({ address: addr, title: `Address-${addr.title}` })); // 直接返回 user.addresses ,页面会更新 return user.addresses; });
]]>空闲时间使用 Angular
复刻了一下 uvcanvas ,今天发布了最初的版本~ (也是第一次发布主题帖😳)
项目: https://github.com/teddingdev/ngx-uvcanvas
文档: https://ngx-uvcanvas.ife.app/
上面这两个都是 lambda ,然后又尝试了 ECS 容器,也可耻的失败鸟。最主要的是 angular 没有提供任何一丁点的部署文档,哪些被部署的地方,也没有任何预制的模板。
]]>{{accessdata|filterby:window['cache']['accessdata']}}
这种离谱代码,启用 strictTemplates 后 build 直接报了 999+ 个错误。WebStorm 即使不开 strictTemplates 也能用 Ctrl+B 跳转属性定义位置,VS Code 的 F12 只有在开启 strictTemplates 才能找到定义。我熟悉的很多前端扩展都在 VS Code 上,v 友有办法解决吗? ]]>我 NAS 上映射的驱动器,无法使用了。比如把 NAS 的路径映射为 W:\,然后在 W:\下创建 app ,现在创建后无法执行,报错,这导致无法多机开发。
组件多了一个 standalone: true 的概念,这样以前可以直接用的组件,都需要按需 import 一下,其实这样挺好的,防止不必要的加载,但代码改起来累死了,尤其是 material.angular 。。。
以前的 app.module.ts 不见了,很多都需要自己改地方
and much more....
此时文字 1 自动使用了 Material 的 Roboto 字体,但是在我的 windows 10 台式机的 chrome 下,文字 2 却使用了 Arial 字体。在 Windows 11 笔记本的 chrome 下,文字 2 也使用了 Arial 字体,但是好看很多。
把 sass 改成这样: mat-toolbar button color: red font-family: Roboto, "Helvetica Neue", sans-serif
发现文字 2 变成了红色,在 windows11 中也使用了 Roboto 字体,但是在 windows10 中居然还保持 Arial 字体。请问这是什么情况?
]]>家庭条件并不好,家里人自从高中起就很支持我计算机方面的兴趣,纵使之后可能得卖掉自己住的房子也坚持找中介送我去美国深造。在美的一个学期真真切切地感受到美国的物价对于留学生来说有多贵,几乎不敢买东西,但苦于未成年并且美国不允许第一年找实习,也暂时没找到途径打小黑工,没办法自己赚钱。
上个月刚过十八周岁生日,但直到最近才突然意识到可以在国内找实习了。。由于 Angular 在国内工作机会并不多,招聘网站上并没有什么实习机会,于是来这里碰碰运气。
简历( OneDrive ): https://1drv.ms/b/s!ArmN_DYQwMC8g-BEiie287s3b88WPA?e=waNeFu
这个链接里的简历里有些信息删掉了,因为不是很想在公共场合透露太多个人信息。。
这也是我的第一份求职简历,如果有发现有问题麻烦狠狠地告诉我!非常感谢!
有意向招实习生的请狠狠地联系我!开学期间我也能干活!!
邮箱: char2s@outlook.com
本人当前大三, 找到一个前端实习, 公司技术栈是 Angular. 本人有一定的前端基础, Vue 和 React 都比较熟悉, 但是从未接触过 Angular, 请问有什么推荐的 Angular 课程吗?
]]>已经将 7 、8 个项目升级完了,有一个 ssr 项目用了 Hydration ,终于不闪屏了[泪目]
晚点玩会 signal
]]>有人认为这是 Angular 稳定成熟的表现,也有人认为这是 Google 放弃 Angular 的前兆。在社区内充斥着各种消极情绪时,Angular 团队在一年时间内接连提出了 Standalone APIs RFC 和 Signals RFC 这两个提案,推出了全新的应用组织方式和与过去完全不同的基于 Signal 的响应性和数据流方案。Angular 似乎正在步入一个新的纪元。
Signals RFC 分为主 RFC 和四个子 RFC:
本文将概述主 RFC 和所有子 RFC 的内容,不包含笔者个人观点。需要注意的是,这些只是该 RFC 当前阶段( 2023/04/12 )的内容,RFC 可能随时更新,最终的实现可能有较大出入。
Signals RFC 是近年来 Angular 团队提出的规模最大,也最具颠覆性的提案,其目标是解决数个在社区中留存数年的问题,如基于 Zone.js 的变更检测的性能问题,基于 RxJS 的状态派生较为繁琐,无法便捷地对特定 Input 的变化作出响应等。
Angular 团队根据过去几年的社区反馈制定了以下目标:
ExpressionChangedAfterItHasBeenChecked
错误而 Signals RFC 则被视为是实现以上目标的基石。
Signal 指的是具有显式变化语义的值。在 Angular 中,Signal 是由调用后立即返回当前值的零参数的 Getter 函数表示的:
interface Signal<T> { (): T; [SIGNAL]: unknown; }
该 Getter 函数具有一个 [SIGNAL]
属性,框架可以用该属性辨识 signals 以用于内部优化。
Signal 本质上应当是只读的,只用于获取当前的值以及对值的变更做出响应。
Getter 函数用于访问当前值,同时将本次 Signal 的读取操作记录在一个 Reactive Context 中,用于构建响应式依赖关系图。
在 Reactive Context 外的 Signal 读取也是被允许的。这意味者非响应式的代码,如第三方库的代码,也可以读取 Signal 的值,而无需注意其响应式的本质。
Angular 的 Signal 库提供一个默认的 Writable Signal 的实现,用于通过其内置的方法变更 Signal 的值:
interface WritableSignal<T> extends Signal<T> { /** * 将 Signal 直接设置到一个新的值。 */ set(value: T): void; /** * 基于 Signal 的当前值以对值进行更新。 */ update(updateFn: (value: T) => T): void; /** * 通过对 Signal 的当前值进行直接的变化来更新 Signal 的当前值(不改变对象)。 */ mutate(mutatorFn: (value: T) => void): void; /** * 返回一个非 Writable 的 Signal ,该 Signal 访问当前 WritableSignal 但不允许对值进行变更。 */ asReadonly(): Signal<T>; }
通过 signal
函数可以创建 WritableSignal
的实例:
function signal<T>( initialValue: T, options?: {equal?: (a: T, b: T) => boolean} ): WritableSignal<T>;
用法示例:
const counter = signal(0); counter.set(5); counter.update(currentValue => currentValue + 1);
可以选择性的为 WritableSignal
指定一个 Equality 比较函数,如果该 Equality 函数确定两个值是相等的,那么:
默认的 Equality 函数使用 ===
来比较基本类型值,但比较对象和数组将会永远返回不等。这允许 Signal 持有非基本类型的值的同时,仍然可以传播其值的变更,例如:
const todos = signal<Todo[]>([{todo: 'Open RFC', done: true}]); // 不使用不可变数据时,我们仍然可以更新该列表并触发值的变更。 todos.mutate(todosList => { todosList.push({todo: 'Respond to RFC comments', done: false}); });
Signal 概念的其他实现是可能的:只要实现相应的接口,Angular 或任何第三方库都可以创建自定义的 Signal 版本。
在 Angular 选择的这一实现中,Signal 是由一个 Getter 函数表示的。使用这一 API 的优势有:
然而,Getter 函数也有诸多弊病:
在模板中的函数调用
多年来,Angular 开发者已经学会了对在模板中调用函数保持警惕。其出现的原因是组件的变更检测运行频繁,而函数则很有可能隐藏具有高计算成本的逻辑。
这些担忧并不适用于 Signal 的 Getter 函数。Getter 函数是相当高效的访问器,计算成本极低,因此反复频繁地调用 Signal 的 Getter 函数并不是一个问题。
然而,在 Signal 读取中使用函数调用仍然可能在会在刚开始时让那些习惯于在模板中避免函数调用的开发者感到困惑。
与类型缩窄的交互
TypeScript 可以在条件语句中缩窄一个表达式的类型。即使 user.name
可以被赋值为 null
,以下代码依然可以通过类型检测,这正是因为 TypeScript 知道在 if
的主体中, user.name
不可能是 null
:
if (user.name) { console.log(user.name.first); }
然而,TypeScript 并不会缩窄函数返回值的类型,因为其不能保证每个函数都像 Signal 函数这样每次都会返回相同的值。因此,上面的示例并不适用于 Signal:
if (user.name()) { console.log(user.name().first); // 类型错误 }
对于这个简单的示例,我们可以很简单地将 user.name()
提取为一个在 if
语句外的常量:
const name = user.name(); if (name) { console.log(name.first); }
然而在模板中,由于无法声明中间变量,这种方式将不在奏效。目前只能依赖一些 Workaround 来解决该问题。
替代语法
Angular 团队考虑了多种 Getter 函数的替代语法,包括 Vue 的 .value
语法,React 的 [value, setValue]
语法,Vue 的 Proxy
响应性,和 Marko/Svelte 的编译时响应性。详见 RFC 原文。
Computed Signal 是从一个或多个依赖值派生出的新的值,会在其依赖的值变更时更新。Computed Signal 也可以依赖其他 Computed Signals 。
示例:
const counter = signal(0); const isEven = computed(() => counter() % 2 === 0); const color = computed(() => isEven() ? 'red' : 'blue');
computed
函数的签名是:
function computed<T>( computation: () => T, options?: {equal?: (a: T, b: T) => boolean} ): Signal<T>;
computed
函数的参数中,名为 compuatation
的函数不应该有任何副作用 —— 对任何 Signal 的变更都应当被避免。Angular 的 Signal 库将会检测在 computation
函数中对其他 Signal 的变更并抛出异常。
与 Writable Signal 类似,Computed Signal 同样可以可选地指定一个 Equality 函数,用于在两个值被确定为相等时阻止更深层的依赖链的重新计算。
示例(默认的 Equality 函数):
const counter = signal(0); const isEven = computed(() => counter() % 2 === 0); const color = computed(() => isEven() ? 'red' : 'blue'); // 当将 counter 设置到一个不同的奇数值时: // - isEven 将必定重新计算(其依赖的值变更了) // - color 无需重新计算( isEven 的值没有变化) counter.set(2);
Angular 选择的用于实现 Computed Signal 的算法对计算的时机和正确性具有强有力的保证:
computation
函数不会被调用computation
函数被调用的次数是最少的。computation
函数永远不会为过时的值或是中间值执行,并且对知名的 "Diamond Dependency Problem" 免疫。防抖计算无需任何显式的“事务”或“批量”操作。Computed Signal 中的条件分支
Computed Signal 会跟踪在 computation
函数中读取了哪些 Signal ,以便知道何时需要重新计算。这个依赖集是动态的,并且会随着每次计算自我调整。因此,在该条件计算中:
const greeting = computed(() => showName() ? `Hello, ${name()}!` : 'Hello!');
如果 showName
的值改变了, greeting
总是会重新计算,但如果 showName
的值为 false
,那么 name
就不会是 greeting
的依赖,其值的变化也就不会导致 greeting
重新计算。
Effect 是具有副作用的操作。每当其中读取的任何一个 Signal 的值更改时,Effect 会自动安排重新运行。
声明 Effect 的基本 API 签名如下:
function effect( effectFn: (onCleanup: (fn: () => void) => void) => void, options?: CreateEffectOptions ): EffectRef;
用法示例:
const firstName = signal('John'); const lastName = signal('Doe'); // 这个 Effect 会向控制台输出 firstName 和 lastName ,并且每当他们的值变更时都会重新向控制台输出。 effect(() => console.log(firstName(), lastName()));
Effect 具有多种用途,包括:
Effect 函数可以选择性地注册一个清理函数。清理函数会在下一次运行改 Effect 前被执行,可以用于“取消”上一次运行 Effect 时遗留的工作。例如:
effect((onCleanup) => { const countValue = this.count(); let secsFromChange = 0; const id = setInterval(() => { console.log( `${countValue} 在 ${++secsFromChange} 秒内没有变化` ); }, 1000); onCleanup(() => { console.log('清理并重新安排 Effect'); clearInterval(id); }); });
Effect 的运行时机
在 Angular Signal 库中,Effect 总会在更改 Signal 的操作完成后运行。
鉴于 Effect 用途的多样性,可能存在各种不同的运行时机。这就是实际的 Effect 运行时机不能被保证,并且 Angular 可能会选择不同策略的原因。应用程序开发人员不应依赖于任何观察到的执行时间。唯一可以保证的是:
终止 Effect
每当一个 Effect 的依赖项的值变更,该 Effect 都会被安排运行。从这个角度上看,Effect 似乎是“永生”的,其永远准备着对 Reactive Graph 中发生的变化做出响应。这样的无限寿命显然不是我们想要的,因为 Effect 应当在应用结束或是其他 Lifespan Scope 结束时被终止。
Angular Effect 的默认寿命是与框架中的 DestroyRef
相关联的。也就是说,Effect 会尝试注入当前的 DestroyRef
实例,然后在其中注册其终止函数。
对于需要更详细的寿命控制的情景,可以在创建 Effect 时启用 manualCleanup
选项:
effect(() => {...}, {manualCleanup?: boolean});
当该选项启用时,即使创建该 Effect 的组件或是指令已被销毁,该 Effect 也不会被终止。
可以使用创建 Effect 时返回的 EffectRef
实例手动终止该 Effect:
const effectRef = effect(() => {...}); effectRef.destroy();
在 Effect 中更改 Signal 的值
Angular 团队普遍认为在 Effect 中更改 Signal 的值可能会导致预料外的表现(如无限循环)和难以跟踪的数据流。因此,任何尝试从 Effect 中更改 Signal 的值的操作都会向控制台输出一个错误并被阻止。
可以通过在创建 Effect 时启用 allowSignalWrites
选项来覆写该默认行为,如:
const counter = signal(0); const isBig = signal(false); effect(() => { if (counter() > 5) { isBig.set(true); } else { isBig.set(false); } }, {allowSignalWrites: true});
注意,一般来说使用 Computed Signal 是一种更声明式,更直观,且更可预测的同步数据的方式:
const counter = signal(0); const isBig = computed(() => counter() > 5);
剩下一大半因长度限制搬不过来,见知乎原文: https://www.zhihu.com/question/595093745/answer/2981152934
]]>
不得不说 Angular 的动画引擎是真的很强大,但即便如此有些动画效果比如 Shared Element Transition 和 Container Transform 还是没法直接用内置的动画引擎实现。这方面的动画效果的实现方式我是借鉴的 React 的 Framer Motion 里的 Layout Projection 技术。Layout Projection 的发明者 Matt Perry 在几年前有过一个关于这个技术的演讲,还发布了一篇技术细节博客,但无奈现在已经打不开了,此处多亏 taowen 在 GitHub Gists 上传的博客副本 我才得以在 Angular 实现 Layout Projection 。
如果你对这个项目有兴趣,希望你可以 star 一下项目的 GitHub 仓库,如果可以分享给你的朋友就更好了!如果可以 follow 一下我那就更好上加好了!:D
马上要出国读大学了,我希望能给教授留下一个深刻的第一印象,非常感谢!
]]>Reply 是一个邮件客户端,使用 Material Design 组件和 Material 主题定制来创建品牌交流体验。
codeRun(code: string): void { if (!this.viewState.source || !this.viewState.source.id) return; this.toolbarState.loading.run = true; this.toolbarState.enable.stop = true; this.viewTableState.loading = true; const param: ViewTestExecute = { sourceId: this.viewState.source.id, scriptType: 'SQL', size: this.toolbarState.limit.value, script: code, variables: [], columns: [], countTotal: true }; this.dataProviderService .execute(param) .pipe( catchError(exception => { this.toolbarState.loading.run = false; this.toolbarState.enable.stop = false; this.viewTableState.loading = false; throw exception; }) ) .pipe(takeUntil(this.destroy$)) .subscribe((result: QueryResult) => { this.viewState.execute = param this.toolbarState.loading.run = false; this.toolbarState.enable = {run: true, stop: false, save: true, setting: false, copy: false}; this.viewTableState = {...result, loading: false}; }); }
如上面这段代码,因为页面的标签例如 <spin [spining]='xxxloading'></spin>
这样,有一个加载状态,但是用
this.loading = true this.http.get().subscribe(xx=>this.loading=false)
这种改变 loading 状态的代码,感觉弄得我代码很不干净,有没有什么方法能尽量让改变页面状态代码精简些,让我的代码干净些
]]>考虑了之后想说 SSR 能不能解决这个问题,不过看了 Express 和其它一些解决方案,可能主要都是针对 SEO 设计的,好像并不能把 Angular 的逻辑全放在服务端,让浏览器只拿到 HTML 。
我前端完全小白,想请问大家有没有什么建议? SSR 这个思路能行吗?有没有其他推荐的方法?在这提前谢过
]]>Angular 文档上写的懒路由声明方式:
const routes: Routes = [ { path: 'customers', loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule) } ];
按照一般后台管理系统的方式,菜单列表都是从接口获取,然后前端再根据接口的列表注册路由。在 Angular 里使用 Router 的 resetConfig 方法可以更新注册路由,那么问题就是:接口返回回来的每个菜单对应的模块 /组件的信息肯定是字符串格式,要怎样的方式才能变成文档中声明所需的格式?
import('./customers/customers.module').then(m => m.CustomersModule)
这或许看起来更像是 TypeScript 的使用问题?网上查了一圈资料都没找到有关的信息(也可能是我方法不对),因此前端小白特来 V2 请教下各位大佬 Angular 下动态注册路由的正确方式,感谢!
]]>找了好几个扩展都不好用,实在不知道了。
]]>实际场景是订单管理,因此只需要列表视图。
有点像 Winform 的 ListView ,试了下表格很难实现,看了下 OneDrive 用的是几个 div ,来问问 V 友有没有现成的轮子。
如果没有的话能说说怎么实现最快么?
]]>Angular
开发小程序 Angular
实现使用Angular
开发小程序修改用于支持自定义构建
通过提前解析获得模板与样式,转换为小程序所需的
用来支持
ngZone
与Angular
默认全局引用
通过实现自定义的 platform,给予小程序的启动上下文支持
原渲染工厂支持的是 dom 渲染,但是小程序不需要
主出口预先加载相关依赖,为后面的 page 做准备
需要在预处理结束时,清除文件缓存
只有被注册,还会自动的查询依赖关系与生成
小程序自带的一些生命周期
APP_TOKEN
可以获得 App 实例COMPONENT_TOKEN
,PAGE_TOKEN
可以获得组件对应的小程序组件实例
对于其他指令及自定义指令,暂未实现
路由是否实现主要看小程序的使用场景需不需要路由这个东西
除非模板运行动态按需加载
管道
,表单
,非结构型指令
的支持请教一下大佬们, 我现在有一个情况是这样的,后端我统一 返回格式是:
{ "status": 200, "msg: "xxx success", "data": any }
我想通过 拦截器 或者在 service 里面将 status 判断好了, 给 component 的数据就 仅是上面的 data, 出错就给个 默认值 这样的效果,但我实在不知道怎么实现了, 还请大家指点一二。
npm run dev:ssr
Angular 是怎么区分哪一部分的 JS 在浏览器端执行,哪一部分在 Server 端执行的?
很可能是我作为后端程序员对 SSR 的认识存在偏颇。多多指教!
]]>虽然公司用 vue,但是 ng 自己还是坚持学,都说 ng 难,vue 搞工程化也是搞死我了😂,不过 vite 开发是真爽
]]>将来我我来用 angular 开发的话,估计思路的话,不会像 angular 传统项目那样各种注入,应该还是和 vue 、react 差不多吧,angular 自带的库不用,各种第三方请求库,import 、export,能不注入就不注入了,维护下 module 就好。
]]>今天才看到多了一个 10 的书…,仔细看目录,凑字数的嫌疑也很大
ps:还是很喜欢 ng 这种大一统的架子,省心好多…
]]>为此,本文简单介绍自己在从 Angular 8 升级到 9 最终到 10 时遇到的问题及相应的解决方法,仅供参考。
首先,Angular 官方文档提供了详细的升级说明,建议在升级项目前首先通览相关文档,了解可能存在的问题。可以从下面的链接找到升级到 Angular 10 的最新信息。
https://angular.io/guide/updating-to-version-10
下面是自己在升级时实际操作的几个主要步骤:
对上述步骤的一些详解,请移步我的博客文章。
希望能对大家有所帮助。
]]>angular
, 但是感觉angular
的模板"不够 typescript"
, 例如官网上的一段template
: <h2>Products</h2> <div *ngFor="let product of products"> <h3> {{ product.name }} </h3> </div>
单纯看这个模板, 完全看不出来product
的类型, 同时typescript
和eslint
也没能力管控这个模板中的变量。相对的来说, 在react
的tsx
中, typescript
和eslint
是能够对变量进行充分的静态分析的。
无意引战, 确实希望试试angular
, 可是, 是我使用的姿势不对吗?
丑话说在前头,如果有错误,欢迎斧正,不要玻璃心。
说实话虽然在灵雀云用 Angular
做着企业级的应用,但我个人是很不认可它大而全的哲学的,虽然我也在 Angular
相关专栏发过几篇水文,但是习惯了 React
和 Vue
『纯粹』框架的哲学后依旧很不喜欢(不喜勿喷),但我很感谢 Angular
带我入了 rxjs
的坑,仅此而已。
Angular
的模块系统和 bundler
都是自己搞得一套标准『黑盒』,也就是说没办法在各个框架直接平滑地切换,比如 http 请求库,其他框架都可以随便选,一般比较通用的是 axios
,还有 axios-observable
支持 Observable
API,但 Angular
为了更好地支持自己的 DI 又搞了一个 @angular/common/http
,其实大可以把 DI
部分抽成一个库嘛(以前是单独抽了一个 DI
包的,后面又被合到 core
里了),这样所有框架都能使用你这个 DI
系统,岂不美哉?ts
打包非要整出一个 ngfactory
的概念,连基本的库打包都要有个专门的 ng-packagr
,真心受不了,学会 rollup
/webpack
已经很不容易了,换个前端框架还要学这个???还有各种 NgModule
的报错信息实在不忍直视,用了 @angular/router
后它还直接给我退出到上一个无报错的页面了,也就是调试的时候我还得再点一次保存页面的入口,如果还有错,还得继续来?!
说到这里实在不得不再吐槽 Angular
对 hmr(hot module reload)
的支持简直弱爆了,甚至可以说是『垃圾』,(我的个人体验来说 Vue
的 hmr
支持是最好的),开发个新功能页面不停地 reload, reload, reload... 我已经放弃挣扎了。
有人会说这些 @angular/cli
都帮你解决了啊,这还是刚刚『黑盒』的问题,这也是我自己写项目都是不用什么所谓的 cli
的,而 @angular/cli
里我只用会用两个命令:ng serve
和 ng build
,而且是在用 @alauda/custom-webpack 的前提下,因为:我压根儿不需要默认的那套打包配置,对我们的生产力反而是阻碍。为什么 Angular
不能往和其他框架一样纯框架的方向走呢?那些什么 ng lint/test
之类的命令真是醉了,这不是脱裤子放屁吗?自己加个 lint/test
脚本的事儿我为什么要去单独学啊?非得在angular.json
里配置?说到 angular.json
就更可笑了,连 js 格式都不支持?每个公司不同项目都要 copy/paste 吗?这也是为什么我在灵雀云搞了 @alauda/custom-webpack 的原因,因为自定义 webpack
配置在公司内部项目里也是通用的啊。
我们再来看一个 css
打包的问题,Angular
的方案是把 css
文件内容处理完转化成字符串,然后运行时由 @angular/core
进行插入,这有什么问题?问题大了,比如 A
/B
组件都在 styleUrls
里引用了 common.css
那么最终它会把 common
inline 到 A
和 B
上,也就是 css
内容是重复的,什么 vue-style-loader
它不香吗?明明是 bundler
该做的事情为什么要跑到框架层去做???
还有之前吹 JIT
到 AOT
优化的事儿,你看 vue
吹过吗?vue
/vue-loader
一直都是原生支持所谓的『AOT
』的,到了 Angular
这儿就变成了大优化了,而且所有相关库和 App
都要做一些必要的修改才能支持 AOT
,而且这个 AOT
呢还有各种乱七八糟的限制,一不小心就是 build error
说什么哪里哪里不支持箭头函数、哪里哪里得把变量导出去,可这些 JIT
的时候明明都是好好的。对了,JIT
和 AOT
的变更检测次数还是策略好像还不太一样,上次 ngChina
的时候有嘉宾演示了一下,这真不是劝退吗?
再来,Angular
的维护者们似乎都喜欢自己玩儿自己的,连 i18n
方案它都帮你内置了,当然我肯定是不用的,因为和其他框架的使用方式差异太大,实在诡异。我们之前是用的 @ngrx/translste
,今年我『二进宫』回来就把这部分精简重写了,只保留并定制我们自己需要的东西。也就是说官方内置的方案它不一定是最好的或者说是对所有人都适用的。
最后呢,再说说几个框架对 SSR
的支持,Vue
是有官方指导的,React
提供了基础能力,但是具体怎么玩儿全凭社区,Angular
我感觉是对这一块儿不上心的,好像到现在都只有 express
相关的指导,不过毕竟目标是『企业级应用』嘛,基本是不需要考虑 SEO 问题。那既然 Angular
是更面向企业级应用的,那么个人应用就没必要选它了嘛。那既然我个人应用都没有用过 Angular
我怎么敢在公司项目里去用呢?(此处手动狗头)
所以像 React
和 Vue
这种的轻量级框架才会更流行,因为它们才代表了自由,而我和很多人一样不喜欢被束缚,更何况只是一个前端框架,所以我的个人项目是绝不会考虑用 Angular
的。而公司的项目,当初选择 Angular
的大哥已经后悔并离职去写 React
了,而现在的我们这些接盘侠还将继续使用,毕竟历史包袱尾大不掉。但我仍然要感谢 Angular
带我走入 Observable
的世界,正如 @徐飞 所说,我相信 React
/Vue
社区经过 hooks
的洗礼也可能会拥抱天然组合的 Observable
。
写着写着好像变成了抨击 Angular
的文章,但其实不是,萝卜青菜各有所爱,有人喜欢框架的约束,让不太会写代码的人也能写出不那么差的代码,而我个人喜欢自由的代码,这样才能显示出我的架构能力不是?(继续狗头)
本文首发于 知乎专栏 - 1stG 全栈之路
]]>很惭愧,几年里没有做什么特别有技术含量的工作。 只是提炼出一个很基础的模板,帮助开发者快速创建一个 SPA ( Single Page Application )站点,或是供对 Android 感兴趣的读者了解 Android 的语法和基本的框架机制。该模板先分享于此 —— AngularGo on GitHub。
该模板基于目前最新的 Angular 8,且会持续跟进更新。在 Angular CLI 自动创建的范例项目的基础上,目前版本的 AngularGo 还包含以下内容:
AngularGo 还很初步,很多细节因水平有限和时间限制写得也比较粗糙,想必会有其他优秀的开源模板提供了更好的实现。从某种意义上来讲,该模板一方面是对自己经验得一个整理,同时期望能起到一个抛砖引玉的作用。希望对读者有帮助,也欢迎批评指教。
]]>Material 主题可以自定义,主要是默认主题颜色太激进了,有没有好看的主题包推荐?
]]>