前言
在“海风日记“的写日记功能中,心情选择器是核心交互组件之一。用户可以从 5 种心情和 5 种天气中选择,选择结果会实时反映在 UI 上。
MoodSelector组件通过@Link装饰器实现与父组件的双向绑定,子组件修改选择项后,父组件的状态自动更新。本文将从源码出发,深入讲解 @Link 的完整用法。
一、@Link 双向绑定
1.1 子组件定义
@Component export struct MoodSelector { @Link selectedMood: number // 双向绑定心情 @Link selectedWeather: number // 双向绑定天气 build() { Column() { // 心情选项 ForEach(MOOD_OPTIONS, (item, index) => { Text(item.emoji) .onClick(() => { this.selectedMood = index }) }) // 天气选项 ForEach(WEATHER_OPTIONS, (item, index) => { Text(item.emoji) .onClick(() => { this.selectedWeather = index }) }) } } }1.2 父组件使用
@Entry @Component struct WriteDiaryPage { @State selectedMood: number = 3 // 默认开心 @State selectedWeather: number = 0 // 默认晴天 build() { MoodSelector({ selectedMood: this.selectedMood, // 传入 @State selectedWeather: this.selectedWeather // 传入 @State }) } }二、心情选项配置
2.1 数据定义
const MOOD_OPTIONS: MoodOption[] = [ { emoji: '😢', label: '难过' }, { emoji: '😕', label: '低落' }, { emoji: '😐', label: '平静' }, { emoji: '🙂', label: '还不错' }, { emoji: '😊', label: '开心' }, ] const WEATHER_OPTIONS: WeatherOption[] = [ { emoji: '☀️', label: '晴' }, { emoji: '⛅', label: '多云' }, { emoji: '🌧️', label: '雨' }, { emoji: '🌬️', label: '大风' }, { emoji: '❄️', label: '雪' }, ]2.2 心情选择 UI
Row({ space: 8 }) { ForEach(MOOD_OPTIONS, (item: MoodOption, index: number) => { Column({ space: 4 }) { Text(item.emoji) .fontSize(20) .width(40).height(40).textAlign(TextAlign.Center) .borderRadius(20) .backgroundColor( this.selectedMood === index ? 'rgba(255,255,255,0.90)' : 'rgba(255,255,255,0.55)' ) .border({ width: this.selectedMood === index ? 1.5 : 0, color: 'rgba(245,166,35,0.5)' }) .shadow(this.selectedMood === index ? { radius: 8, color: 'rgba(245,166,35,0.25)' } : { radius: 0, color: 'transparent' } ) Text(item.label) .fontSize(9.5) .fontColor(this.selectedMood === index ? '#D4900A' : COLOR_TEXT_HINT) .fontWeight(this.selectedMood === index ? FontWeight.Bold : FontWeight.Normal) } .onClick(() => { this.selectedMood = index }) }) }三、@State 与 @Link 的对比
3.1 装饰器对比
| 装饰器 | 数据流向 | 声明位置 | 修改权限 |
|---|---|---|---|
@State | 内部状态 | 组件内部 | 仅本组件 |
@Prop | 父→子(单向) | 子组件 | 不可同步回父组件 |
@Link | 双向绑定 | 子组件 | 可同步回父组件 |
3.2 选择指南
- 子组件需要修改父组件数据 → 使用
@Link - 子组件只展示父组件数据 → 使用
@Prop或普通属性 - 数据只在组件内部使用→ 使用
@State
四、天气选择 UI
Row({ space: 8 }) { ForEach(WEATHER_OPTIONS, (item: WeatherOption, index: number) => { Row({ space: 4 }) { Text(item.emoji).fontSize(12) Text(item.label).fontSize(12) .fontColor(this.selectedWeather === index ? '#C8800A' : COLOR_AMBER) .fontWeight(this.selectedWeather === index ? FontWeight.Bold : FontWeight.Normal) } .padding({ left: 10, right: 10, top: 5, bottom: 5 }) .borderRadius(14) .backgroundColor( this.selectedWeather === index ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.45)' ) .border({ width: 1, color: this.selectedWeather === index ? 'rgba(245,166,35,0.35)' : 'rgba(245,166,35,0.15)' }) .onClick(() => { this.selectedWeather = index }) }) }五、完整组件布局
Column({ space: 0 }) { // 心情选择 Text('今天的心情') .fontSize(11).fontColor(COLOR_AMBER).fontWeight(FontWeight.Medium) .margin({ bottom: 8 }) // 心情 Row this.moodRow() // 天气 Row this.weatherRow() } .width('100%') .alignItems(HorizontalAlign.Start)六、常见问题与排查
6.1 @Link 绑定失败
问题:子组件修改了@Link变量,但父组件 UI 没有更新。
原因:父组件传入的值不是@State变量。
解决方案:确保父组件传入的是@State变量。
6.2 选中态不显示
问题:点击心情选项后选中状态没有变化。
原因:@Link绑定成功但 UI 判断逻辑有误。
解决方案:检查selectedMood === index的比较逻辑。
总结
本文通过“海风日记“的 MoodSelector 组件,深入讲解了 @Link 双向绑定的用法:
- @Link 装饰器:子组件中定义,与父组件 @State 双向绑定
- 心情选项:5 种心情的 emoji 和标签
- 天气选项:5 种天气的 emoji 和标签
- 选中态样式:背景色、边框、阴影的条件切换
- @State vs @Link:不同装饰器的选择策略
下一篇文章将深入讲解TextInput 与 TextArea输入框的优化体验,敬请期待。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- @Link 装饰器文档
- @State 装饰器文档
- @Prop 装饰器文档
- 海风日记项目源码
- [HarmonyOS 开发者官网](https://atomgit.com/openharmony/docs
- 开源鸿蒙跨平台社区