鸿蒙面试题系列(二):一多开发与ArkTS实战进阶
在上一篇文章中,我们探讨了鸿蒙的基础组件、状态管理和资源管理。今天,我们来深入项目的实际开发场景,聊聊一多开发(一次开发,多端部署)、ArkTS/ArkUI 的核心概念以及面试中高频出现的布局与状态问题。
8. 你项目中的一多开发是如何实现的?
核心思路:自适应布局 + 断点系统 + 多态组件
在实战中,“一多开发”并不是为每种设备单独写一套代码,而是通过自适应布局来响应当前设备的屏幕尺寸和方向。
-
布局适配:优先使用
Flex、Column、Row、Stack等弹性布局,配合layoutWeight分配空间,避免写死宽高。 -
媒体查询(MediaQuery):针对大屏(如平板折叠屏)和小屏(手机)展示不同布局。例如,手机端单列展示,平板端双列展示。
-
栅格系统(GridRow/GridCol):常用于表单、列表页,通过断点(xs, sm, md, lg)控制每行的列数。
-
多态组件:使用
@MediaQuery装饰器或useBreakpointAPI 获取当前屏幕宽度,动态改变组件排列方式。
9. 什么是 ArkTS?什么是 ArkUI?
这是两个不同层面的概念:
-
ArkTS:
-
定义:是鸿蒙生态的应用开发语言。
-
本质:它是 TypeScript(TS)的超集。在 TS 的基础上,扩展了静态类型检查、声明式 UI 语法、状态管理等能力。
-
作用:负责处理业务逻辑、数据处理和算法。
-
-
ArkUI:
-
定义:是鸿蒙的声明式 UI 框架。
-
本质:一套用于构建用户界面的框架体系。
-
作用:负责将数据和状态渲染成界面。
-
一句话总结:ArkTS 是“大脑”(逻辑语言),ArkUI 是“画笔”(UI 框架)。
10. 请说下你使用过鸿蒙中哪些装饰器?并说明这些装饰器的作用?
在 ArkTS 中,装饰器(Decorator)是连接数据与 UI 的桥梁。常见的可分为以下几类:
-
状态管理类:
-
@State:组件内部状态。当其修饰的变量变化时,当前组件 UI 刷新。 -
@Prop:父子单向通信。父组件传值给子组件,子组件不可反向修改。 -
@Link:父子双向通信。父子组件共享同一份数据引用,一方改两边都变。 -
@ObjectLink/@Observed:嵌套对象的状态同步。
-
-
应用级状态类:
-
@StorageLink/@StorageProp:与 AppStorage 联动,实现全局状态管理。
-
-
组件复用类:
-
@Component:标记这是一个自定义组件。 -
@Builder:定义可复用的 UI 结构片段(类似局部模板)。 -
@Entry:标记页面的入口组件。
-
11. 什么场景(你项目中哪里)使用 Flex 布局?使用 Flex 布局会存在什么问题?
-
使用场景:
-
导航栏/标签栏:横向排列的 Tab 或底部菜单。
-
列表项:左侧图标 + 右侧文字的列表排版。
-
表单区域:一行内放置多个输入框或标签。
-
流式布局:元素需要自动换行的情况。
-
-
存在的问题:
-
权重分配陷阱:过度依赖
layoutWeight有时会导致父容器尺寸计算延迟,引起闪烁。 -
默认对齐方式:Flex 默认不换行且靠主轴起点对齐,如果不显式设置
flexWrap: FlexWrap.Wrap,在小屏设备上容易出现内容溢出。 -
高度塌陷:如果主轴是水平方向(
direction: FlexDirection.Row),且子元素没有明确高度,交叉轴(高度)可能会压缩。
-
12. 什么场景(你项目中哪里)使用 Stack 布局?
Stack(层叠布局)用于将组件按照层级堆叠在一起。
-
典型场景:
-
绝对定位覆盖:比如图片上叠加文字(商品封面图 + 标题)。
-
悬浮按钮(FAB):在页面右下角固定一个按钮,覆盖在列表之上。
-
遮罩层(Overlay):弹窗背景半透明遮罩,上层显示弹窗内容。
-
引导页指示点:底部的小圆点指示当前在第几页。
-
13. 定位有哪些?区别是啥?什么场景下使用定位?
在 ArkUI 声明式开发中,"定位"不完全等同于 CSS 的 position枚举,更准确的说法是组件相对于父容器/兄弟组件的摆放方式。常用的有四种思路:
① .offset({x, y})—— 相对偏移
Text('原位置')
.width(100).height(40)
.backgroundColor('#90CAF9')
Text('offset 偏移')
.width(100).height(40)
.offset({ x: 120, y: 60 }) // 在原位置基础上向右120、向下60
-
特点:在原文档流位置基础上做偏移,原位置仍保留占位,不会影响兄弟组件的布局测算。
-
场景:微调按钮上的红点、Tooltip 气泡、图标旁的小标签——"我想让它挪一下,但别打乱别人"。
② .position({x, y})—— 绝对定位
Stack() {
Image($r('app.media.bg'))
Text('99+')
.position({ x: 32, y: 4 }) // 以父容器(Stack)左上角为原点
.backgroundColor(Color.Red)
}
-
特点:以父组件内容区左上角为坐标原点放置子组件,脱离文档流,父容器如果是
Row/Column/Flex,设了.position()的子组件不参与父容器的排版测算(不占位)。 -
场景:铃铛右上角的红点徽标、图片上叠加文字、悬浮按钮、遮罩层内的弹窗主体。
💡 搭配
.markAnchor({x, y})可以改变"自身哪个点"去对齐那个坐标——比如想让红点的右上角贴在铃铛右肩,而不是默认的左上角。
③ RelativeContainer+ alignRules—— 约束定位
RelativeContainer() {
Text('A').id('a').alignRules({
top: { anchor: '__container__', align: VerticalAlign.Top },
left: { anchor: '__container__', align: HorizontalAlign.Start }
})
Text('B').alignRules({
top: { anchor: 'a', align: VerticalAlign.Bottom },
left: { anchor: 'a', align: HorizontalAlign.Start }
})
}
-
特点:通过
id+alignRules用"锚点"描述组件之间的相对关系,不需要写死 x/y,适配性远好于.position()。 -
场景:复杂表单、仪表盘、多个元素彼此有"谁在谁上面/左边"关系的界面。是鸿蒙官方推荐的精确关系布局方案,比绝对定位更适合多尺寸设备。
④ Stack+ Alignment—— 层叠定位
Stack({ alignContent: Alignment.TopEnd }) {
Image($r('app.media.banner'))
Badge({ count: 3 }) // 自动贴右上角
}
-
特点:子组件按"层"堆叠,通过
Alignment或alignSelf决定每层在父容器里的位置。 -
场景:封面图+标题、卡片+角标、全屏遮罩+居中弹窗。
一张表理清区别
|
方式 |
是否脱流 |
参考系 |
多端适配友好度 |
|---|---|---|---|
|
|
否,原位置保留 |
自身原位置 |
⭐⭐⭐ 好 |
|
|
是,不占位 |
父容器内容区左上角 |
⭐ 差(写死坐标) |
|
|
否,按约束算 |
锚点组件 / 父容器 |
⭐⭐⭐⭐ 最佳 |
|
|
否,层叠 |
父容器九宫格方位 |
⭐⭐⭐ 中等 |
📌 面试踩坑点:很多人把 ArkUI 的
.position()直接等同于 CSS 的position: absolute,但其实 ArkUI 没有static/relative/absoulte/fixed这套枚举(类 CSS 的position字符串写法只在方舟 UI 框架/元服务类场景出现,声明式 ArkTS 主流是 API 这套)。被问到"鸿蒙的定位有几种"时,按「offset → position → RelativeContainer → Stack」四条答,比套 CSS 那套更贴鸿蒙面试官的预期。
14. layoutWeight 属性作用是什么?什么时候使用?
-
作用:
layoutWeight用于在线性布局(Column/Row/Flex)中分配剩余空间。它决定了组件在主轴上占据的相对比例。-
在
Column中,控制高度占比。 -
在
Row中,控制宽度占比。
-
-
使用时机:
-
当容器有多余空间需要分配给子组件时。
-
经典案例:底部 Tab 栏平分宽度。给每个 Tab 按钮设置
layoutWeight(1),它们就会自动等宽撑满底部。
-
15. 如何让一个组件在页面中既水平又垂直居中显示?
这是面试必考题,有三种常用方案:
方案一:使用 Flex布局(推荐,最灵活)
设置容器的主轴和交叉轴对齐方式均为居中。
Column() {
Text('居中内容')
}.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
方案二:使用 Stack布局(最直观)
利用层叠布局的特性,将子组件堆叠在父容器的中心原点。
Stack() {
Text('居中内容')
}.width('100%').height('100%').alignContent(Alignment.Center)
方案三:使用 Blank组件(巧妙解法)
利用空白填充物把组件“挤”到中间。
Column() {
Blank() // 自动填满上方空间
Text('居中内容')
Blank() // 自动填满下方空间
}.width('100%').height('100%')
16. let 和 const 和 @State 的区别?
这三个概念分别处于语言基础层和框架状态层:
-
let(可变变量):-
ES6 语法。
-
值可以改变,但改变时不会触发 UI 刷新。
-
仅用于存储纯逻辑计算的临时数据。
-
-
const(常量):-
ES6 语法。
-
一旦赋值不可更改,试图修改会报错。
-
同样不具备 UI 响应能力。
-
-
@State(状态装饰器):-
ArkTS 特有装饰器。
-
本质上它也是一个变量,但当它修饰的变量值发生改变时,框架会自动检测变化并触发依赖它的 UI 重新渲染。
-
总结:let/const是纯粹的编程语言特性,负责数据的存储;@State是框架提供的机制,负责数据的响应式绑定。
更多推荐

所有评论(0)