安卓开发者自学鸿蒙开发4自定义组件
·
先来个最简例子
// 1. 定义自定义组件,其实跟页面的定义差异不大,页面也是一个组件,万物兼组件
@Component
struct MyButton {
// 组件属性,用prop表示可以外部传入参数值,state则为内部独有数据
@Prop text: string = '按钮';
// 事件回调
private onClick: () => void = () => {};
// 必须的build方法
build() {
Button(this.text)
.onClick(() => this.onClick())
}
}
// 2. 使用自定义组件
@Entry
@Component
struct MyPage {
@State count: number = 0;
// 按钮点击处理
handleClick() {
this.count++;
console.log('点击次数:', this.count);
}
build() {
Column() {
Text(`计数: ${this.count}`)
// 使用自定义组件
MyButton({
text: '点我增加',
onClick: this.handleClick.bind(this) // 绑定事件
})
}
}
}
插槽使用
注意定义的时候用的@BuilderParam 以及他的定义方式和默认值(title: string) => void = () => {};这个格式是固定的
使用的时候就当做一个普通的预设组件是几乎完全相同的
// 1. 定义组件
@Component
struct DualSlot {
// 带参数插槽
@BuilderParam header: (title: string) => void = () => {};
// 不带参数插槽
@BuilderParam content: () => void = () => {};
build() {
Column() {
// 调用带参数插槽
this.header("标题")
// 调用不带参数插槽
this.content()
}
}
}
// 2. 使用组件
@Entry
@Component
struct MainPage {
build() {
DualSlot()
// 带参数插槽使用
.header((title: string) => {
Text(title) // 使用传入的参数
})
// 不带参数插槽使用
.content(() => {
Text("内容")
})
}
}
父子组件数据传递
// 1. 子组件(包含三种接收方式)
@Component
struct Child {
// 1. 双向绑定
@Link linkValue: number;
// 2. 单向传递
@Prop propValue: number;
// 3. 只读传递
normalValue: number;
build() {
Column() {
// 双向绑定组件
Button(`双向: ${this.linkValue}`)
.onClick(() => this.linkValue++) // 可修改父组件数据
// 单向传递组件
Button(`单向: ${this.propValue}`)
.onClick(() => {
this.propValue++; // 只能修改本地副本
})
// 只读传递组件
Text(`只读: ${this.normalValue}`)
}
}
}
// 2. 父组件
@Entry
@Component
struct Parent {
@State count: number = 0;
build() {
Column() {
Text(`父组件值: ${this.count}`)
.fontSize(20)
.margin(20)
// 传递三种类型数据
Child({
linkValue: $count, // 双向绑定(使用$)
propValue: this.count, // 单向传递
normalValue: this.count // 只读传递
})
Button('父组件增加')
.onClick(() => this.count++)
.margin(20)
}
}
}
| 传递方式 | 装饰器 | 方向 | 子组件能否修改 | 父组件更新 | 代码示例 |
|---|---|---|---|---|---|
| 双向绑定 | @Link |
父 ↔ 子 | 是 | 自动同步 | Child({ value: $count }) |
| 单向传递 | @Prop |
父 → 子 | 是(仅本地) | 不自动更新 | Child({ value: this.count }) |
| 只读传递 | 无装饰器 | 父 → 子 | 否 | 不自动更新(因为没绑定到组件上) | Child({ value: this.count }) |
祖孙组件通信:@Provide 和 @Consume
// 1. 祖先组件
@Component
struct Grandparent {
@Provide theme: string = 'light';
build() {
Column() {
Text('祖先组件').fontSize(20)
Parent()
}
}
}
// 2. 父组件(中间层)
@Component
struct Parent {
build() {
Column() {
Text('父组件').fontSize(18)
Child()
}
}
}
// 3. 子孙组件
@Component
struct Child {
@Consume theme: string;
build() {
Text(`当前主题: ${this.theme}`)
.fontColor(this.theme === 'light' ? '#000' : '#FFF')
}
}
事件总线实现数据更新
简单实现
// eventBus.ts
type EventHandler = (data: any) => void;
class EventBus {
private static events: Map<string, EventHandler[]> = new Map();
// 订阅事件
static on(event: string, handler: EventHandler) {
if (!this.events.has(event)) {
this.events.set(event, []);
}
this.events.get(event)?.push(handler);
}
// 取消订阅
static off(event: string, handler?: EventHandler) {
if (!handler) {
this.events.delete(event);
return;
}
const handlers = this.events.get(event);
if (handlers) {
const index = handlers.indexOf(handler);
if (index > -1) {
handlers.splice(index, 1);
}
}
}
// 发布事件
static emit(event: string, data?: any) {
const handlers = this.events.get(event);
if (handlers) {
handlers.forEach(handler => handler(data));
}
}
}
export default EventBus;
使用
import EventBus from './eventBus';
// 在组件A中
Button('发送事件').onClick(() => {
EventBus.emit('DATA_CHANGE', { value: 100 });
});
更多推荐



所有评论(0)