本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

在HarmonyOS应用开发中,随着项目规模扩大,重复的样式设置会导致代码臃肿、维护困难。@Styles装饰器应运而生,它能够将多条样式设置提炼成一个方法,实现样式的快速定义和复用。

一、@Styles装饰器

@Styles装饰器是HarmonyOS提供的一种样式复用机制,允许将多个样式属性封装成一个方法,在组件声明位置直接调用,从而减少重复代码,提高开发效率。

支持版本

版本 支持范围
API version 9 开始支持
API version 9+ 支持在ArkTS卡片中使用
API version 11+ 支持在元服务中使用

二、装饰器使用说明

2.1 支持范围

@Styles装饰器仅支持以下两类内容:

1. 通用属性

  • 所有组件通用的属性,如宽高、背景色、边距等

2. 通用事件

  • 所有组件通用的事件,如点击事件、触摸事件等

2.2 定义方式

@Styles有两种定义方式:组件内定义全局定义

定义位置 语法要求 使用范围
组件内 不需要function关键字 当前组件内使用
全局 需要在方法名前加function关键字 当前文件内使用

2.3 优先级规则

  • 组件内@Styles优先级高于全局@Styles

  • 框架查找顺序:先找当前组件内的@Styles → 找不到则全局查找

提示:@Styles只能在当前文件内使用,不支持export导出。如果需要实现样式导出,推荐使用AttributeModifier。

三、使用示例

3.1 基础用法示例

@Entry
@Component
struct FancyUse {
    @State heightValue: number = 50;
    
    // 组件内定义@Styles
    @Styles
    fancy() {
        .height(this.heightValue)
        .backgroundColor(Color.Blue)
        .onClick(() => {
            this.heightValue = 100;
        })
    }
    
    build() {
        Column() {
            Button('change height')
                .fancy()  // 调用组件内样式
        }
        .height('100%')
        .width('100%')
    }
}

效果

  • 按钮初始高度为50,背景色为蓝色

  • 点击按钮后,高度变为100

  • 展示了@Styles中可以使用状态变量和事件

3.2 组件内与全局样式对比示例

// 定义在全局的@Styles封装的样式
@Styles
function globalFancy1() {
    .width(150)
    .height(100)
    .backgroundColor(Color.Pink)
}

@Entry
@Component
struct GlobalFancy {
    @State heightValue: number = 100;
    
    // 定义在组件内的@Styles封装的样式
    @Styles
    fancy() {
        .width(200)
        .height(this.heightValue)
        .backgroundColor(Color.Gray)
        .onClick(() => {
            this.heightValue = 200;
        })
    }
    
    build() {
        Column({ space: 10 }) {
            // 使用全局的@Styles封装的样式
            Text('FancyA')
                .globalFancy1()  // 调用全局样式
                .fontSize(30)
            
            // 使用组件内的@Styles封装的样式
            Text('FancyB')
                .fancy()  // 调用组件内样式
                .fontSize(30)
        }
        .width('100%')
    }
}

效果对比

  • FancyA:粉色背景,固定150*100尺寸,无交互

  • FancyB:灰色背景,宽度200,高度初始100,点击后变为200

四、限制条件

4.1 不支持参数传递

@Styles方法不能定义参数,这是最重要的限制条件。

// 错误:@Styles不支持参数,编译期报错
@Styles
function globalFancy(value: number) {
    .width(value)
}

// 正确写法:必须使用固定值
@Styles
function globalFancy() {
    .width(100)
}

// 组件内同样不支持参数
@Styles
fancy(value: number) {  // 编译错误
    .width(value)
}

// 组件内正确写法
@Styles
fancy() {
    .width(100)
}

4.2 不支持逻辑组件

@Styles方法内不能使用条件语句、循环等逻辑组件。

// 错误写法:不能在@Styles内使用if语句
@Styles
function backgroundColorStyle() {
    if (true) {
        .backgroundColor(Color.Red)
    }
}

// 正确写法:直接设置样式
@Styles
function backgroundColorStyle() {
    .backgroundColor(Color.Red)
}

// 错误示例:也不能使用switch、for等
@Styles
function multipleStyles() {
    for (let i = 0; i < 10; i++) {  // 编译错误
        .width(100)
    }
}

4.3 其他限制

  • 不支持导出(export)

  • 只能定义在当前文件内使用

  • 方法体内只能包含样式属性和事件

五、进阶使用

5.1 访问组件状态

组件内的@Styles可以通过this访问组件的常量和状态变量:

@Entry
@Component
struct StatefulStyle {
    @State fontSizeValue: number = 16
    @State colorValue: Color = Color.Blue
    
    @Styles
    dynamicStyle() {
        .fontSize(this.fontSizeValue)
        .fontColor(this.colorValue)
        .onClick(() => {
            this.fontSizeValue = 20
            this.colorValue = Color.Red
        })
    }
    
    build() {
        Column() {
            Text('点击改变样式')
                .dynamicStyle()
        }
    }
}

5.2 组合多个样式

@Styles
function baseStyle() {
    .width('100%')
    .padding(10)
    .margin(5)
}

@Styles
function themeStyle() {
    .backgroundColor('#f5f5f5')
    .borderRadius(8)
    .border({ width: 1, color: '#e0e0e0' })
}

@Entry
@Component
struct CombinedStyles {
    build() {
        Column() {
            Text('组合样式示例')
                .baseStyle()
                .themeStyle()
                .fontSize(20)
        }
    }
}

5.3 事件处理封装

@Entry
@Component
struct EventStyleDemo {
    @State count: number = 0
    
    @Styles
    interactiveStyle() {
        .padding(10)
        .backgroundColor('#0077FF')
        .borderRadius(5)
        .onClick(() => {
            this.count++
            console.log('点击次数:' + this.count)
        })
        .onTouch((event) => {
            if (event.type === TouchType.Down) {
                this.backgroundColor('#0055CC')
            } else if (event.type === TouchType.Up) {
                this.backgroundColor('#0077FF')
            }
        })
    }
    
    build() {
        Column() {
            Text(`点击计数:${this.count}`)
                .interactiveStyle()
        }
    }
}

六、样式复用方案对比

复用方式 适用场景 优点 缺点
@Styles 组件内/文件内样式复用 简单直接,支持状态和事件 不能传参,不能导出
AttributeModifier 跨文件样式复用 支持导出,灵活可扩展 使用相对复杂
复制粘贴 临时使用 简单粗暴 代码冗余,难以维护

建议

  1. 单文件内复用:优先使用@Styles

  2. 需要跨文件复用:使用AttributeModifier

  3. 需要参数化样式:考虑使用自定义组件或AttributeModifier

注意事项

  1. 参数传递:如果需要参数,考虑使用属性方法直接设置(不支持参数)

  2. 逻辑处理:复杂逻辑应该在build()方法中处理,而不是在@Styles内(不支持if/for等逻辑)

  3. 样式冲突:注意组件内样式会覆盖全局同名样式

  4. 性能考虑:合理复用样式,避免过度抽象

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐