
文章目录前言先把这页在干什么看明白状态字段不多但分工要清楚哪几个函数最值得先看第一段关键代码页面是怎么被带起来的第二段关键代码真正决定交互手感的地方把页面跑起来之后建议你这样操作一遍如果我把它迁进正式项目这个案例为什么值得留一份完整代码收个尾前言光有字母高亮还不够用户在快速滑动索引条时还需要一个更明显的反馈。这个案例里的弹出提示就是典型的“看起来小体验上很关键”的设计点。 我自己看这类案例时通常不会先背属性而是先判断它到底在解决什么页面问题。这个习惯很有用因为一旦知道“它是给谁用、解决什么场景”后面的代码就不容易看散。字母索引弹窗提示页 这一页真正有意思的地方不是把效果堆出来而是它把 索引触控反馈与提示浮层展示 这件事说得比较落地。这篇我会按“先看到什么、再点什么、最后哪里变化”的顺序去讲适合第一次复刻这个案例时照着走。这类写法尤其适合落在 通讯录、字典检索、品牌导航与大数据列表 这些场景里所以我下面不会只讲“组件怎么写”而是更关心“放进页面之后为什么这样组织”。先把这页在干什么看明白如果你已经打开运行效果会更容易理解这一段。因为这页并不是靠某一个孤立控件撑起来的而是几个区域互相配合才成立。页面区域主要职责在代码里的典型表现头部说明区交代当前案例在演示什么Text标题、补充说明、标签文案核心展示区承载组件能力的主要效果Column、Row、业务组件本体辅助信息区补充状态、标签、分组或统计信息次级文本、角标、分组标题、描述块交互入口区负责切换、返回、定位、选择等动作点击事件、按钮、索引条、导航入口这一页没有额外拆出接口页面更多是直接围绕基础数据和组件参数展开。这篇我会按“先看到什么、再点什么、最后哪里变化”的顺序去讲适合第一次复刻这个案例时照着走。状态字段不多但分工要清楚弹窗提示页的状态要分成两层看一层是索引本身一层是提示浮层。isShow控制示例区域显示。selected记录当前选中字母让索引条高亮有依据。popupText决定浮层里展示哪个字母。showPopup决定自定义提示是否出现。usingPopup(true)可以打开系统级提示但如果想做更强的视觉反馈就需要自己维护popupText和showPopup。这两个状态让页面能在“用户正在滑动索引”的瞬间给出更醒目的反馈。哪几个函数最值得先看如果你想更快进入状态可以把这些方法当成页面的控制台。哪个方法被触发页面就往哪个方向走。这个案例没有太多额外方法核心价值主要集中在页面结构和组件组合方式。我自己读这类方法时通常只抓一条线谁触发、谁被改、页面哪里立刻有反馈。把这三件事连起来很多交互代码一下就顺了。第一段关键代码页面是怎么被带起来的这一段建议慢一点看。它通常决定了页面初始状态也决定了后续哪些区域会跟着刷新。StateisShow:booleantrueStateselected:number0StatepopupText:stringAStateshowPopup:booleanfalsebuild(){Column(){if(this.isShow){Column({space:16}){Text(弹出提示效果).fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text(使用 usingPopup 开启字母弹窗选中时显示大号提示).fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width(100%)Column({space:14}){// 开启弹窗Column({space:8}){Text(开启弹窗 (usingPopup: true)).fontSize(14)这一段我通常不会一下翻过去而是先确认下面这几个判断点State字段到底在控制显示、选择、跳转结果还是模式切换。默认值是不是合理页面一打开会不会就落在一个可理解的状态上。字段命名能不能让后来的人一眼看懂用途而不是还要翻半天 UI。第二段关键代码真正决定交互手感的地方这一段完整代码适合对照两种提示方式看一种是组件属性usingPopup提供的默认弹窗另一种是页面自己用popupText和showPopup做出的自定义提示。前者省事后者更适合品牌化页面和强反馈场景。/** * 字母索引弹窗提示页 */import{PRESET_COLORS,generateListItems,DEMO_BG_COLOR,DEMO_CARD_COLOR,DEMO_THEME_COLOR,DEMO_SUBTEXT_COLOR}from./typesconstalphabetArray:string[]ABCDEFGHIJKLMNOPQRSTUVWXYZ.split()EntryComponentstruct AlphabetIndexerPopupTip{StateisShow:booleantrueStateselected:number0StatepopupText:stringAStateshowPopup:booleanfalsebuild(){Column(){if(this.isShow){Column({space:16}){Text(弹出提示效果).fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)代码读到这里我通常会顺手补三件事不然后面很容易只看热闹这个交互入口接收的到底是什么输入。输入进来之后代码改了哪个状态或者触发了哪次导航。变化发生后用户最先感知到的反馈会落在哪个区域。这三个问题串起来之后这一页基本就不只是“看过”而是真的读懂了。把页面跑起来之后建议你这样操作一遍我比较推荐用“观察 - 触发 - 对照源码”的方式学这个页面。先看到效果再回去找原因记得会更牢。先进入页面确认首屏是不是把字母索引弹窗提示页的主题交代清楚。盯住核心展示区观察默认状态下最醒目的内容是什么。主动触发一次关键交互比如点击、滑动、跳转、返回、切换或者选择。回头检查状态区、提示区、标题区或者附属信息有没有跟着变化。最后再打开源码对照刚才那次交互把状态变化链路串起来。如果这五步你能边操作边说清楚页面发生了什么后面再换成自己的数据和交互心里会稳很多。如果我把它迁进正式项目如果只把这页当 demo 看它的价值其实只发挥了一半。更值得做的是顺手想一遍放进项目之后哪里该抽哪里该换哪里该收口。字母索引类页面建议先把分组数据结构稳定下来再去调索引条样式和反馈层。一旦页面里还要加搜索、筛选或定位结果状态来源最好先分层不然后面很容易互相覆盖。只要页面里有重复块就别硬撑着手写到底早点抽成小组件后面改样式和改交互都会轻松很多。示例数据最好和布局代码分开放不然后面一接接口页面文件很容易立刻变臃肿。这个案例为什么值得留一份如果你经常做业务页会发现这种案例特别适合复用思路。它不像单纯 API 示例那样看完就过去。页面结构比较稳后续不管是换数据还是换皮肤成本都不会特别高。状态数量总体可控适合拿来练“一个页面里如何分配职责”这件事。组件参数和页面目标之间关系比较直观不太会出现“能跑但看不懂为什么这么配”的情况。完整代码下面保留整理过命名的完整 ArkTS 代码方便你直接对照学习。这里已经去掉原始的 Demo 命名改成了更贴近当前案例语义的名称。/** * 字母索引弹窗提示页 */import{PRESET_COLORS,generateListItems,DEMO_BG_COLOR,DEMO_CARD_COLOR,DEMO_THEME_COLOR,DEMO_SUBTEXT_COLOR}from./typesconstalphabetArray:string[]ABCDEFGHIJKLMNOPQRSTUVWXYZ.split()EntryComponentstruct AlphabetIndexerPopupTip{StateisShow:booleantrueStateselected:number0StatepopupText:stringAStateshowPopup:booleanfalsebuild(){Column(){if(this.isShow){Column({space:16}){Text(弹出提示效果).fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text(使用 usingPopup 开启字母弹窗选中时显示大号提示).fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width(100%)Column({space:14}){// 开启弹窗Column({space:8}){Text(开启弹窗 (usingPopup: true)).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333).width(100%)Row(){Column({space:6}){Text(当前选中).fontSize(12).fontColor(DEMO_SUBTEXT_COLOR)Text(this.popupText).fontSize(48).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)}.layoutWeight(1).alignItems(HorizontalAlign.Center)AlphabetIndexer({arrayValue:alphabetArray,selected:this.selected}).selectedColor(DEMO_THEME_COLOR).popupColor(#FFFFFF).popupBackground(DEMO_THEME_COLOR).popupSelectedColor(#FFFFFF).usingPopup(true).color(#666666).selectedBackgroundColor(#E8EAF6).itemSize(16).onSelect((index:number){this.selectedindexthis.popupTextalphabetArray[index]this.showPopuptrue})}.width(100%).height(160).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)}.width(100%)// 关闭弹窗Column({space:8}){Text(关闭弹窗 (usingPopup: false)).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333).width(100%)Row(){Text(仅高亮选中字母不显示弹窗提示).fontSize(14).fontColor(DEMO_SUBTEXT_COLOR).layoutWeight(1).textAlign(TextAlign.Center)AlphabetIndexer({arrayValue:alphabetArray.slice(0,10),selected:2}).selectedColor(PRESET_COLORS[0].value).usingPopup(false).itemSize(14).selectedBackgroundColor(#E8F5E9)}.width(100%).height(80).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)}.width(100%)// 自定义弹窗样式说明Row({space:6}){Text(提示).fontSize(11).fontWeight(FontWeight.Bold).fontColor(#FF6B35)Text(popupColor 设置弹窗文字颜色popupBackground 设置弹窗背景色).fontSize(11).fontColor(DEMO_SUBTEXT_COLOR).layoutWeight(1)}.width(100%).padding(10).backgroundColor(#FFF8E1).borderRadius(8)}.width(100%).padding(16).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)}.alignItems(HorizontalAlign.Start)}Text(字母索引弹窗提示页 - AlphabetIndexer 弹出提示).fontSize(12).fontColor(#999999).margin({top:12})}.width(100%).height(100%).backgroundColor(DEMO_BG_COLOR).padding(16)}}收个尾字母索引弹窗提示页 这一页我建议你至少亲手改一次。哪怕只是换一组数据、调一个布局、补一个状态字段你都会比只看文章更快进入自己的节奏。