Angular 等了三年,那个她已经来了 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhennann
V2EX    前端开发

Angular 等了三年,那个她已经来了

  •  
  •   zhennann
    zhennann 2024-05-27 18:26:52 +08:00 2198 次点击
    这是一个创建于 532 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Angular 生态丰富,功能强大,支撑了许多大型项目的开发。而且一直在前方等待着其他框架跟上。但是不得不直面的一个问题就是:“在等待其他框架跟上的这三年”,Angular 在陆陆续续抛弃之前引以为豪的设计。又由于大量的历史包袱,这些设计变更又做得扭扭捏捏,做不到轻装上阵。比如 NgModule 之于 Standalone ,zone.js 之于 Singals ,Rxjs 更是一言难尽

    Angular 虽然有许多超前的架构设计和工程化能力,但是就目前而言,仍有以下不足:

    1. 响应式系统不好用:即便是新引入的 Signal ,如果要访问一个状态值,需要像函数一样调用,这是反直觉的实现方式
    2. 对 tsx 支持不友好:全网很难找到 angular+tsx 的最佳实践。单靠模版,支撑大型业务系统的开发,难度是很大的
    3. ioc 容器太过繁琐:看看文档就知道了,angular 劝退新人的点很多,ioc 繁琐是最主要的
    4. 模块化隔离性不够好,拖泥带水:虽然 angular 引入了模块化概念,但是模块之间隔离不彻底。比如我在 A 模块实现了一个 service ,如果要在 B 模块使用,就需要明确指定 service 在 A 模块的文件路径,而不是指定一个名称就行。这样就让模块耦合很深。类似这样的设计问题还有很多

    Cabloy-Front就很好的解决了 angular 的这些短板。Cabloy-Front 是一款支持 ioc 容器的 Vue3 框架,有以下特点:

    1. 底层采用 vue3 的响应式系统:在 ioc 容器的加持下,定义响应式状态不再需要ref/reactive,也不再需要ref.value
    2. 在独立的 render class 中书写 tsx 代码,从而让 tsx 代码更加舒展、从容
    3. 提供了两类 ioc 容器:一类是全局 ioc 容器,可以实现 pinia 的能力。另一类是组件实例 ioc 容器,该容器与 Vue 组件实例绑定,在这个容器中的所有 Class 实例都可以在组件实例范围之内共享数据和逻辑
    4. 模块化体系:实现了完全隔离的模块化体系。模块作为一个相对独立的业务单元,包含各种类型的资源,包括 Config 配置、Constant 常量、Locale 国际化、Error 错误异常、Component 组件,等等。在跨模块访问这些资源时,是基于名称寻址,而不是基于资源的原始文件路径寻址,因此,心智负担更低
    5. 更优雅的 ioc 容器开发体验:采用依赖注入依赖查找相结合的方式,大量减少装饰器的使用,让代码更简洁、更优雅。优先使用依赖查找的机制可以达到化类型于无形的效果?简而言之,就是无须标注类型,却能享受到“类型约束”和“智能提示”的好处

    口说无凭,我们简单看一下cabloy-front的代码风格是怎样的:

    1 、定义响应式状态

    在组件中定义一个响应式变量 count ,并且添加两个方法修改变量

    export class MotherPageCounter { count: number = 0; inrement() { this.count++; } decrement() { this.count--; } } 

    2 、使用响应式状态

    采用 tsx 语法使用 count

    export class RenderPageCounter { render() { return ( <div> <div>count(ref): {this.count}</div> <button OnClick={() => this.inrement()}>Inrement</button> <button OnClick={() => this.decrement()}>Decrement</button> </div> ); } } 

    3 、逻辑抽离

    将 count 逻辑抽离出来,创建一个 Counter Bean

    @Local() export class Counter { count: number = 0; inrement() { this.count++; } decrement() { this.count--; } } 

    4 、在组件中注入并使用

    使用装饰器函数 @Use 注入 bean

    export class MotherPageCounter { @Use() $$counter: Counter; } 

    采用 tsx 语法使用已注入的 bean 实例

    export class RenderPageCounter { render() { return ( <div> <div>count(ref): {this.$$counter.count}</div> <button OnClick={() => this.$$counter.inrement()}>Inrement</button> <button OnClick={() => this.$$counter.decrement()}>Decrement</button> </div> ); } } 

    Cabloy-Front 框架已开源:https://github.com/cabloy/cabloy-front

    12 条回复    2024-05-29 06:55:02 +08:00
    07aPzknB16ui9Cp3
        1
    07aPzknB16ui9Cp3  
       2024-05-27 18:41:14 +08:00
    老实说在我的理念里 Vue 的 tsx + 组合 API 就是 next gen Angular ,我知道 Angular 面向的人群和设计理念,但它使用的设计模式毕竟在 JS 生态中是可选项,不如只保留最轻便的服务容器( Vue provide )在特定场景下提供便利,剩下的让用户来决定(比如用专门的状态管理还是随手写一个 hook ),而不是还要捆绑诸如 rxjs 之类的东西;我以为楼主的项目是给 Angular 用的,定睛一看是 Vue 的服务容器,感觉 Vue team 的人看到会哭瞎,这不是 Vue Class Component 还魂么,好不容易才把 this 送走的这下全回来了
    zhennann
        2
    zhennann  
    OP
       2024-05-27 20:22:11 +08:00
    @wuzzispacelake Cabloy-Front 采用的 class 机制与 Vue Class Component 有本质区别。Vue Class Component 不好用,是因为想用 class 解决 Vue 组件的定义问题。而 Cabloy-Front 仍然采用 Vue3 setup 语法糖来定义组件(如组件的 Props 和 Emits ),仅在业务层面引入 ioc 容器和 class 。这样,就结合了二者的优点,让代码更加简洁优雅。在 ioc+class+ts 的语境下,this 不仅可以清晰定位代码来源,还能更加快捷的访问系统能力。this 的弊端,仅仅是针对 mixins 和 options api 而言。
    rxjs 是 angular 中的用法,Cabloy-Front 中并没有采用。
    Cabloy-Front 提供了两类 ioc 容器:一类是全局 ioc 容器,可以实现 pinia 的能力。另一类是组件实例 ioc 容器,该容器与 Vue 组件实例绑定,在这个容器中的所有 Class 实例都可以在组件实例范围之内共享数据和逻辑。
    IvanLi127
        3
    IvanLi127  
       2024-05-27 21:25:17 +08:00
    我怎么感觉我喜欢的 Angular 的点都被你唾弃了
    07aPzknB16ui9Cp3
        4
    07aPzknB16ui9Cp3  
       2024-05-27 21:28:11 +08:00
    @zhennann 我的意思是对于 Vue team 来讲可能就不认可面向对象这样的设计模式,Class Component 也是迫不得已,不过当成一个 Angular slim 也不是不行,只不过受众群真的很小就是了
    sunorg
        5
    sunorg  
       2024-05-27 21:29:13 +08:00 via Android
    有 bug 这页面,手机 chronme 进这个页面,停留一会必定闪退
    zhennann
        6
    zhennann  
    OP
       2024-05-27 22:10:17 +08:00
    @IvanLi127 你可以对比一下 Angular 和 Cabloy-Front 的代码风格,看看是不是这么回事。这里有一些视频,可以作为参考: https://front.cabloy.com/zh/guide/resources/videos.html
    zhennann
        7
    zhennann  
    OP
       2024-05-27 22:11:32 +08:00
    @sunorg 这种情况我也遇到过。随机性比较强,比较魔幻。
    zhennann
        8
    zhennann  
    OP
       2024-05-27 22:18:41 +08:00
    @wuzzispacelake 你说的情况我了解。Vue team 不认可 class api 的理由我也看到了。他们的理由是使用 class 定义 vue 组件并不方便,代码冗余,性价比不高。这点我也认同。社区有好几款基于 class 来定义 vue 组件的方案,效果都不是很理想。这就说明了一个道理:Class 不应该用在视图层,而是要用到业务层。所以,Cabloy-Front 仍然在视图层使用 setup 语法糖来定义组件(包括 Props 和 Emits ),而在业务层引入 ioc 容器和 class 。这样,可以充分利用二者的优势,让整个代码更加简洁优雅。因为使用了 class 之后,再也不需要使用 ref/reactive 了,也不需要 ref.value 了。可以参考这篇文章:为什么需要 Vue3+IOC: https://front.cabloy.com/zh/guide/start/why.html
    19cm
        9
    19cm  
       2024-05-29 02:07:42 +08:00
    看到装饰器就想吐,维护过几个 vue2.6 装饰器写法的项目恶心得一批,完全没有框架应该有的便利性了, 不得不说 vue3 的 setup 真是天才设计
    19cm
        10
    19cm  
       2024-05-29 02:11:01 +08:00
    另外 vue3.4 开始组件都可以用 defineModel 了,不需要分开写 Props 和 Emits 了
    zhennann
        11
    zhennann  
    OP
       2024-05-29 06:35:46 +08:00
    @tianzi123 我也不喜欢 vue2.6 的装饰器写法。但是 Cabloy-Front 采取的策略完全不同。之前的装饰器写法不好用,是因为在用 class 定义 Vue 组件。实践证明,用函数式定义 Vue 组件最方便。所以,Cabloy-Front 仍然在视图层使用 setup 语法糖来定义组件(包括 Props 和 Emits ),而在业务层引入 ioc 容器和 class 。同时又采用了依赖注入与依赖查找相结合的策略,大量减少装饰器函数的使用,让代码更简洁优雅。这是 codesandbox 的在线演示,可以看一下: https://codesandbox.io/p/github/zhennann/cabloy-front-demo-codesandbox2/main?checkout=true&embed=1&file=%2Fsrc%2Fsuite%2Fa-demo%2Fmodules%2Fa-demo%2Fsrc%2Fpage%2Fcounter%2Fcontroller.ts
    zhennann
        12
    zhennann  
    OP
       2024-05-29 06:55:02 +08:00
    @tianzi123 如果代码都在 sfc 中,使用这些语法糖确实舒服。但是代码一多就乱;如果想拆分多个 hook 出去,这些语法糖的使用可能就不太方便了。Cabloy-Front 采用 ioc 容器,从一开始就把结构搭好了,不论代码再多也不会乱,而且可以平滑的扩张。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     992 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 19:19 PVG 03:19 LAX 11:19 JFK 14:19
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86