HarmonyOS开发实战:笔友-@Extend/@Styles 样式复用与主题系统
前言在 ArkUI 声明式开发范式中样式复用是提升代码可维护性和 UI 一致性的关键手段。Styles和Extend两个装饰器分别从“通用样式集合“和“组件特定扩展“两个维度为开发者提供了样式复用的能力。本文将以开源鸿蒙笔友通信应用 xiexin 的Constants.ets中的AppColors设计令牌和各页面中的样式代码为蓝本详细剖析Styles/Extend的语法、使用场景以及它们如何与设计令牌Design Tokens配合构建可维护的样式系统。提示本文假设你已经了解 ArkUI 声明式开发的基本概念。如果还不熟悉建议先阅读前十一篇文章。一、样式复用的两个维度ArkUI 提供了两种样式复用机制分别解决不同的问题装饰器作用范围适用场景Styles通用样式集合跨组件共享的样式规则Extend特定组件扩展针对特定组件类型的样式扩展1.1 它们的区别// Styles通用样式不限定组件类型 Styles function CommonShadow() { .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) } // Extend特定组件样式限定 Text 组件 Extend(Text) function TitleText() { .fontSize(16) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) }二、xiexin 的样式现状2.1 当前样式组织方式xiexin 当前没有使用Styles或Extend而是通过直接属性调用和设计令牌来管理样式// Constants.ets — AppColors 设计令牌 export class AppColors { static readonly PRIMARY_BG: string #FAF6F0; static readonly SECONDARY_BG: string #F0EBE3; static readonly PAPER_BG: string #FFFDF7; static readonly PRIMARY: string #8B6914; static readonly SECONDARY: string #C4956A; static readonly TEXT_PRIMARY: string #2D2A26; static readonly TEXT_SECONDARY: string #7A746B; static readonly ACCENT: string #B8860B; static readonly WAITING: string #6B8E6B; static readonly DISABLED: string #C8C2B8; static readonly DIVIDER: string #E8E2D8; static readonly WHITE: string #FFFFFF; static readonly CARD_BG: string #FFFFFF; static readonly AMBER_LIGHT: string #FFF8E7; static readonly SUCCESS: string #4CAF50; static readonly AMBER_OPACITY: string #1A8B6914; }2.2 直接属性调用的弊端// 反例重复的样式代码 // PenPalCard Row() .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) // LetterCard Row() .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 })这两段代码几乎完全相同却散落在两个不同的Builder函数中。这就是Styles和Extend要解决的问题。三、Styles 装饰器通用样式集合3.1 Styles 的基本用法Styles装饰器用于定义一组通用的样式规则可以被多个组件共享。全局 StylesStyles function CardShadow() { .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) } Styles function TextPrimary() { .fontSize(16) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) }组件内 StylesComponent struct MyComponent { Styles CardStyle() { .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) } build() { Row() { /* ... */ } .CardStyle() // 调用组件内 Styles } }3.2 Styles 的核心特性特性说明不限定组件任何组件都可以调用不可使用参数Styles函数不能带参数不可使用状态不能访问this的State变量全局可导出全局Styles可以被export导出3.3 Styles 在 xiexin 中的应用示例如果 xiexin 使用Styles可以对重复的卡片样式进行提取// 全局 Styles 函数 Styles function CardBase() { .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) } Styles function CardShadow() { .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) } Styles function SmallChip() { .fontSize(11) .borderRadius(8) .padding({ left: 6, right: 6, top: 2, bottom: 2 }) }然后在组件中使用Builder PenPalCard(pal: PenPal) { Row() { // 笔友卡片内容 } .CardBase() .CardShadow() .onClick(() { router.pushUrl({ url: pages/PenPalDetailPage, params: { penPalId: pal.id } }) }) } Builder LetterCard(letter: Letter) { Row() { // 信件卡片内容 } .CardBase() .CardShadow() .onClick(() { router.pushUrl({ url: pages/ReadLetterPage, params: { letterId: letter.id } }) }) }提示Styles函数不能带参数适用于“统一所有卡片外观“的场景。如果不同卡片需要不同的边距或颜色应该使用Extend。四、Extend 装饰器特定组件扩展4.1 Extend 的基本用法Extend装饰器用于针对特定组件类型扩展样式。// 针对 Text 组件的扩展 Extend(Text) function TitleText() { .fontSize(16) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) } // 针对 Text 组件的扩展带参数 Extend(Text) function StatusText(color: string) { .fontSize(11) .fontColor(color) .fontWeight(FontWeight.Medium) .borderRadius(10) .padding({ left: 8, right: 8, top: 3, bottom: 3 }) }4.2 Extend 的核心特性特性说明组件限定只能针对特定组件类型定义支持参数可以带参数动态生成样式全局函数只能定义为全局函数链式调用多个Extend可以链式调用4.3 Extend 在 xiexin 中的应用示例xiexin 中重复次数最多的样式是Text组件的各种排版样式// 针对 Text 组件的扩展 Extend(Text) function TitleText() { .fontSize(16) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) } Extend(Text) function SubtitleText() { .fontSize(12) .fontColor(AppColors.TEXT_SECONDARY) } Extend(Text) function PrimaryButton() { .fontSize(14) .fontColor(AppColors.WHITE) .backgroundColor(AppColors.PRIMARY) .borderRadius(24) .height(40) .width(140) } // 针对 Row 组件的扩展 Extend(Row) function CardContainer() { .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) }在组件中使用// 使用 Extend 简化样式代码 Builder PenPalCard(pal: PenPal) { Row() { AvatarComponent({ name: pal.name, avatarSize: 48, fontSize: 20 }) .margin({ right: 14 }) Column({ space: 4 }) { Text(pal.name).TitleText() // 调用 Extend(Text) 扩展 Text(认识 ${pal.daysSinceMet} 天 · 通信 ${pal.totalLetters} 封) .SubtitleText() } .layoutWeight(1) } .CardContainer() // 调用 Extend(Row) 扩展 .onClick(() { router.pushUrl({ url: pages/PenPalDetailPage, params: { penPalId: pal.id } }) }) }五、Styles vs Extend 对比5.1 选择决策树需要复用的样式是 ├── 跨多种组件类型共享 → Styles │ └── 示例卡片阴影、圆角、背景色 └── 针对特定组件类型 → Extend └── 示例Text 字号、Button 形状5.2 对比表格维度StylesExtend组件限定否是参数支持否是作用范围全局/组件内全局调用方式链式调用链式调用可导出是是典型场景卡片阴影、基础布局Text 字号、Button 样式5.3 组合使用Styles和Extend可以组合使用实现更精细的样式管理// 基础布局样式跨组件 Styles function FlexCenter() { .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Center) } Styles function FullWidth() { .width(100%) } // 特定组件样式 Extend(Text) function TitleText() { .fontSize(16) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) } // 组合使用 Row() .FullWidth() .FlexCenter() .height(48)六、stateStyles 多态样式6.1 stateStyles 的基本用法stateStyles是 ArkUI 提供的多态样式机制允许组件在不同状态下应用不同的样式Entry Component struct Index { Styles normalStyle() { .backgroundColor(AppColors.CARD_BG) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) } Styles pressedStyle() { .backgroundColor(AppColors.SECONDARY_BG) .shadow({ radius: 3, color: #0A000000, offsetX: 0, offsetY: 1 }) } build() { Row() .stateStyles({ normal: this.normalStyle, pressed: this.pressedStyle, // focused: this.focusedStyle // 可选 }) } }6.2 stateStyles 在 xiexin 中的应用如果 xiexin 使用stateStyles卡片按压效果可以这样实现Styles cardNormal() { .backgroundColor(AppColors.CARD_BG) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) } Styles cardPressed() { .backgroundColor(AppColors.SECONDARY_BG) .shadow({ radius: 3, color: #0A000000, offsetX: 0, offsetY: 1 }) } Builder PenPalCard(pal: PenPal) { Row() { // 内容 } .CardContainer() .stateStyles({ normal: this.cardNormal, pressed: this.cardPressed, }) .onClick(() { router.pushUrl({ url: pages/PenPalDetailPage, params: { penPalId: pal.id } }) }) }提示stateStyles支持normal、pressed、focused三种状态。pressed状态在用户按下时触发focused状态在组件获得焦点时触发。七、AnimatableExtend 可动画属性扩展7.1 AnimatableExtend 的基本用法AnimatableExtend装饰器用于定义可动画的属性可以在动画过程中平滑过渡AnimatableExtend(Text) function AnimatableOpacity() { .opacity() } AnimatableExtend(Row) function AnimatableScale() { .scale() }7.2 AnimatableExtend 与动画的配合AnimatableExtend(Text) function AnimatableFontSize() { .fontSize() } Entry Component struct AnimatedText { State fontSize: number 16; build() { Column() { Text(Hello) .AnimatableFontSize(this.fontSize) Button(放大) .onClick(() { animateTo({ duration: 300 }, () { this.fontSize 32; }) }) } } }八、设计令牌与样式系统的整合8.1 设计令牌 Styles/Extend 三层架构将设计令牌、Styles、Extend三层整合可以构建完整的样式系统graph TD subgraph 第1层 设计令牌 C[AppColors 颜色常量] S[字号常量] M[间距常量] end subgraph 第2层 通用样式 ST[全局 Styles 函数] EX[全局 Extend 函数] end subgraph 第3层 组件样式 CP[组件内 Styles] DS[stateStyles 多态样式] end C -- ST C -- EX ST -- CP EX -- DS8.2 样式文件组织建议对于 xiexin 项目建议将样式代码按以下方式组织entry/src/main/ets/ ├── common/ │ ├── AppColors.ets # 设计令牌颜色 │ ├── Typography.ets # 设计令牌字号、行高 │ └── Spacing.ets # 设计令牌间距 ├── styles/ │ ├── GlobalStyles.ets # 全局 Styles 函数 │ ├── TextStyles.ets # Extend(Text) 扩展 │ └── LayoutStyles.ets # Extend(Row/Column) 扩展 └── pages/ ├── Index.ets # 组件内 Styles └── ... # 其他页面8.3 设计令牌 Extend 的完整示例// 第1层设计令牌 export class FontSizes { static readonly TITLE: number 16; static readonly BODY: number 14; static readonly CAPTION: number 12; static readonly SMALL: number 11; } // 第2层Extend 扩展 Extend(Text) function TitleText() { .fontSize(FontSizes.TITLE) .fontColor(AppColors.TEXT_PRIMARY) .fontWeight(FontWeight.Medium) } Extend(Text) function BodyText() { .fontSize(FontSizes.BODY) .fontColor(AppColors.TEXT_PRIMARY) } Extend(Text) function CaptionText() { .fontSize(FontSizes.CAPTION) .fontColor(AppColors.TEXT_SECONDARY) } // 第3层组件中使用 Builder PenPalCard(pal: PenPal) { Row() { Column({ space: 4 }) { Text(pal.name).TitleText() // 笔友名标题字号 Text(pal.signature).BodyText() // 签名正文字号 Text(认识 ${pal.daysSinceMet} 天).CaptionText() // 天数注解字号 } } }九、主题切换样式9.1 深色模式适配通过Styles和Extend配合 AppColors 设计令牌可以方便地实现主题切换// 浅色模式 const lightColors { PRIMARY_BG: #FAF6F0, TEXT_PRIMARY: #2D2A26, // ... }; // 深色模式 const darkColors { PRIMARY_BG: #1C1B1F, TEXT_PRIMARY: #E6E1E5, // ... }; // 根据主题切换设计令牌 Styles function CardBase() { .backgroundColor(AppColors.CARD_BG) .borderRadius(16) }9.2 运行时主题切换Entry Component struct MyApp { StorageProp(darkMode) darkMode: boolean false; Styles cardBase() { .backgroundColor(this.darkMode ? #2D2D2D : #FFFFFF) .borderRadius(16) } build() { Row() { // 卡片内容 } .cardBase() } }提示Styles虽然不能带参数但可以通过StorageProp访问全局状态实现主题切换样式。十、样式系统的性能优化10.1 Styles 与 Extend 的渲染开销Styles和Extend在编译时会被展开为普通的属性调用不会带来额外的运行时开销// 编译前 Row() .CardBase() .CardShadow() // 编译后等价 Row() .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 })10.2 避免过度抽象// 过度抽象仅仅封装了一个属性 Styles function Width100() { .width(100%) } // 合理的使用封装了多个属性的组合 Styles function CardContainer() { .width(100%) .padding(16) .backgroundColor(AppColors.CARD_BG) .borderRadius(16) .shadow({ radius: 6, color: #0A000000, offsetX: 0, offsetY: 2 }) }总结本文详细剖析了 HarmonyOS ArkUI 的Styles/Extend样式复用机制重点讲解了它们与设计令牌AppColors的配合使用以及如何通过stateStyles实现多态样式。理解样式复用机制的关键是把握“三层架构“设计令牌AppColors→ 通用样式Styles→ 组件特定扩展Extend。这三层各司其职共同构成了可维护的样式系统。下一篇文章我们将深入Observed和ObjectLink装饰器剖析 xiexin 中如何通过嵌套对象响应式追踪实现高效的状态更新。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS Styles 装饰器https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-styleHarmonyOS Extend 装饰器https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-extendHarmonyOS stateStyles 多态样式https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-statestylesHarmonyOS AnimatableExtend 装饰器https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-animatable-extendHarmonyOS 资源分类与访问https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/resource-categories-and-accessHarmonyOS 深色模式适配https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-dark-light-adaptationHarmonyOS 组件扩展概述https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-extend-components-overviewHarmonyOS 自定义组件复用https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-reusable

相关新闻

AM387x GPIO与GPMC实战:寄存器配置、时序计算与调试避坑指南

AM387x GPIO与GPMC实战:寄存器配置、时序计算与调试避坑指南

1. 项目概述与核心价值如果你正在基于TI的AM387x系列处理器(比如AM3874或AM3871)进行嵌入式系统开发,那么GPIO和GPMC这两个外设绝对是你绕不开的核心模块。GPIO,也就是通用输入输出,它就像是处理器的“手脚”和“感官”…

2026/7/25 13:53:33阅读更多 →
今日提示词分享多宫格杂志写真

今日提示词分享多宫格杂志写真

提示词: 多宫格杂志写真,眼镜猫娘cosplay,超高还原原创眼镜猫娘设定,白色猫耳,细长猫尾,银白色长发,柔顺发丝,空气刘海,精致金属细框眼镜,清澈明亮的大眼睛,甜美可爱与知性气质结合,少女感,官方角色设定风格,顶级漫展场照,极度写实,杂志封面风格,Fashion Edit…

2026/7/25 13:53:33阅读更多 →
基于SpringBoot体育俱乐部管理系统设计与实现毕业设计任务书

基于SpringBoot体育俱乐部管理系统设计与实现毕业设计任务书

一、课题名称 基于SpringBoot体育俱乐部管理系统设计与实现 二、课题研究背景与意义 随着全民健身体育事业快速发展,各类民间体育俱乐部、运动社团的规模持续扩大,会员数量、训练课程、场地资源、教练团队、活动赛事不断增多。传统体育俱乐部大多采用人工…

2026/7/25 13:51:33阅读更多 →
自然语言转SQL与智能BI可视化实践

自然语言转SQL与智能BI可视化实践

1. 项目背景与核心价值最近在做一个特别有意思的项目——通过自然语言直接生成SQL查询并可视化展示结果。这个需求来源于我们团队内部的数据分析场景:每次产品经理想看某个维度的数据,都要找工程师写SQL,效率太低。于是我们决定开发一个智能B…

2026/7/26 2:15:50阅读更多 →
智能法务助手:NLP与规则引擎驱动的合同审查系统

智能法务助手:NLP与规则引擎驱动的合同审查系统

1. 项目背景与核心价值去年处理某跨境合作协议时,团队因疏忽赔偿条款中的连带责任描述,导致后期产生数百万额外支出。这件事让我意识到:传统人工合同审查存在响应延迟、标准不一、疲劳漏检三大痛点。我们开发的智能法务助手,通过N…

2026/7/26 2:15:50阅读更多 →
C++引用与指针深度解析:使用场景、内存模型与工程实践指南

C++引用与指针深度解析:使用场景、内存模型与工程实践指南

1. 项目概述:为什么C程序员必须厘清引用与指针?在C的日常开发中,引用和指针是绕不开的两个核心概念。很多初学者,甚至一些有一定经验的开发者,常常对它们的使用场景感到困惑:什么时候该用引用?什…

2026/7/26 2:15:50阅读更多 →
TWL6030 PMIC充电管理:从寄存器配置到软件状态机的嵌入式实战

TWL6030 PMIC充电管理:从寄存器配置到软件状态机的嵌入式实战

1. 项目概述与核心价值在嵌入式系统,尤其是便携式设备的设计中,电源管理单元(PMIC)的电池充电管理功能是决定产品续航、安全性和用户体验的基石。TWL6030作为一款高度集成的电源管理芯片,其内置的充电控制器功能强大&a…

2026/7/26 2:15:50阅读更多 →
大模型无监督强化学习:DSCO框架与知识引导探索

大模型无监督强化学习:DSCO框架与知识引导探索

1. 前沿背景与研究动机去年在NeurIPS会场咖啡区,我和几位同行争论到深夜:当大模型遇到强化学习,无监督范式到底能突破哪些边界?这个讨论直接促成了我们团队针对ICLR 2026的这项研究。当前大模型在监督学习领域已经展现出惊人能力&…

2026/7/26 2:15:50阅读更多 →
2026全球AI产业格局与关键技术趋势分析

2026全球AI产业格局与关键技术趋势分析

1. 全球AI产业格局现状扫描2026年初的AI领域呈现出前所未有的激烈竞争态势。从波士顿到班加罗尔,从东京到特拉维夫,全球科技力量正在人工智能赛道上展开全方位角逐。根据最新行业白皮书数据显示,全球AI产业规模已突破1.8万亿美元,…

2026/7/26 2:13:50阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/26 0:01:28阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/26 0:01:28阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/26 0:01:28阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/26 0:01:28阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/26 0:01:28阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/26 0:01:28阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/25 23:03:25阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/25 19:03:04阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/25 19:03:04阅读更多 →