视频演示地址:

https://www.bilibili.com/video/BV1jomdBBE4H/
在这里插入图片描述

📋 目录


概述

TextButton 是控件库中的文本按钮组件,采用无背景设计,适用于链接、次要操作等场景。与 PrimaryButtonSecondaryButton 的主要区别在于:

  • PrimaryButton:实心背景,用于主要操作
  • SecondaryButton:边框样式,用于次要操作
  • TextButton:无背景,仅文字,用于链接或最次要的操作

设计理念

文本按钮采用极简设计,具有以下特点:

  1. 视觉轻量:无背景、无边框,视觉权重最低
  2. 链接风格:类似超链接,适合导航和跳转
  3. 灵活定制:支持下划线、自定义颜色等
  4. 品牌标识:左下角自动包含品牌标识(圆圈红字"PC")
  5. 主题统一:所有样式配置都在代码中,方便定制

特性

✨ 核心特性

  • 无背景设计:透明背景,仅显示文字和图标
  • 多种尺寸:支持 small、medium、large 三种尺寸
  • 图标支持:支持左侧或右侧图标
  • 加载状态:内置加载动画
  • 禁用状态:支持禁用状态,自动调整样式
  • 下划线支持:可选择是否显示下划线(类似链接)
  • 自定义颜色:支持自定义文字颜色
  • 品牌标识:自动包含左下角品牌标识
  • 主题配置:所有样式都可通过代码配置

🎨 视觉特点

  • 正常状态:蓝色文字 + 透明背景(可选下划线)
  • 悬停状态:文字颜色加深(通过系统自动处理)
  • 按下状态:文字颜色进一步加深
  • 禁用状态:灰色文字 + 50% 透明度

快速开始

基础用法

import { TextButton } from '../components/base'

@Entry
@Component
struct MyPage {
  build() {
    Column({ space: 20 }) {
      // 基础文本按钮
      TextButton({
        text: '了解更多'
      })
      
      // 带下划线的文本按钮(类似链接)
      TextButton({
        text: '查看详情',
        underline: true
      })
      
      // 带图标的文本按钮
      TextButton({
        text: '下载',
        icon: $r('app.media.icon_download'),
        iconPosition: 'left'
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

与其他按钮配合使用

@Entry
@Component
struct ButtonGroupExample {
  build() {
    Column({ space: 20 }) {
      // 主要操作
      PrimaryButton({
        text: '提交'
      })
      
      // 次要操作
      SecondaryButton({
        text: '取消'
      })
      
      // 链接式操作
      TextButton({
        text: '了解更多',
        underline: true
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

关于点击事件处理

TextButtononClickBuilder 属性是 @BuilderParam 类型,需要使用 @Builder@LocalBuilder 方法初始化。在实际项目中,推荐使用以下方式处理点击事件:

  1. 状态管理方式:通过 @State 变量和普通 ButtononClick 来处理
  2. 自定义事件系统:创建自定义事件处理机制
  3. @Builder 方法:如果需要使用 onClickBuilder,需要定义 @Builder 方法

本文档中的示例主要展示按钮的视觉效果和样式配置,点击事件处理可以通过上述方式实现。


API 参考

Props

属性名 类型 默认值 说明
text string '按钮' 按钮文字
icon ResourceStr? undefined 按钮图标(可选)
iconPosition 'left' | 'right' 'left' 图标位置
buttonSize 'small' | 'medium' | 'large' 'medium' 按钮尺寸
loading boolean false 是否加载中
disabled boolean false 是否禁用
showBrand boolean true 是否显示品牌标识
buttonWidth string | number? undefined 按钮宽度(可选)
buttonHeight string | number? undefined 按钮高度(可选)
onClickBuilder @BuilderParam () => void? undefined 点击事件回调(需要使用 @Builder 或 @LocalBuilder 方法)
textColor string? undefined 文字颜色(可选,默认使用主题主色)
underline boolean false 是否显示下划线

尺寸规格

尺寸 高度 字体大小 图标大小 内边距
small 28vp 12vp 14vp 8vp × 4vp
medium 36vp 14vp 18vp 12vp × 6vp
large 44vp 16vp 22vp 16vp × 8vp

使用示例

1. 基础按钮

@Entry
@Component
struct ButtonExample1 {
  build() {
    Column({ space: 15 }) {
      TextButton({
        text: '了解更多'
      })
      
      TextButton({
        text: '查看详情'
      })
      
      TextButton({
        text: '帮助文档'
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

2. 不同尺寸

@Entry
@Component
struct ButtonExample2 {
  build() {
    Column({ space: 15 }) {
      TextButton({
        text: '小按钮',
        buttonSize: 'small'
      })
      
      TextButton({
        text: '中等按钮(默认)',
        buttonSize: 'medium'
      })
      
      TextButton({
        text: '大按钮',
        buttonSize: 'large'
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

3. 下划线样式(链接风格)

@Entry
@Component
struct ButtonExample3 {
  build() {
    Column({ space: 15 }) {
      // 无下划线(默认)
      TextButton({
        text: '普通文本按钮'
      })
      
      // 有下划线(链接风格)
      TextButton({
        text: '链接式按钮',
        underline: true
      })
      
      // 带下划线的图标按钮
      TextButton({
        text: '查看详情',
        icon: $r('app.media.icon_link'),
        iconPosition: 'right',
        underline: true
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

4. 图标按钮

@Entry
@Component
struct ButtonExample4 {
  build() {
    Column({ space: 15 }) {
      // 左侧图标
      TextButton({
        text: '下载',
        icon: $r('app.media.icon_download'),
        iconPosition: 'left'
      })
      
      // 右侧图标
      TextButton({
        text: '更多',
        icon: $r('app.media.icon_more'),
        iconPosition: 'right'
      })
      
      // 仅图标(通过空文字实现)
      TextButton({
        text: '',
        icon: $r('app.media.icon_settings'),
        buttonWidth: 32,
        buttonHeight: 32
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

5. 自定义颜色

@Entry
@Component
struct ButtonExample5 {
  build() {
    Column({ space: 15 }) {
      // 默认颜色(主题主色)
      TextButton({
        text: '默认颜色'
      })
      
      // 自定义颜色
      TextButton({
        text: '成功色',
        textColor: '#34C759'
      })
      
      TextButton({
        text: '警告色',
        textColor: '#FF9500'
      })
      
      TextButton({
        text: '错误色',
        textColor: '#FF3B30'
      })
      
      TextButton({
        text: '自定义蓝色',
        textColor: '#5AC8FA'
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

6. 加载状态

@Entry
@Component
struct ButtonExample6 {
  @State loading: boolean = false
  
  // 处理加载操作
  handleLoad() {
    this.loading = true
    // 模拟异步操作
    setTimeout(() => {
      this.loading = false
      console.info('加载完成')
    }, 2000)
  }
  
  build() {
    Column({ space: 20 }) {
      TextButton({
        text: '加载数据',
        loading: this.loading
      })
      
      // 使用普通按钮触发加载状态
      Button() {
        Text(this.loading ? '加载中...' : '点击加载')
      }
      .onClick(() => {
        this.handleLoad()
      })
      .enabled(!this.loading)
      
      Text('点击按钮查看加载状态')
        .fontSize(12)
        .fontColor('#999999')
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

7. 禁用状态

@Entry
@Component
struct ButtonExample7 {
  @State canEdit: boolean = false
  
  build() {
    Column({ space: 20 }) {
      TextButton({
        text: '编辑',
        disabled: !this.canEdit
      })
      
      Row({ space: 10 }) {
        Text('编辑权限:')
          .fontSize(14)
        Toggle({ type: ToggleType.Switch, isOn: this.canEdit })
          .onChange((isOn: boolean) => {
            this.canEdit = isOn
          })
        Text(this.canEdit ? '已开启' : '已关闭')
          .fontSize(14)
          .fontColor(this.canEdit ? '#10B981' : '#EF4444')
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

8. 按钮组合

@Entry
@Component
struct ButtonExample8 {
  build() {
    Column({ space: 20 }) {
      // 主要操作 + 链接
      Row({ space: 12 }) {
        PrimaryButton({
          text: '提交',
          buttonSize: 'medium'
        })
        
        TextButton({
          text: '取消',
          buttonSize: 'medium'
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.End)
      
      // 链接组
      Row({ space: 16 }) {
        TextButton({
          text: '帮助',
          underline: true
        })
        
        TextButton({
          text: '反馈',
          underline: true
        })
        
        TextButton({
          text: '关于',
          underline: true
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.Center)
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

9. 导航场景

@Entry
@Component
struct NavigationExample {
  build() {
    Column({ space: 20 }) {
      // 面包屑导航
      Row({ space: 8 }) {
        TextButton({
          text: '首页',
          buttonSize: 'small'
        })
        Text('>')
          .fontColor('#999999')
        TextButton({
          text: '分类',
          buttonSize: 'small'
        })
        Text('>')
          .fontColor('#999999')
        Text('详情')
          .fontColor('#666666')
      }
      
      // 操作链接
      Row({ space: 16 }) {
        TextButton({
          text: '返回',
          icon: $r('app.media.icon_back'),
          iconPosition: 'left',
          underline: true
        })
        
        TextButton({
          text: '分享',
          icon: $r('app.media.icon_share'),
          iconPosition: 'left',
          underline: true
        })
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

10. 表单场景

@Entry
@Component
struct FormExample {
  @State formData: {
    username: string
    password: string
  } = { username: '', password: '' }
  
  build() {
    Column({ space: 20 }) {
      // 表单标题
      Text('登录')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
      
      // 表单内容
      TextInput({ placeholder: '用户名' })
        .onChange((value: string) => {
          this.formData.username = value
        })
      
      TextInput({ placeholder: '密码' })
        .type(InputType.Password)
        .onChange((value: string) => {
          this.formData.password = value
        })
      
      // 主要操作
      PrimaryButton({
        text: '登录',
        buttonWidth: '100%',
        buttonSize: 'large'
      })
      
      // 次要操作和链接
      Row({ space: 12 }) {
        TextButton({
          text: '忘记密码?',
          underline: true,
          buttonSize: 'small'
        })
        
        TextButton({
          text: '注册账号',
          underline: true,
          buttonSize: 'small'
        })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

主题配置

TextButton 的所有样式都通过 ComponentTheme 配置,所有配置都在代码中,不依赖JSON文件。

修改默认文字颜色

import { ComponentTheme } from '../theme/ComponentTheme'

// 修改主题主色(影响 TextButton 的默认文字颜色)
ComponentTheme.PRIMARY_COLOR = '#007AFF'

// 修改禁用文字颜色
ComponentTheme.TEXT_DISABLED = '#CCCCCC'

批量配置

import { ComponentTheme } from '../theme/ComponentTheme'

// 使用 setTheme 方法批量配置
ComponentTheme.setTheme({
  primaryColor: '#007AFF',
  borderRadius: 8,
  spacing: 16
})

自定义主题

// 在应用启动时配置
import { ComponentTheme } from './theme/ComponentTheme'

// 设置自定义主色
ComponentTheme.PRIMARY_COLOR = '#34C759'  // 绿色

最佳实践

1. 按钮层次使用

推荐:根据操作重要性选择按钮类型

// 主要操作
PrimaryButton({ text: '提交' })

// 次要操作
SecondaryButton({ text: '取消' })

// 链接式操作
TextButton({ text: '了解更多', underline: true })

2. 尺寸选择

  • small:用于紧凑空间,如表格操作列、面包屑导航
  • medium:默认尺寸,适用于大多数场景
  • large:用于重要链接或大屏幕显示

3. 下划线使用

  • 有下划线:用于明确的链接操作(如"查看详情"、“了解更多”)
  • 无下划线:用于次要操作按钮(如"取消"、“跳过”)

4. 图标使用

  • 使用图标增强按钮的可识别性
  • 常用操作使用标准图标(如返回、下载、设置)
  • 图标位置根据阅读习惯选择

5. 颜色使用

  • 默认使用主题主色,保持视觉统一
  • 特殊场景可使用自定义颜色(如成功、警告、错误)
  • 避免在同一页面使用过多不同颜色

6. 响应式设计

  • 使用百分比宽度适配不同屏幕
  • 在小屏幕上考虑使用全宽按钮
  • 保持按钮之间的合理间距

常见问题

Q1: TextButton 和其他按钮有什么区别?

A: 主要区别在于视觉样式和适用场景:

  • PrimaryButton:实心背景,用于主要操作
  • SecondaryButton:边框样式,用于次要操作
  • TextButton:无背景,仅文字,用于链接或最次要的操作

功能上三者基本相同,都支持图标、加载、禁用等状态。

Q2: 什么时候使用下划线?

A: 下划线用于明确的链接操作:

  • 使用下划线:导航链接、跳转链接、详情链接
  • 不使用下划线:次要操作按钮、取消按钮

Q3: 如何自定义按钮颜色?

A: 有两种方式:

  1. 通过 textColor 属性(单个按钮):
TextButton({
  text: '按钮',
  textColor: '#34C759'
})
  1. 通过 ComponentTheme(全局配置):
ComponentTheme.PRIMARY_COLOR = '#34C759'

Q4: 如何处理按钮点击事件?

A: onClickBuilder@BuilderParam 类型,需要使用 @Builder@LocalBuilder 方法。推荐使用状态管理或自定义事件系统:

@Entry
@Component
struct MyPage {
  @State count: number = 0
  
  handleClick() {
    this.count++
    console.info('按钮被点击')
  }
  
  build() {
    Column({ space: 20 }) {
      // 使用普通按钮处理点击
      Button('点击我')
        .onClick(() => {
          this.handleClick()
        })
      
      // 使用 TextButton 展示样式
      TextButton({
        text: '文本按钮'
      })
      
      Text(`点击次数:${this.count}`)
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

Q5: TextButton 可以用于导航吗?

A: 可以。TextButton 非常适合用于导航场景,特别是配合下划线使用:

Row({ space: 16 }) {
  TextButton({
    text: '首页',
    underline: true
  })
  TextButton({
    text: '分类',
    underline: true
  })
  TextButton({
    text: '关于',
    underline: true
  })
}

Q6: 按钮文字可以换行吗?

A: 按钮文字默认不换行。如果需要多行文字,建议使用其他组件或自定义实现。


总结

TextButton 是控件库中的文本按钮组件,具有以下核心特性:

  1. 视觉轻量:无背景设计,视觉权重最低
  2. 链接风格:支持下划线,适合导航和跳转
  3. 功能完整:支持图标、加载、禁用等多种状态
  4. 尺寸灵活:三种尺寸满足不同场景需求
  5. 易于使用:简单的 API,开箱即用
  6. 主题配置:所有样式都可通过代码配置
  7. 品牌标识:自动包含品牌标识,保持视觉统一

关键要点

  • ✅ 使用 buttonSize 属性选择合适尺寸
  • ✅ 使用 underline 属性实现链接风格
  • ✅ 使用 textColor 属性自定义颜色
  • ✅ 使用 loading 属性处理异步操作
  • ✅ 使用 disabled 属性控制按钮状态
  • ✅ 通过 ComponentTheme 自定义全局样式

适用场景

  • 导航链接(如面包屑、菜单项)
  • 次要操作按钮(如"取消"、“跳过”)
  • 帮助和说明链接(如"了解更多"、“查看详情”)
  • 表单中的辅助链接(如"忘记密码"、“注册账号”)
  • 需要降低视觉权重的操作按钮

下一篇预告:IconButton(图标按钮)详解


本文档属于《鸿蒙PC UI控件库开发系列文章》第4篇

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐