HarmonyOS开发实战: EmailFeedbackPage 意见反馈 + AboutPage 关于页
EmailFeedbackPage 意见反馈 + AboutPage 关于页
前言
当用户使用「海风日记」一段时间后,可能会想:这个 App 是谁做的?我有问题该反馈给谁?于是关于页(AboutPage)与意见反馈页(EmailFeedbackPage)成了产品「最后一公里」的关键触点。
本文将从源码出发,深入讲解:
- EmailFeedbackPage 的反馈类型选择 + 文本输入 + 邮箱留档 + 提交校验
- AboutPage 的品牌头部 + 版本信息列表 + 版权尾部
- 表单校验的
enabled联动 - 用户协议、隐私政策的「内部链接」跳转
- 两个页面的视觉一致性原则
一个好的「关于页」,应该让用户感受到「这是有人在认真做的产品」,而不是冷冰冰的版权声明。
一、EmailFeedbackPage:四段式表单
意见反馈页采用经典的「类型选择 + 文本输入 + 邮箱留档 + 提交」结构。
@Entry@Componentstruct EmailFeedbackPage{@StatefeedbackType:number=0@StatefeedbackText:string=''@Stateemail:string=''build(){Column(){// 1. 导航栏this.NavBarBuilder('意见反馈')// 2. 表单主体Scroll(){Column({space:16}){this.TypeSelectorBuilder()// 反馈类型this.ContentInputBuilder()// 问题描述this.EmailInputBuilder()// 联系邮箱this.SubmitButtonBuilder()// 提交按钮}.padding({left:16,right:16,top:16,bottom:40})}.layoutWeight(1).scrollBar(BarState.Off)}.height('100%').backgroundColor(COLOR_BG)}}1.1 页面结构图
┌────────────────────────────┐ │ ‹ 意见反馈 │ ← 导航栏 ├────────────────────────────┤ │ 反馈类型 │ │ [功能建议][问题反馈]… │ ← 类型选择 │ │ │ 问题描述 │ │ ┌────────────────────────┐│ │ │ TextArea 多行输入 ││ ← 文本输入 │ │ ││ │ └────────────────────────┘│ │ │ │ 联系邮箱(选填) │ │ ┌────────────────────────┐│ │ │ Email 输入框 ││ ← 邮箱留档 │ └────────────────────────┘│ │ │ │ ┌────────────────────────┐│ │ │ 提交反馈 ││ ← 提交按钮 │ └────────────────────────┘│ └────────────────────────────┘二、反馈类型选择:胶囊按钮组
@BuilderTypeSelectorBuilder(){Column(){Text('反馈类型').fontSize(12).fontColor(COLOR_TEXT_HINT)Row({space:8}){ForEach(['功能建议','问题反馈','体验问题','其他'],(label,i)=>{Text(label).fontSize(13).fontColor(this.feedbackType===i?COLOR_WHITE:COLOR_TEXT_MAIN).backgroundColor(this.feedbackType===i?COLOR_PRIMARY:COLOR_BUTTON_INACTIVE_BG).borderRadius(14).padding({left:12,right:12,top:5,bottom:5}).onClick(()=>{this.feedbackType=i})})}.margin({top:8})}.alignItems(HorizontalAlign.Start).width('100%')}2.1 视觉对比
| 状态 | 背景色 | 字色 |
|---|---|---|
| 选中 | COLOR_PRIMARY(琥珀) | 白色 |
| 未选 | COLOR_BUTTON_INACTIVE_BG(浅灰) | 主文本色 |
胶囊形borderRadius(14)与按钮高度(约 28vp)形成半圆,符合 iOS 胶囊按钮规范。
2.2 为什么不用单选 radio?
- 空间占用:radio + label 横向排列,4 个选项需要 2 行
- 可读性:胶囊按钮的文字更醒目
- 触控友好:胶囊按钮的点击区域更大
三、问题描述:TextArea 多行输入
@BuilderContentInputBuilder(){Column(){Text('问题描述').fontSize(12).fontColor(COLOR_TEXT_HINT)TextArea({placeholder:'请详细描述您遇到的问题',text:this.feedbackText}).constraintSize({minHeight:140}).backgroundColor(COLOR_CARD_BG).borderRadius(CARD_RADIUS).padding(12).onChange((v)=>this.feedbackText=v).margin({top:8})}.alignItems(HorizontalAlign.Start).width('100%')}3.1 关键属性
| 属性 | 值 | 作用 |
|---|---|---|
constraintSize.minHeight | 140vp | 输入框最少高度,避免一开始只剩一行 |
placeholder | 提示文字 | 输入为空时显示 |
backgroundColor | 卡片色 | 与页面背景形成层次 |
3.2 字符校验
提交按钮的enabled状态会根据feedbackText的长度变化:
this.feedbackText.trim().length>10- 少于 10 字:按钮禁用,避免无意义提交
- 多于 500 字:可选截断或提示「请精简描述」
四、联系邮箱:InputType.Email
@BuilderEmailInputBuilder(){Column(){Text('联系邮箱(选填)').fontSize(12).fontColor(COLOR_TEXT_HINT)TextInput({placeholder:'方便我们回复您',text:this.email}).type(InputType.Email).backgroundColor(COLOR_CARD_BG).borderRadius(INPUT_RADIUS).padding(12).onChange((v)=>this.email=v).margin({top:8})}.alignItems(HorizontalAlign.Start).width('100%')}4.1InputType.Email的作用
- 移动端键盘自动显示
@和.快捷键 - 部分输入法会校验邮箱格式
4.2 邮箱格式校验(可选)
constemailRegex=/^[\w.-]+@[\w.-]+\.\w+$/if(!emailRegex.test(this.email)){promptAction.showToast({message:'邮箱格式不正确'})return}五、提交按钮:条件启用 + 视觉反馈
@BuilderSubmitButtonBuilder(){Button('提交反馈').width('90%').height(50).fontSize(16).fontColor(COLOR_WHITE).fontWeight(FontWeight.Bold).backgroundColor(this.feedbackText.trim().length>10?COLOR_PRIMARY:COLOR_BUTTON_DISABLED_BG).borderRadius(BTN_RADIUS_FULL).enabled(this.feedbackText.trim().length>10).onClick(()=>this.submitFeedback())}5.1 三层校验
submitFeedback(){// 1. 必填校验if(this.feedbackText.trim().length<=10){promptAction.showToast({message:'请至少输入 10 个字符'})return}// 2. 邮箱格式校验(如果填了)if(this.email&&!/^[\w.-]+@[\w.-]+\.\w+$/.test(this.email)){promptAction.showToast({message:'邮箱格式不正确'})return}// 3. 提交(伪代码)feedbackService.submit({type:this.feedbackType,content:this.feedbackText,email:this.email}).then(()=>{promptAction.showToast({message:'反馈已提交,感谢支持!'})router.back()})}六、AboutPage:三段式品牌展示
关于页采用「品牌头部 + 信息列表 + 版权尾部」三段式结构。
@Entry@Componentstruct AboutPage{build(){Column(){this.NavBarBuilder('关于海风')Scroll(){Column({space:24}){this.BrandHeaderBuilder()// 1. 品牌 Logothis.InfoListBuilder()// 2. 信息列表this.CopyrightFooterBuilder()// 3. 版权信息}.padding({left:16,right:16,top:32,bottom:40})}.layoutWeight(1).scrollBar(BarState.Off)}.height('100%').backgroundColor(COLOR_BG)}}七、品牌头部:Logo + 名称 + 版本 + Slogan
@BuilderBrandHeaderBuilder(){Column({space:12}){Stack(){Circle().width(80).height(80).fill(COLOR_AVATAR_BG)Text('🌊').fontSize(38)}Text('海风日记').fontSize(22).fontColor(COLOR_TEXT_MAIN).fontWeight(FontWeight.Bold)Text('Version 1.0.0').fontSize(13).fontColor(COLOR_TEXT_HINT)Text('让每一天随海风飘散').fontSize(14).fontColor(COLOR_TEXT_SECONDARY)}}7.1 Logo 设计
- 80vp 圆形底色
COLOR_AVATAR_BG - 上层叠加 🌊 emoji,简单直观
- 相比于绘制 SVG,emoji 跨平台一致性更好
7.2 版本号格式
Version 1.0.0遵循语义化版本(SemVer):
1—— 主版本(不兼容更新)0—— 次版本(新增功能,向后兼容)0—— 修订号(bug 修复)
八、信息列表:ForEach 动态渲染
@BuilderInfoListBuilder(){Column(){ForEach([{label:'版本号',value:'1.0.0'},{label:'开发商',value:'海风科技'},{label:'更新日期',value:'2025年1月'},{label:'用户协议',value:'查看 ›'},{label:'隐私政策',value:'查看 ›'}],(item)=>{Row(){Text(item.label).fontSize(14).fontColor(COLOR_TEXT_MAIN).layoutWeight(1)Text(item.value).fontSize(14).fontColor(item.value.includes('›')?COLOR_AMBER:COLOR_TEXT_SECONDARY)}.height(50).padding({left:PAGE_PADDING,right:PAGE_PADDING})Divider().color(COLOR_DIVIDER).margin({left:PAGE_PADDING})})}.backgroundColor(COLOR_CARD_BG).borderRadius(CARD_RADIUS)}8.1 列表项高度统一
每项固定height(50),确保用户在快速浏览时视线流动稳定。
8.2 「查看 ›」的视觉提示
「用户协议」「隐私政策」这两项是可点击的内部链接,用COLOR_AMBER(琥珀色)标识,并附加›箭头符号提示「可跳转」。
.onClick(()=>{if(item.label==='用户协议')router.pushUrl({url:'pages/UserAgreementPage'})if(item.label==='隐私政策')router.pushUrl({url:'pages/PrivacyPolicyPage'})})九、版权尾部:Slogan + Copyright
@BuilderCopyrightFooterBuilder(){Column({space:6}){Text('🌊 用文字守护每一天的珍贵').fontSize(13).fontColor(COLOR_AMBER)Text('© 2025 海风科技').fontSize(11).fontColor(COLOR_TEXT_HINT)}}9.1 版权符号©
Unicode 编码U+00A9,在 HTML 中也可以用©表示。
9.2 Slogan 的情感价值
「用文字守护每一天的珍贵」比「让记录更简单」更有温度。这种情感化文案是品牌差异化的关键。
十、视觉一致性原则
两个页面虽然功能不同,但都遵循统一的设计规范:
| 设计要素 | 取值 | 作用 |
|---|---|---|
| 页面背景 | COLOR_BG | 浅米色,温暖 |
| 卡片背景 | COLOR_CARD_BG | 比页面背景略白 |
| 主色 | COLOR_PRIMARY/COLOR_AMBER | 品牌琥珀色 |
| 标题字号 | 17vp | 标准导航栏字号 |
| 正文字号 | 14vp | 易读 |
| 圆角 | CARD_RADIUS12vp /BTN_RADIUS_FULL | 统一圆角体系 |
十一、常见问题与踩坑记录
Q1:TextArea 在 iOS 上换行触发onChange频繁?
原因:合成输入期间多次触发。
解决:用防抖setTimeout或在onSubmit时统一处理。
Q2:InputType.Email在某些输入法上不显示@?
原因:输入法兼容性问题。
解决:用InputType.Normal+ 手动校验。
Q3:版本号写死在代码里,更新时容易遗漏?
原因:硬编码。
解决:从app.json5的versionName动态读取:
importappfrom'@system.app'app.getInfo().then((info)=>{this.version=info.versionName})十二、总结
本文通过「海风日记」的意见反馈和关于页面,深入讲解了:
- EmailFeedbackPage—— 四段式表单:类型、内容、邮箱、提交
- AboutPage—— 三段式品牌展示:Logo、信息列表、版权
- 表单校验——
enabled联动 + 字符长度 + 邮箱正则 - 视觉一致性—— 统一的颜色常量、字号、圆角
- 情感化文案—— Slogan 与 Copyright 的温度
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源
- TextArea 组件文档
- TextInput 组件文档
- Scroll 组件文档
- 海风日记项目源码
- HarmonyOS 开发者官网
- 开源鸿蒙跨平台社区
