
https://www.bilibili.com/video/BV1jomdBBE4H/

系列文章第2篇 | 作者:红目香薰 | 更新时间:2025年
在上一篇文章中,我们介绍了控件库的品牌标识系统,这是所有控件的基础设施。从本文开始,我们将逐一介绍控件库中的实际控件。
本文要介绍的是 PrimaryButton(主要按钮),这是控件库中的第1个基础控件,也是最常用的按钮组件。PrimaryButton 支持图标、加载状态、多种尺寸,并且自动包含品牌标识。
PrimaryButton 是一个功能完整的主要按钮组件,具有以下特点:
import { PrimaryButton } from '../components/base'最简单的使用方式:
@Entry
@Component
struct MyPage {
build() {
Column({ space: 20 }) {
// 基础按钮
PrimaryButton({
text: '点击我'
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}最简单的按钮,只需要设置文字:
PrimaryButton({
text: '提交'
})可以在按钮左侧或右侧添加图标:
// 左侧图标
PrimaryButton({
text: '保存',
icon: $r('app.media.icon_save'),
iconPosition: 'left'
})
// 右侧图标
PrimaryButton({
text: '下一步',
icon: $r('app.media.icon_arrow_right'),
iconPosition: 'right'
})支持三种尺寸:small、medium、large
Column({ space: 20 }) {
// 小按钮
PrimaryButton({
text: '小按钮',
buttonSize: 'small'
})
// 中等按钮(默认)
PrimaryButton({
text: '中等按钮',
buttonSize: 'medium'
})
// 大按钮
PrimaryButton({
text: '大按钮',
buttonSize: 'large'
})
}尺寸对比:
尺寸 | 高度 | 字体大小 | 图标大小 | 内边距 |
|---|---|---|---|---|
small | 32vp | 12vp | 16vp | 12vp |
medium | 40vp | 14vp | 20vp | 16vp |
large | 48vp | 16vp | 24vp | 24vp |
在异步操作时显示加载动画:
@Entry
@Component
struct MyPage {
@State loading: boolean = false
build() {
Column({ space: 20 }) {
PrimaryButton({
text: '提交数据',
loading: this.loading,
onClickCallback: () => {
this.loading = true
// 模拟异步操作
setTimeout(() => {
this.loading = false
}, 2000)
}
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}加载状态特点:
禁用按钮,常用于表单验证或权限控制:
@Entry
@Component
struct MyPage {
@State formValid: boolean = false
build() {
Column({ space: 20 }) {
PrimaryButton({
text: '提交',
disabled: !this.formValid
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}禁用状态特点:
PRIMARY_COLOR_DISABLED)使用 onClickCallback 处理点击事件:
@Entry
@Component
struct MyPage {
handleClick() {
console.info('按钮被点击了')
// 执行你的业务逻辑
}
build() {
Column({ space: 20 }) {
PrimaryButton({
text: '点击我',
onClickCallback: () => {
this.handleClick()
}
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}可以自定义按钮的宽度和高度:
// 固定宽度
PrimaryButton({
text: '固定宽度按钮',
buttonWidth: 200
})
// 百分比宽度
PrimaryButton({
text: '全宽按钮',
buttonWidth: '100%'
})
// 自定义高度
PrimaryButton({
text: '自定义高度',
buttonHeight: 50
})如果需要隐藏品牌标识(不推荐):
PrimaryButton({
text: '无标识按钮',
showBrand: false
})PrimaryButton 的所有样式都通过 ComponentTheme 配置,所有配置都在代码中,不依赖JSON文件。
import { ComponentTheme } from '../theme/ComponentTheme'
// 修改主色调
ComponentTheme.PRIMARY_COLOR = '#007AFF' // 正常状态
ComponentTheme.PRIMARY_COLOR_HOVER = '#0051D5' // 悬停状态
ComponentTheme.PRIMARY_COLOR_ACTIVE = '#0040A8' // 按下状态
ComponentTheme.PRIMARY_COLOR_DISABLED = '#CCCCCC' // 禁用状态ComponentTheme.BORDER_RADIUS = 8 // 默认圆角ComponentTheme.setTheme({
primaryColor: '#007AFF',
borderRadius: 8
})属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
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 | 按钮高度(可选) |
onClickCallback | () => void? | undefined | 点击事件回调 |
尺寸 | 高度 | 字体 | 图标 | 内边距(左右) | 内边距(上下) |
|---|---|---|---|---|---|
small | 32vp | 12vp | 16vp | 12vp | 6vp |
medium | 40vp | 14vp | 20vp | 16vp | 8vp |
large | 48vp | 16vp | 24vp | 24vp | 12vp |
根据使用场景选择合适的尺寸:
// ✅ 推荐:主要操作使用 medium 或 large
PrimaryButton({ text: '提交', buttonSize: 'medium' })
// ✅ 推荐:次要操作或空间受限时使用 small
PrimaryButton({ text: '取消', buttonSize: 'small' })
// ✅ 推荐:重要操作使用 large
PrimaryButton({ text: '立即购买', buttonSize: 'large' })在异步操作时及时显示加载状态:
@State loading: boolean = false
async handleSubmit() {
this.loading = true
try {
await submitData()
// 成功处理
} catch (error) {
// 错误处理
} finally {
this.loading = false
}
}
PrimaryButton({
text: '提交',
loading: this.loading,
onClickCallback: () => this.handleSubmit()
})使用图标增强按钮的可识别性:
// ✅ 推荐:使用语义明确的图标
PrimaryButton({
text: '保存',
icon: $r('app.media.icon_save'),
iconPosition: 'left'
})
// ✅ 推荐:操作类按钮使用右侧图标
PrimaryButton({
text: '下一步',
icon: $r('app.media.icon_arrow_right'),
iconPosition: 'right'
})在表单验证或权限控制时使用禁用状态:
@State formValid: boolean = false
@State hasPermission: boolean = true
PrimaryButton({
text: '提交',
disabled: !this.formValid || !this.hasPermission
})除非特殊需求,建议保持品牌标识显示:
// ✅ 推荐:保持品牌标识
PrimaryButton({ text: '提交' })
// ⚠️ 仅在特殊场景下隐藏
PrimaryButton({ text: '提交', showBrand: false })通过 ComponentTheme 修改:
ComponentTheme.PRIMARY_COLOR = '#FF6B35' // 自定义主色加载状态会自动禁用按钮,无需额外处理:
PrimaryButton({
text: '提交',
loading: this.loading, // loading 为 true 时自动禁用
onClickCallback: () => {
this.loading = true
// 执行异步操作
}
})按钮会自动使用 ComponentTheme.PRIMARY_COLOR_HOVER 作为悬停颜色,你只需要配置:
ComponentTheme.PRIMARY_COLOR_HOVER = '#0051D5'图标资源需要放在 resources/base/media/ 目录下,然后在代码中引用:
// 使用资源引用
icon: $r('app.media.icon_save')
// 或使用路径
icon: 'common/icons/save.png'可以,使用 @State 管理文字:
@State buttonText: string = '提交'
PrimaryButton({
text: this.buttonText
})
// 动态更新
this.buttonText = '提交中...'import { PrimaryButton } from '../components/base'
@Entry
@Component
struct ButtonExample1 {
build() {
Column({ space: 20 }) {
// 基础按钮
PrimaryButton({
text: '提交'
})
// 带图标按钮
PrimaryButton({
text: '保存',
icon: $r('app.media.icon_save'),
iconPosition: 'left'
})
// 不同尺寸
Row({ space: 20 }) {
PrimaryButton({ text: '小', buttonSize: 'small' })
PrimaryButton({ text: '中', buttonSize: 'medium' })
PrimaryButton({ text: '大', buttonSize: 'large' })
}
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}import { PrimaryButton } from '../components/base'
@Entry
@Component
struct ButtonExample2 {
@State loading: boolean = false
async handleSubmit() {
this.loading = true
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 2000))
this.loading = false
console.info('提交成功')
}
build() {
Column({ space: 20 }) {
PrimaryButton({
text: '提交数据',
loading: this.loading,
onClickCallback: () => {
this.handleSubmit()
}
})
Text(this.loading ? '提交中...' : '点击提交')
.fontSize(14)
.fontColor('#666666')
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}import { PrimaryButton } from '../components/base'
@Entry
@Component
struct ButtonExample3 {
@State username: string = ''
@State password: string = ''
@State loading: boolean = false
get formValid(): boolean {
return this.username.length > 0 && this.password.length > 0
}
async handleLogin() {
if (!this.formValid) return
this.loading = true
try {
// 执行登录逻辑
await login(this.username, this.password)
console.info('登录成功')
} catch (error) {
console.error('登录失败', error)
} finally {
this.loading = false
}
}
build() {
Column({ space: 20 }) {
TextInput({ placeholder: '用户名' })
.onChange((value: string) => {
this.username = value
})
TextInput({ placeholder: '密码', type: InputType.Password })
.onChange((value: string) => {
this.password = value
})
PrimaryButton({
text: '登录',
loading: this.loading,
disabled: !this.formValid,
buttonWidth: '100%',
onClickCallback: () => {
this.handleLogin()
}
})
}
.width('100%')
.height('100%')
.padding(20)
}
}import { PrimaryButton } from '../components/base'
@Entry
@Component
struct ButtonExample4 {
build() {
Column({ space: 20 }) {
// 左侧图标
PrimaryButton({
text: '保存',
icon: $r('app.media.icon_save'),
iconPosition: 'left',
buttonWidth: 150
})
// 右侧图标
PrimaryButton({
text: '下一步',
icon: $r('app.media.icon_arrow_right'),
iconPosition: 'right',
buttonWidth: 150
})
// 仅图标(通过空文字实现)
PrimaryButton({
text: '',
icon: $r('app.media.icon_add'),
buttonWidth: 48,
buttonHeight: 48
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}import { PrimaryButton } from '../components/base'
@Entry
@Component
struct ButtonExample5 {
build() {
Column({ space: 15 }) {
PrimaryButton({
text: '全宽按钮',
buttonWidth: '100%',
buttonSize: 'large'
})
PrimaryButton({
text: '中等宽度',
buttonWidth: '60%',
buttonSize: 'medium'
})
PrimaryButton({
text: '小宽度',
buttonWidth: 120,
buttonSize: 'small'
})
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}PrimaryButton 是控件库中的第一个基础控件,具有以下核心特性:
buttonSize 属性选择合适尺寸loading 属性处理异步操作disabled 属性控制按钮状态icon 和 iconPosition 添加图标ComponentTheme 自定义样式下一篇预告:《鸿蒙PC UI控件库 - SecondaryButton 次要按钮详解》
本文是鸿蒙PC UI控件库系列文章的第2篇,后续将陆续发布更多控件的详细教程。