HarmonyOS7 多行文本输入页实战:TextArea 不只是会用,还要用得顺手
文章目录评论输入最怕边界没处理addReview 负责把输入变成列表数据页面怎么搭起来这里有个小经验完整代码写在最后TextArea看起来只是一个多行输入框但真放进业务里马上就会遇到几个细节空内容能不能提交、最多允许多少字、聚焦时边框要不要变化、保存后要不要给反馈。这个页面把TextArea放进两个常见场景评论输入和笔记编辑。一个偏短内容提交一个偏长内容保存刚好能看出多行输入在不同业务里的处理方式。评论输入最怕边界没处理评论框里有reviewContent、charCount、maxChars、isFocused几个状态。reviewContent存输入内容charCount做字数展示maxChars限制最大长度isFocused控制边框高亮。这些状态看起来琐碎但少一个体验就会断。比如不限制长度用户可能输入超长内容不处理空字符串就会出现空评论提交后不清空输入框用户会以为没成功。addReview 负责把输入变成列表数据addReview()不是简单把字符串塞进数组。它先用trim()挡掉空内容再组装成一个完整的ReviewItem_nku3最后把新评论放到列表最前面并清空输入内容和字数。这个顺序很重要先校验再生成数据再更新列表最后重置输入状态。关键代码如下addReview(){if(this.reviewContent.trim().length0)returnconstnewReview:ReviewItem_nku3{id:Date.now(),author:我,avatar:我,content:this.reviewContent,time:刚刚,likes:0}this.reviews[newReview].concat(this.reviews)this.reviewContentthis.charCount0}这类函数建议保持短小输入和输出都清楚。后面如果要接接口、接本地数据库改动点也会集中一些。页面怎么搭起来MultilineInputPage仍然是一个标准的EntryComponent页面。外层一般用Column承接整页再把可滚动内容放进Scroll里面根据业务模块继续拆Row、Column、ForEach。我建议你照着代码看的时候先找这些标题一、评论输入框字数限制、二、笔记编辑器。它们基本就是页面的骨架。骨架看懂了再看每个模块里的事件回调理解成本会低很多。这里有个小经验多行输入要同时考虑字数限制、空内容和保存反馈体验才完整。完整代码下面是整理后的完整代码入口组件名已经换成和当前场景匹配的名字放进自己的页面目录后可以按项目路由规则接入。// TextArea 多行文本输入interfaceReviewItem_nku3{id:numberauthor:stringavatar:stringcontent:stringtime:stringlikes:number}EntryComponentstruct MultilineInputPage{StatereviewContent:stringStatecharCount:number0StatemaxChars:number300StateisFocused:booleanfalseStatereviews:ReviewItem_nku3[][{id:1,author:李华,avatar:L,content:这个 HarmonyOS 组件库真的很实用极大提升了我的开发效率感谢分享,time:5分钟前,likes:12},{id:2,author:王芳,avatar:W,content:ArkUI 的布局系统非常灵活Column/Row/Flex 组合使用效果很好。,time:1小时前,likes:8},{id:3,author:张明,avatar:Z,content:代码规范写得很清晰变量命名和注释都很到位适合学习参考。,time:昨天,likes:24},]StatenoteTitle:stringStatenoteBody:stringStatenoteSaved:booleanfalseaddReview(){if(this.reviewContent.trim().length0)returnconstnewReview:ReviewItem_nku3{id:Date.now(),author:我,avatar:我,content:this.reviewContent,time:刚刚,likes:0}this.reviews[newReview].concat(this.reviews)this.reviewContentthis.charCount0}saveNote(){if(this.noteBody.trim().length0)returnthis.noteSavedtruesetTimeout((){this.noteSavedfalse},2000)}build(){Scroll(){Column({space:0}){// 标题Text(TextArea 多行文本输入).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#111827).width(100%).padding({left:20,right:20,top:20,bottom:4})Text(评论区、笔记编辑等多行输入场景).fontSize(13).fontColor(#6B7280).width(100%).padding({left:20,right:20,bottom:16})// 一、评论输入框Column({space:12}){Text(一、评论输入框字数限制).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#374151).width(100%)Column({space:8}){// 输入区Column(){TextArea({placeholder:说说你的想法...,text:this.reviewContent}).placeholderColor(#9CA3AF).placeholderFont({size:14}).fontSize(14).fontColor(#1F2937).backgroundColor(Color.Transparent).width(100%).height(100).padding({left:12,right:12,top:10,bottom:10}).onChange((val:string){if(val.lengththis.maxChars){this.reviewContentvalthis.charCountval.length}else{this.reviewContentval.substring(0,this.maxChars)this.charCountthis.maxChars}}).onFocus((){this.isFocusedtrue}).onBlur((){this.isFocusedfalse})}.width(100%).borderWidth(1.5).borderColor(this.isFocused?#2563EB:#E5E7EB).borderRadius(10).backgroundColor(#FFFFFF)// 底部操作栏Row(){Text(${this.charCount}/${this.maxChars}).fontSize(12).fontColor(this.charCountthis.maxChars?#EF4444:#9CA3AF)Blank()Button(发表评论).fontSize(13).fontColor(Color.White).backgroundColor(this.reviewContent.length0?#2563EB:#9CA3AF).borderRadius(20).padding({left:16,right:16,top:8,bottom:8}).onClick(()this.addReview())}.width(100%).alignItems(VerticalAlign.Center)}// 评论列表Column({space:0}){ForEach(this.reviews,(review:ReviewItem_nku3){Row({space:10}){Text(review.avatar.substring(0,1)).fontSize(16).fontWeight(FontWeight.Bold).width(38).height(38).textAlign(TextAlign.Center).fontColor(Color.White).backgroundColor(#2563EB).borderRadius(19)Column({space:4}){Row(){Text(review.author).fontSize(13).fontWeight(FontWeight.Bold).fontColor(#111827)Blank()Text(review.time).fontSize(11).fontColor(#9CA3AF)}.width(100%)Text(review.content).fontSize(13).fontColor(#374151).lineHeight(20)Row(){Text( review.likes.toString()).fontSize(12).fontColor(#6B7280)}}.layoutWeight(1).alignItems(HorizontalAlign.Start)}.width(100%).padding({top:12,bottom:12}).alignItems(VerticalAlign.Top)Divider().color(#F3F4F6).strokeWidth(1)},(review:ReviewItem_nku3)review.id.toString())}.width(100%).backgroundColor(#F9FAFB).borderRadius(10).padding({left:12,right:12})}.width(100%).padding({left:20,right:20}).alignItems(HorizontalAlign.Start).margin({bottom:16})// 二、笔记编辑器Column({space:10}){Text(二、笔记编辑器).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#374151).width(100%)Column({space:0}){// 标题输入TextInput({placeholder:笔记标题,text:this.noteTitle}).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#111827).placeholderColor(#D1D5DB).backgroundColor(Color.Transparent).borderRadius(0).borderWidth({bottom:1}).borderColor(#E5E7EB).padding({left:16,right:16,top:14,bottom:14}).onChange((val:string){this.noteTitleval})// 正文输入TextArea({placeholder:开始记录你的想法...,text:this.noteBody}).placeholderColor(#9CA3AF).fontSize(15).fontColor(#374151).lineHeight(24).backgroundColor(Color.Transparent).width(100%).height(160).padding({left:16,right:16,top:12,bottom:12}).onChange((val:string){this.noteBodyvalthis.noteSavedfalse})// 工具栏Row({space:16}){Text(B).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#6B7280)Text(I).fontSize(16).fontStyle(FontStyle.Italic).fontColor(#6B7280)Text(U).fontSize(16).fontColor(#6B7280).decoration({type:TextDecorationType.Underline,color:#6B7280})Blank()Text(this.noteBody.length.toString() 字).fontSize(12).fontColor(#9CA3AF)Button(this.noteSaved?✓ 已保存:保存).fontSize(13).fontColor(this.noteSaved?#059669:Color.White).backgroundColor(this.noteSaved?#D1FAE5:#2563EB).borderRadius(16).padding({left:14,right:14,top:6,bottom:6}).onClick(()this.saveNote())}.width(100%).padding({left:12,right:12,top:8,bottom:10}).backgroundColor(#F9FAFB).borderRadius({bottomLeft:10,bottomRight:10})}.width(100%).borderWidth(1).borderColor(#E5E7EB).borderRadius(10).backgroundColor(#FFFFFF).shadow({radius:4,color:rgba(0,0,0,0.04),offsetY:2})}.width(100%).padding({left:20,right:20}).alignItems(HorizontalAlign.Start).margin({bottom:24})}}.width(100%).height(100%).backgroundColor(#FFFFFF)}}写在最后多行文本输入页 这个案例的价值不在于用了多少组件而在于它把TextArea放进了一个完整页面里。照着这个思路改自己的业务比单独背 API 更靠谱。