前言:ArkTS作为鸿蒙生态的应用开发语言,提供了丰富而强大的组件通信机制。在实际应用开发中,组件之间的数据传递和状态同步是构建复杂应用的关键。本次将深入探讨ArkTS中的各种组件通信方式,通过详细代码示例帮助开发者全面掌握这一核心技术。

一、Props单向数据传递

1.1 基础Props传递

Props是父子组件通信最基本的方式,支持父组件向子组件传递数据:

// 定义数据接口
interface UserInfo {
  name: string;
  age: number;
  email: string;
}

@Component
struct UserCard {
  // 使用@Prop接收父组件传递的数据
  @Prop user: UserInfo;
  // 接收简单数据类型
  @Prop isActive: boolean = false;

  build() {
    Column() {
      Text(this.user.name)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      
      Text(`Age: ${this.user.age}`)
        .fontSize(16)
        .opacity(0.8)
      
      Text(this.user.email)
        .fontSize(14)
        .opacity(0.6)
      
      Text(this.isActive ? 'Active' : 'Inactive')
        .fontColor(this.isActive ? '#007AFF' : '#999999')
    }
    .padding(12)
    .backgroundColor(this.isActive ? '#F5F5F5' : '#FFFFFF')
  }
}

@Component
struct ParentComponent {
  private userData: UserInfo = {
    name: '张三',
    age: 28,
    email: 'zhangsan@example.com'
  };

  build() {
    Column() {
      UserCard({ user: this.userData, isActive: true })
      UserCard({ 
        user: {
          name: '李四',
          age: 32,
          email: 'lisi@example.com'
        }, 
        isActive: false 
      })
    }
  }
}

1.2 Props的响应式特性

当父组件中的数据发生变化时,子组件会自动更新:

@Component
struct CounterDisplay {
  @Prop count: number;

  build() {
    Text(`当前计数: ${this.count}`)
      .fontSize(24)
      .fontColor(Color.Blue)
  }
}

@Component
struct CounterController {
  @State private currentCount: number = 0;

  build() {
    Column() {
      CounterDisplay({ count: this.currentCount })
      
      Button('增加计数')
        .onClick(() => {
          this.currentCount++;
        })
        .margin(10)
      
      Button('重置')
        .onClick(() => {
          this.currentCount = 0;
        })
    }
  }
}

二、@Link双向数据绑定

@Link装饰器用于实现父子组件之间的双向数据绑定:

@Component
struct TextEditor {
  @Link textValue: string;

  build() {
    TextInput({ text: this.textValue })
      .onChange((value: string) => {
        this.textValue = value;
      })
      .width('100%')
      .height(40)
      .borderWidth(1)
  }
}

@Component
struct EditorPage {
  @State inputText: string = '';

  build() {
    Column() {
      Text('当前内容: ' + this.inputText)
        .margin(10)
      
      TextEditor({ textValue: $inputText })
        .margin(10)
      
      Button('清空内容')
        .onClick(() => {
          this.inputText = '';
        })
    }
  }
}

三、@Provide和@Consume跨层级通信

对于深层嵌套的组件,使用@Provide和@Consume避免逐层传递:

// 主题配置接口
interface ThemeConfig {
  primaryColor: string;
  backgroundColor: string;
  textColor: string;
  fontSize: number;
}

@Component
struct AppRoot {
  @Provide('appTheme') theme: ThemeConfig = {
    primaryColor: '#007AFF',
    backgroundColor: '#FFFFFF',
    textColor: '#333333',
    fontSize: 16
  };

  build() {
    Column() {
      HeaderComponent()
      ContentComponent()
      FooterComponent()
    }
  }
}

@Component
struct HeaderComponent {
  @Consume('appTheme') theme: ThemeConfig;

  build() {
    Text('应用标题')
      .fontSize(this.theme.fontSize + 4)
      .fontColor(this.theme.primaryColor)
      .backgroundColor(this.theme.backgroundColor)
      .padding(10)
  }
}

@Component
struct ContentComponent {
  @Consume('appTheme') theme: ThemeConfig;

  build() {
    Column() {
      Text('内容区域')
        .fontSize(this.theme.fontSize)
        .fontColor(this.theme.textColor)
      
      Button('切换主题')
        .onClick(() => {
          // 通过@Consume获取的引用可以直接修改
          this.theme.primaryColor = this.theme.primaryColor === '#007AFF' ? '#FF9500' : '#007AFF';
        })
    }
  }
}

四、全局状态管理

4.1 AppStorage全局状态

// 初始化全局状态
AppStorage.SetOrCreate('userPreferences', {
  language: 'zh-CN',
  theme: 'light',
  notifications: true
});

AppStorage.SetOrCreate('authToken', '');

@Component
struct SettingsPage {
  @StorageLink('userPreferences') preferences: any;
  @StorageProp('authToken') token: string;

  build() {
    Column() {
      Text(`当前语言: ${this.preferences.language}`)
      
      Toggle({ type: ToggleType.Switch, isOn: this.preferences.notifications })
        .onChange((value: boolean) => {
          this.preferences.notifications = value;
        })
      
      Button('退出登录')
        .onClick(() => {
          this.token = '';
          AppStorage.Set('authToken', '');
        })
    }
  }
}

4.2 LocalStorage页面级状态

const pageStorage = new LocalStorage();

@Component
struct DataListPage {
  @LocalStorageProp('listData') data: string[] = [];
  @LocalStorageLink('selectedItem') selectedItem: string = '';

  build() {
    Column() {
      List({ space: 10 }) {
        ForEach(this.data, (item: string) => {
          ListItem() {
            Text(item)
              .fontColor(this.selectedItem === item ? Color.Red : Color.Black)
          }
          .onClick(() => {
            this.selectedItem = item;
          })
        })
      }
      
      Button('添加项目')
        .onClick(() => {
          this.data.push(`项目 ${this.data.length + 1}`);
        })
    }
  }
}

@Entry(pageStorage)
@Component
struct MainEntry {
  build() {
    DataListPage()
  }
}

五、自定义事件通信

// 定义自定义事件
class CustomEventDetail {
  constructor(public type: string, public data: any, public timestamp: number) {}
}

@Component
struct EventEmitterComponent {
  @State private eventCount: number = 0;

  // 发送事件的方法
  private emitEvent(type: string, data: any) {
    const eventDetail = new CustomEventDetail(type, data, Date.now());
    this.emit(eventDetail);
    this.eventCount++;
  }

  build() {
    Column() {
      Button('发送用户登录事件')
        .onClick(() => {
          this.emitEvent('userLogin', { userId: 123, username: 'testuser' });
        })
      
      Button('发送数据更新事件')
        .onClick(() => {
          this.emitEvent('dataUpdate', { items: [1, 2, 3], total: 3 });
        })
      
      Text(`已发送事件数: ${this.eventCount}`)
    }
  }
}

@Component
struct EventReceiverComponent {
  private handleEvent(event: CustomEventDetail) {
    console.log('收到事件:', event.type, event.data);
    
    switch (event.type) {
      case 'userLogin':
        this.handleUserLogin(event.data);
        break;
      case 'dataUpdate':
        this.handleDataUpdate(event.data);
        break;
    }
  }

  private handleUserLogin(data: any) {
    console.log('用户登录处理:', data);
  }

  private handleDataUpdate(data: any) {
    console.log('数据更新处理:', data);
  }

  build() {
    Column() {
      EventEmitterComponent()
        .onEvent((event: CustomEventDetail) => this.handleEvent(event))
    }
  }
}

六、通信方式小结

  1. Props​​:简单的父子组件单向数据传递
  2. @Link​​:需要双向数据绑定的场景
  3. @Provide/@Consume​​:跨多层组件的状态共享
  4. AppStorage​​:全局需要访问的配置和状态
  5. ​LocalStorage​​:页面内多个组件共享的状态
  6. 自定义事件​​:组件需要向外部发送通知的场景

总结

ArkTS提供了多层次、多场景的组件通信解决方案,开发者可以根据具体需求选择合适的通信方式。在实际开发中,建议遵循以下原则:

  1. 尽量使用Props进行简单的数据传递
  2. 合理使用@Link进行双向绑定,避免过度使用
  3. 跨层级通信优先考虑@Provide/@Consume
  4. 全局状态使用AppStorage统一管理
  5. 复杂交互场景可以结合多种通信方式

通过熟练掌握这些通信机制,开发者能够构建出结构清晰、维护方便的高质量ArkTS应用。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐