还在纠结 eTS、JS、ArkTS?不如三小时吃透“ArkUI × ArkTS”双栈,香不香?

举报
bug菌 发表于 2025/11/01 22:24:06 2025/11/01
【摘要】 🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8 前言先抛一个灵魂拷问:你是要“能跑的 Demo”,还是“敢上线、能扩展...

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

前言

先抛一个灵魂拷问:你是要“能跑的 Demo”,还是“敢上线、能扩展、可观测”的鸿蒙应用?如果你也在 ArkUI 与 ArkTS 双栈eTS 与 JS 应用的岔路口踟蹰,那这篇就是为你准备的“人话+实例+避坑指南”。我不跟你虚的:概念对齐 -> 对比清单 -> 代码示例 -> 实战范式,一口气把四个主题讲顺——“看得懂”“抄得走”“改得快”。走起!🚀

1) 双栈开发模式到底“双”在哪?

所谓“ArkUI × ArkTS 双栈”,我更喜欢拆成两层来理解:

  • UI 栈(ArkUI):声明式组件体系(TextRowColumnList…)+ 生命周期/路由/过渡/动画。
  • 语言栈(ArkTS / eTS / JS):同样写 ArkUI,但用的语言层能力不同——类型系统、装饰器、编译优化 差异会直接影响可维护性与性能潜力

再进一步,在一些业务里你还会引入:

  • 能力栈(C/C++/Rust 通过 NAPI/NDK):做算法/多媒体/加解密等“重活”,上层 ArkTS/JS 调用即可。

一句话:ArkUI 统一 UI 编程范式ArkTS(eTS)与 JS 决定你写代码的“刀锋锐利度”;必要时用原生扩展把性能拉满。


2) eTS 与 JS 应用:同门兄弟,有何取舍?

注:很多资料把 eTS(extended TS,历史叫法)与 ArkTS 混着提。当前推荐主力是 ArkTS(面向 ArkUI 的 TypeScript 超集),JS 一样可用,但工程体验与类型安全度不同。

维度 eTS / ArkTS 应用 JS 应用
语言特性 TS 超集 + 装饰器(@State/@Provide/...)+ 更强类型推导 纯 JS,灵活但类型安全不足
组件声明 @Component/@Entry + build(),强约束 函数式/对象式组件,约束较弱
状态管理 @State/@Prop/@Link/@Provide/@ConsumeAppStorage@Observed 以普通对象/闭包为主,需人为约束
编译与优化 编译期做更多语义检查与优化,体积/性能更可控 动态特性强,优化空间受限
团队协作 类型即契约,回归 IDE 驱动开发 自由度高,易“各写各的”
适用场景 中大型、多人协作、长期维护 轻量 Demo、原型、对 TS 抗拒的场景

实话实说:如果不是特殊历史包袱,优先选 ArkTS(eTS 语法谱系)。写起来更自洽,调试、联调、Review 都更省心。


3) ArkTS 语法特性与组件绑定:装饰器、数据流与编译期校验

ArkTS 面向 ArkUI 的“声明式 + 响应式”语法糖,关键在 组件装饰器状态装饰器。下面这张“口袋卡”够你对拍源码了👇

3.1 组件与生命周期

@Entry
@Component
struct HomePage {
  aboutToAppear() { /* 首次渲染前 */ }
  aboutToDisappear() { /* 销毁前 */ }

  build() {
    Column() {
      Text('Hello ArkTS')
    }.padding(16)
  }
}
  • @Entry:应用或路由的入口组件
  • @Component:声明式组件,必须实现 build()
  • 生命周期:aboutToAppear/… 与路由过渡相呼应

3.2 数据与绑定(“单向为主、双向慎用”)

目标 用啥 绑定说明
组件内部可变状态 @State 改即刷新,范围局部
父传子只读 @Prop 子不可直接改
父子双向 @Link 少用在深层树,易乱
跨层共享 @Provide/@Consume “祖孙通信”,像依赖注入
全局共享/持久 AppStorage/@StorageLink 可作为全局会话/主题
可观察对象 @Observed/@ObjectLink 对象属性级追踪

示例:父传子 + 双向回写

@Entry
@Component
struct App {
  @State name: string = 'ArkUI'

  build() {
    Column() {
      ProfileEditor({ title: 'Nickname' , text: this.name })
        .onSaved((v: string) => this.name = v)
      Text(`Hi, ${this.name}!`).fontSize(20)
    }.padding(20)
  }
}

@Component
struct ProfileEditor {
  @Prop title: string
  @Link text: string   // 与父同步(慎用深层)
  private onSavedCb?: (v: string) => void

  onSaved(cb: (v: string) => void) { this.onSavedCb = cb; return this }

  build() {
    Column({ space: 8 }) {
      Text(this.title).fontWeight(FontWeight.Bold)
      TextInput({ text: this.text }).onChange(v => this.text = v)
      Button('Save').onClick(() => this.onSavedCb?.(this.text))
    }
  }
}

经验:能用单向就单向@Prop + 事件回调);@Link 只在同域小组件里使用,避免“状态四处窜”。

3.3 样式与链式修饰

ArkUI 支持“语义组件 + 链式样式”:

Text('ArkUI × ArkTS')
  .fontSize(22)
  .fontWeight(FontWeight.Medium)
  .fontColor('#222')
  .padding({ top: 12, bottom: 8 })

优点:读起来像句子,且对 IDE 友好(补全 + 校验)。


4) 响应式 UI 编程模式:状态 → 视图 → 动画的“顺拐”节奏

4.1 隐式为主:让“样式变化”自动过渡

@State progress: number = 0

Rectangle()
  .width(this.progress + '%')
  .height(6)
  .borderRadius(3)
  .animation({ duration: 300, curve: Curve.EaseInOut })
  • 只改状态,样式自动“丝滑”过渡
  • 列表/表单/微交互的默认首选

4.2 显式兜底:需要编排就上 animateTo

@State open: boolean = false
@State opacity: number = 0
@State offsetY: number = -16

Button(this.open ? 'Hide' : 'Show')
  .onClick(() => {
    animateTo({ duration: 260, curve: Curve.Spring }, () => {
      this.open = !this.open
      this.opacity = this.open ? 1 : 0
      this.offsetY = this.open ? 0 : -16
    })
  })

Column()
  .opacity(this.opacity)
  .translate({ y: this.offsetY })
  • 时序可控、联动强,但请集中管理,别层层嵌套

4.3 过渡(Transition):让组件“进场/退场”有礼貌

ListItem() {
  /* ... */
}
.transition(
  TransitionEffect.OPACITY
    .combine(TransitionEffect.SCALE)
    .animation({ duration: 220, curve: Curve.Spring })
)

口诀数据单向流 → 视图声明式 → 动画最少必要。先稳,再漂亮。


5) 可运行的小示例:从 JS 版到 ArkTS 版的“同题双解”

目标:搜索 + 收藏的微型列表。感受 JSArkTS 在“类型/装饰器/可维护性”上的差异。

5.1 JS 版本(轻量但松散)

//@ts-nocheck  // 这里故意不校验以示对比
@Entry
@Component
struct SearchPage {
  build() {
    this.keyword = ''
    this.favs = []

    Column({ space: 10 }) {
      TextInput({ placeholder: 'Search...' })
        .onChange(v => this.keyword = v)

      List() {
        ForEach(mockData.filter(i => i.includes(this.keyword)), (item) => {
          ListItem() {
            Row({ space: 8 }) {
              Text(item)
              Blank()
              Button('Fav').onClick(() => {
                if (!this.favs.includes(item)) this.favs.push(item)
              })
            }
          }
        })
      }

      Text('Favorites: ' + JSON.stringify(this.favs))
    }.padding(16)
  }
}
  • 优点:写得快
  • 缺点:无类型护栏、状态来源松散、复杂后易乱

5.2 ArkTS 版本(强约束、好维护)

type Item = { id: number; name: string }

const DATA: Item[] = [
  { id: 1, name: 'ArkUI' },
  { id: 2, name: 'ArkTS' },
  { id: 3, name: 'eTS' },
  { id: 4, name: 'JS App' },
]

@Entry
@Component
struct SearchPage {
  @State keyword: string = ''
  @State favs: Set<number> = new Set()

  build() {
    Column({ space: 12 }) {
      Text('Search & Favorite').fontSize(20).fontWeight(FontWeight.Bold)

      TextInput({ placeholder: 'Type to filter...' })
        .onChange(v => this.keyword = v)

      List() {
        ForEach(this.filtered(DATA), (item: Item) => {
          ListItem() {
            Row({ space: 8 }) {
              Text(item.name)
              Blank()
              Button(this.favs.has(item.id) ? '★' : '☆')
                .onClick(() => this.toggle(item.id))
            }
            .padding(8)
          }
          .transition(TransitionEffect.OPACITY.animation({ duration: 180 }))
        })
      }

      Text(`Favorites: ${[...this.favs].join(', ') || 'None'}`)
        .fontColor('#666')
    }
    .padding(16)
  }

  private filtered(src: Item[]): Item[] {
    const k = this.keyword.trim().toLowerCase()
    if (!k) return src
    return src.filter(x => x.name.toLowerCase().includes(k))
  }

  private toggle(id: number) {
    // 集中式修改,易测
    if (this.favs.has(id)) this.favs.delete(id)
    else this.favs.add(id)
    // 触发刷新:ArkTS 对 Set 需显式更新引用(如必要)
    this.favs = new Set(this.favs)
  }
}

感受差异

  • ArkTS 的 类型签名 + 私有方法 + 状态引用更新 让代码更可控;
  • 复杂度上来之后,架构与演进成本立刻分出高下。

6) 工程化与避坑清单:把坑踩在我这儿

6.1 架构建议(Page/Stage 皆适用)

/app                # 入口、路由、全局Provider
/features
  /search           # 业务特性:组件+store+service
  /favorites
/shared             # 通用:主题、工具、类型、UI-kits
  • UI 与状态解耦:纯展示组件不直接发请求
  • Provider 下沉:主题/用户/权限用 @Provide/@Consume
  • 请求聚合services/ 统一管理,便于切换能力侧

6.2 性能&体验

  • 列表 不可变更新(新数组/新引用)提高 diff 准确度
  • 隐式动画优先,显式集中控制、别层层嵌套
  • 大计算/IO 做防抖/节流;动画期间避免同步重排

6.3 状态规则“二三事”

  • @Prop + 回调 就别上 @Link
  • 跨很多层才用 @Provide/@Consume;全局才用 AppStorage
  • 复杂对象用 @Observed/@ObjectLink,不要野蛮 any

6.4 常见坑

  1. Set/Map 变更不刷新 → 重新赋值新实例触发更新(this.set = new Set(this.set)
  2. 跨页数据丢AppStorage 或参数路由,别靠全局变量
  3. 动效掉帧 → 曲线别太“硬”、组件树别太“深”、尽量隐式动画
  4. 类型逐步“腐化” → 打开严格 TS 规则,公共类型抽到 /shared/types.ts

7) 结语 & 你的下一步

到这儿,“ArkUI × ArkTS”这对黄金搭档是不是顺眼多了?UI 用 ArkUI 的声明式范式保证一致性;语言选 ArkTS 获得类型与编译期红线;响应式状态与动画遵守“最少必要原则”,既稳又优雅。剩下的,就是把你的业务塞进去,然后疯狂迭代,开心打磨。😎

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

✨️ Who am I?

我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。