V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhennann
V2EX  ›  前端开发

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

  •  
  •   zhennann ·
    zhennann · 26 天前 · 968 次点击

    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
    wuzzispacelake
        1
    wuzzispacelake  
       26 天前
    老实说在我的理念里 Vue 的 tsx + 组合 API 就是 next gen Angular ,我知道 Angular 面向的人群和设计理念,但它使用的设计模式毕竟在 JS 生态中是可选项,不如只保留最轻便的服务容器( Vue provide )在特定场景下提供便利,剩下的让用户来决定(比如用专门的状态管理还是随手写一个 hook ),而不是还要捆绑诸如 rxjs 之类的东西;我以为楼主的项目是给 Angular 用的,定睛一看是 Vue 的服务容器,感觉 Vue team 的人看到会哭瞎,这不是 Vue Class Component 还魂么,好不容易才把 this 送走的这下全回来了
    zhennann
        2
    zhennann  
    OP
       26 天前
    @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  
       26 天前
    我怎么感觉我喜欢的 Angular 的点都被你唾弃了😭
    wuzzispacelake
        4
    wuzzispacelake  
       26 天前
    @zhennann 我的意思是对于 Vue team 来讲可能就不认可面向对象这样的设计模式,Class Component 也是迫不得已,不过当成一个 Angular slim 也不是不行,只不过受众群真的很小就是了
    sunorg
        5
    sunorg  
       26 天前 via Android
    有 bug 这页面,手机 chronme 进这个页面,停留一会必定闪退
    zhennann
        6
    zhennann  
    OP
       26 天前
    @IvanLi127 你可以对比一下 Angular 和 Cabloy-Front 的代码风格,看看是不是这么回事。这里有一些视频,可以作为参考: https://front.cabloy.com/zh/guide/resources/videos.html
    zhennann
        7
    zhennann  
    OP
       26 天前
    @sunorg 这种情况我也遇到过。随机性比较强,比较魔幻。
    zhennann
        8
    zhennann  
    OP
       26 天前
    @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
    tianzi123
        9
    tianzi123  
       25 天前
    看到装饰器就想吐,维护过几个 vue2.6 装饰器写法的项目恶心得一批,完全没有框架应该有的便利性了, 不得不说 vue3 的 setup 真是天才设计
    tianzi123
        10
    tianzi123  
       25 天前
    另外 vue3.4 开始组件都可以用 defineModel 了,不需要分开写 Props 和 Emits 了
    zhennann
        11
    zhennann  
    OP
       25 天前
    @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
       25 天前
    @tianzi123 如果代码都在 sfc 中,使用这些语法糖确实舒服。但是代码一多就乱;如果想拆分多个 hook 出去,这些语法糖的使用可能就不太方便了。Cabloy-Front 采用 ioc 容器,从一开始就把结构搭好了,不论代码再多也不会乱,而且可以平滑的扩张。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2324 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:25 · PVG 10:25 · LAX 19:25 · JFK 22:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.