demo 通讯录 + 城市选择器 (字母索引左右联动 ListItemGroup+AlphabetIndexer)笔记

一、城市选择器实现笔记

1. 双层 for 循环渲染

数据结构

interface BKCityContent {initial: string; // 字母索引cityNameList: string[]; // 城市列表
}

核心实现

// 外层循环:字母分组 - 遍历城市数据,按字母分组显示
ForEach(this.cityContentList, (item: BKCityContent, index: number) => {// ListItemGroup:创建分组容器,header显示字母标题ListItemGroup({ header: this.ListItemGroupHeaderBuilder(item.initial) }) {// 内层循环:城市列表 - 遍历每个分组下的城市名称ForEach(item.cityNameList, (ele: string, index: number) => {ListItem() {Text(ele)  // 显示城市名称.width('100%').padding({ left: 20 })}.width('100%').height(50)  // 统一高度,保持列表整齐.backgroundColor(Color.White)})}
})

要点

  • 外层遍历字母分组,内层遍历城市
  • ListItemGroup 实现分组效果

2. 模态框左右联动

状态变量

@State isShow: boolean = false    // 模态框显示
@State selected: number = 0       // 选中索引
scroller: Scroller = new Scroller() // 滚动器

联动代码

// 模态框结构 - 使用Stack布局,右侧放置索引器
@Builder
ContentCoverBuilder() {Stack({ alignContent: Alignment.End }) {  // 内容右对齐,为索引器留出空间Column() {this.TopBuilder()    // 顶部搜索栏this.ListBuilder()   // 城市列表}.backgroundColor(Color.White)// 右侧索引器 - 提供快速定位功能AlphabetIndexer({arrayValue: this.alphabets, selected: this.selected}).usingPopup(true)  // 启用弹出提示,显示当前选中的字母.onSelect((index) => {this.scroller.scrollToIndex(index, true)  // 点击索引时滚动到对应位置})}
}// 列表滚动监听 - 实现双向联动
List({scroller: this.scroller}) {  // 绑定滚动控制器// 列表内容
}
.onScrollIndex((index) => {this.selected = index  // 手动滚动时同步更新索引器的选中状态
})

联动机制

  • 点击索引 → onSelectscrollToIndex() 滚动
  • 手动滚动 → onScrollIndex → 更新 selected

3. 关键组件

AlphabetIndexer

// 字母索引器 - 右侧快速定位组件
AlphabetIndexer({arrayValue: this.alphabets, // 索引数组:['#', '热', "A", "B", "C"...]selected: this.selected, // 当前选中的索引位置
}).usingPopup(true) // 启用弹出提示,显示当前选中的字母.onSelect((index) => {this.scroller.scrollToIndex(index, true); // 点击时滚动到对应位置});

ListItemGroup

// 列表分组组件 - 按字母对城市进行分组显示
ListItemGroup({header: this.ListItemGroupHeaderBuilder(item.initial) // 自定义分组头部,显示字母
}) {// 分组内容 - 该字母下的所有城市
}
.padding({ bottom: 20 })  // 分组底部间距
.divider({ startMargin: 20, endMargin: 20, color: '#f3f3f3', strokeWidth: 2 }) // 分组间分割线

4. 数据组织

城市数据

cityContentList: BKCityContent[] = [{ initial: 'A', cityNameList: ['阿拉善', '鞍山', '安庆'] },{ initial: 'B', cityNameList: ['北京', '保定', '包头'] },// ...
]

索引数组

alphabets: string[] = ['#', '热', "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y", "Z"]

5. 交互流程

  1. 打开模态框:this.isShow = true
  2. 点击索引:onSelectscrollToIndex(index)
  3. 滚动列表:onScrollIndexthis.selected = index
  4. 关闭模态框:this.isShow = false

6. 关键代码

模态框绑定

// 背景图片绑定模态框 - 点击图片显示城市选择器
Image($r("app.media.ic_BK_content")).bindContentCover($$this.isShow, this.ContentCoverBuilder()) // 绑定模态框内容.onClick(() => {this.isShow = true; // 点击时显示模态框});

分组头部

// 自定义分组头部构建器 - 显示字母标题
@Builder
ListItemGroupHeaderBuilder(title: string) {Text(title)  // 显示字母(如:A、B、C...).padding({ left: 20, bottom: 15, top: 20 })  // 内边距.fontSize(14)  // 字体大小.fontColor(Color.Gray)  // 灰色字体.backgroundColor('#f8f8f8')  // 浅灰色背景.width('100%')  // 占满宽度
}

总结

  1. 双层循环:外层分组 + 内层列表
  2. 左右联动:索引器 + 滚动器双向同步
  3. 状态管理@State 控制显示,Scroller 控制滚动
  4. 数据驱动:接口规范数据结构

城市选择全部代码:

interface BKCityContent {initial: stringcityNameList: string[]
}@Entry
@Component
struct Page10_Demo_BK {// 热门城市hotCitys: string[] = ['北京', '上海', '广州', '深圳', '天津', '杭州', '南京', '苏州', '成都', '武汉', '重庆', '西安', '香港', '澳门', '台北']// 历史城市historyCitys: string[] = ['北京', '上海', '广州', '深圳', '重庆']// 城市信息cityContentList: BKCityContent[] = [{initial: 'A',cityNameList: ['阿拉善', '鞍山', '安庆', '安阳', '阿坝', '安顺']},{initial: 'B',cityNameList: ['北京', '保定', '包头', '巴彦淖尔', '本溪', '白山']},{initial: 'C',cityNameList: ['成都', '重庆', '长春', '长沙', '承德', '沧州']},{initial: 'D',cityNameList: ['大连', '东莞', '大同', '丹东', '大庆', '大兴安岭']},{initial: 'E',cityNameList: ['鄂尔多斯', '鄂州', '恩施', '额尔古纳市', '二连浩特市', '恩施市']},{initial: 'F',cityNameList: ['福州', '佛山', '抚顺', '阜新', '阜阳', '抚州']},{initial: 'G',cityNameList: ['广州', '贵阳', '赣州', '桂林', '贵港', '广元']},{initial: 'H',cityNameList: ['杭州', '海口', '哈尔滨', '合肥', '呼和浩特', '邯郸']},{initial: 'J',cityNameList: ['济南', '晋城', '晋中', '锦州', '吉林', '鸡西']},{initial: 'K',cityNameList: ['昆明', '开封', '康定市', '昆山', '康保县', '宽城满族自治县']},{initial: 'L',cityNameList: ['兰州', '廊坊', '临汾', '吕梁', '辽阳', '辽源']},{initial: 'M',cityNameList: ['牡丹江', '马鞍山', '茂名', '梅州', '绵阳', '眉山']},{initial: 'N',cityNameList: ['南京', '宁波', '南昌', '南宁', '南通', '南平']},{initial: 'P',cityNameList: ['盘锦', '莆田', '萍乡', '平顶山', '濮阳', '攀枝花']},{initial: 'Q',cityNameList: ['青岛', '秦皇岛', '齐齐哈尔', '七台河', '衢州', '泉州']},{initial: 'R',cityNameList: ['日照', '日喀则', '饶阳县', '任丘市', '任泽区', '饶河县']},{initial: 'S',cityNameList: ['上海', '苏州', '深圳', '沈阳', '石家庄', '朔州']},{initial: 'T',cityNameList: ['天津', '太原', '唐山', '通辽', '铁岭', '通化']},{initial: 'W',cityNameList: ['无锡', '武汉', '乌海', '乌兰察布', '温州', '芜湖']},{initial: 'X',cityNameList: ['厦门', '西安', '西宁', '邢台', '忻州', '兴安盟']},{initial: 'Y',cityNameList: ['扬州', '阳泉', '运城', '营口', '延边', '伊春']},{initial: 'Z',cityNameList: ['郑州', '珠海', '张家口', '镇江', '舟山', '漳州']}]// 右侧导航索引alphabets: string[] = ['#', '热', "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "W", "X", "Y", "Z"]//全模态的显示@State isShow:boolean=false//@State selected:number=0scroller:Scroller= new Scroller()build() {Column() {Image($r('app.media.ic_BK_content')).width('100%').bindContentCover($$this.isShow, this.ContentCoverBuilder()).onClick(()=>{this.isShow=true})// 全屏模态的内容}.width('100%').height('100%').backgroundColor('#f8f8f8')}@BuilderContentCoverBuilder() {Stack({ alignContent: Alignment.End }) {Column() {// 顶部this.TopBuilder();// 列表this.ListBuilder();}.backgroundColor(Color.White)AlphabetIndexer({arrayValue:this.alphabets,selected:this.selected}).usingPopup(true).onSelect((index)=>{this.scroller.scrollToIndex(index,true)})}}@BuilderListBuilder() {List({scroller:this.scroller}) {// 历史this.LocationListItemBuilder()// 热门this.HotListItemBuilder()// A-B的区域this.LetterListItemBuilder()}.divider({ startMargin: 20, endMargin: 20, color: '#f3f3f3', strokeWidth: 2 }).width('100%').layoutWeight(1).onScrollIndex((index)=>{this.selected=index})}@BuilderLetterListItemBuilder() {// A-B的区域ForEach(this.cityContentList,(item:BKCityContent,index:number)=>{ListItemGroup({ header: this.ListItemGroupHeaderBuilder(item.initial) }) {ForEach(item.cityNameList,(ele:string,index:number)=>{ListItem() {Text(ele).width('100%').padding({ left: 20 })}.width('100%').height(50).backgroundColor(Color.White)})}.padding({ bottom: 20 }).divider({ startMargin: 20, endMargin: 20, color: '#f3f3f3', strokeWidth: 2 })})}@BuilderListItemGroupHeaderBuilder(title: string) {Text(title).padding({ left: 20, bottom: 15, top: 20 }).fontSize(14).fontColor(Color.Gray).backgroundColor('#f8f8f8').width('100%')}@BuilderHotListItemBuilder() {// 热门ListItem() {Column({ space: 10 }) {Text('热门城市').alignSelf(ItemAlign.Start).fontColor(Color.Gray).fontSize(14)Flex({ wrap: FlexWrap.Wrap }) {ForEach(this.hotCitys,(item:string)=>{Text(item).height(25).backgroundColor(Color.White).width('25%').margin({ bottom: 10 })})}.padding({ left: 20, right: 20 })}.width('100%').padding({ left: 20, right: 20, bottom: 10 })}}@BuilderLocationListItemBuilder() {ListItem() {Column({ space: 15 }) {// 定位地址Row() {Text('北京')Text() {ImageSpan($r('app.media.ic_public_location_fill_blue')).width(20)Span('开启定位')}}.width('100%').padding({ top: 10, bottom: 10, right: 20, left: 20 }).justifyContent(FlexAlign.SpaceBetween).backgroundColor(Color.White)// 历史Column({ space: 10 }) {Text('历史').fontColor(Color.Gray).alignSelf(ItemAlign.Start).fontSize(14)Flex({ wrap: FlexWrap.Wrap }) {ForEach(this.historyCitys,(item:string,indedx:number)=>{Text(item).height(25).backgroundColor(Color.White).width('25%').margin({ bottom: 10 })})}.padding({ left: 20, right: 20 })}.width('100%').padding({ left: 20, right: 20 })}}.padding({ top: 20 })}@BuilderTopBuilder() {Column() {// X + 输入框Row({ space: 20 }) {Image($r('app.media.ic_public_cancel')).width(30).fillColor(Color.Gray).onClick(()=>{this.isShow=false})Row({ space: 5 }) {Image($r('app.media.ic_public_search')).width(18)Text('请输入城市名称').layoutWeight(1)}.height(50).border({ width: .5, color: Color.Gray, radius: 5 }).padding({ left: 5 }).layoutWeight(1).shadow({radius: 20,color: '#f6f6f7'})}.padding({left: 15,right: 15,top: 15})// 国内城市Column() {Text('国内城市').fontSize(15).fontWeight(800).padding(5)Row().width(20).height(2).backgroundColor('#0094ff').borderRadius(2)}}.width('100%').backgroundColor(Color.White).height(100).border({width: { bottom: 4 },color: '#f6f6f7',})}
}

效果展示:

二、通讯录字母索引左右联动笔记

1. 数据结构设计

// 定义联系人数据结构
interface ContactData {initial: string    // 首字母nameList: string[] // 该字母下的联系人列表
}// 数据组织:按字母分组存储
contacts: ContactData[] = [{ initial: 'A', nameList: ['阿猫', '阿狗', ...] },{ initial: 'B', nameList: ['白兔', '白鸽', ...] },// ... 26个字母分组
]

2. 核心变量定义

// 滚动控制器 - 控制列表滚动
scroller: Scroller = new Scroller()// 当前激活索引 - 用于左右联动
@State activeIndex: number = 0// 字母索引数组 - 提供给AlphabetIndexer使用
alphabets: string[] = ['A', 'B', 'C', ..., 'Z']

3. 随机颜色功能

getRandomColor(): ResourceColor {const r = Math.floor(Math.random() * 256);const g = Math.floor(Math.random() * 256);const b = Math.floor(Math.random() * 256);return `rgba(${r}, ${g}, ${b}, 0.5)`;
}

4. 左右联动实现流程

4.1 列表滚动 → 索引器高亮

List({ scroller: this.scroller }) {// 列表内容...
}
.onScrollIndex((index) => {this.activeIndex = index  // 关键:滚动时更新激活索引
})

实现原理

  • 用户滚动列表时,onScrollIndex回调触发
  • 更新activeIndex,触发 UI 重新渲染
  • AlphabetIndexer 通过$$this.activeIndex自动高亮对应字母

4.2 索引器点击 → 列表跳转

AlphabetIndexer({arrayValue: this.alphabets,selected: $$this.activeIndex, // 关键:双向绑定
}).onSelect((index) => {this.scroller.scrollToIndex(index); // 关键:点击时滚动到对应位置
});

实现原理

  • $$双向绑定:activeIndex变化时索引器自动更新
  • onSelect回调:点击字母时调用scrollToIndex跳转

5. 分组列表渲染流程

5.1 分组头部组件

@Builder
itemHead(text: string) {Text(text).fontSize(20).backgroundColor('#fff1f3f5').width('100%').padding(5)
}

5.2 分组列表渲染

ForEach(this.contacts, (item: ContactData, index: number) => {ListItemGroup({header: this.itemHead(item.initial),  // 设置分组头部space: 10}) {ForEach(item.nameList, (it: string, i: number) => {ListItem() {Row({ space: 10 }) {Image($r('app.media.ic_public_lianxiren')).width(40).fillColor(this.getRandomColor())  // 随机颜色Text(it)}}})}.divider({ startMargin: 60, strokeWidth: 1, color: '#ccc' })
})

渲染流程

  1. 外层遍历 26 个字母分组
  2. 每个分组用ListItemGroup包装
  3. 内层遍历该分组下的联系人
  4. 每个联系人显示头像+姓名
  5. 添加分割线

6. 弹窗功能实现

AlphabetIndexer({ arrayValue: this.alphabets, selected: $$this.activeIndex }).usingPopup(true) // 启用弹窗.selectedColor(Color.Red) // 选中字母颜色.selectedBackgroundColor(Color.Green) // 选中背景色.popupColor(Color.Red) // 弹窗文字颜色.popupBackground(Color.Brown) // 弹窗背景色.popupTitleBackground(Color.Yellow); // 弹窗标题背景色

7. 关键样式设置

List({ scroller: this.scroller }).sticky(StickyStyle.Header)  // 分组标题粘性显示.scrollBar(BarState.Off)     // 隐藏滚动条AlphabetIndexer(...).offset({ x: 0, y: -100 })   // 调整位置避免遮挡

8. 快速回到顶部

Text("通讯录").onClick(() => {this.scroller.scrollToIndex(0, true); // 滚动到第一个位置
});

9. 完整交互流程

  1. 页面加载:显示所有联系人分组
  2. 滚动列表onScrollIndexactiveIndex更新 → 索引器高亮
  3. 点击字母onSelectscrollToIndex → 列表跳转
  4. 弹窗反馈:操作时显示当前选中字母
  5. 回到顶部:点击标题 → scrollToIndex(0)

10. 关键技术点

  • 双向绑定$$this.activeIndex实现状态同步
  • 滚动控制Scroller对象精确控制滚动
  • 分组显示ListItemGroup实现分组列表
  • 粘性头部.sticky(StickyStyle.Header)提升体验
  • 随机颜色:动态生成增加视觉区分度

11. 常见问题

Q: 为什么用@State activeIndex?
A: 响应式状态,变化时 UI 自动更新,实现左右联动

Q: 如何实现平滑滚动?
A: scrollToIndex(index, true) 第二个参数 true

Q: 双向绑定怎么工作?
A: $$符号,activeIndex 变化时索引器自动更新,点击索引器时触发 onSelect

通讯录全部代码:

// 定义联系人数据结构 - 每个字母分组包含首字母和对应的联系人列表
interface ContactData {initial: string    // 首字母,如 'A', 'B', 'C'nameList: string[] // 该字母下的联系人列表
}@Entry
@Component
struct Page09_ContactAndAlpha {// 联系人数据 - 按字母A-Z分组存储,便于后续的字母索引和分组显示// 注意:这里不需要@State,因为数据不会动态变化,只是用来渲染contacts: ContactData[] = [{ initial: 'A', nameList: ['阿猫', '阿狗', '阿虎', '阿龙', '阿鹰', '阿狼', '阿豹', '阿狮', '阿象', '阿鲸'] },{ initial: 'B', nameList: ['白兔', '白鸽', '白鹤', '白鹭', '白狐', '白狼', '白虎', '白鹿', '白蛇', '白马'] },{ initial: 'C', nameList: ['春花', '春风', '春雨', '春草', '春柳', '春燕', '春莺', '春蝶', '春蓝', '春绿'] },{ initial: 'D', nameList: ['冬雪', '冬梅', '冬松', '冬竹', '冬云', '冬霜', '冬月', '冬夜', '冬青', '冬红'] },{ initial: 'E', nameList: ['饿狼', '饿虎', '饿鹰', '饿豹', '饿熊', '饿蛇', '饿鱼', '饿虾', '饿蟹', '饿蚌'] },{ initial: 'F', nameList: ['飞鸟', '飞鱼', '飞虫', '飞蜂', '飞蝶', '飞蛾', '飞蝉', '飞蝗', '飞鼠', '飞猫'] },{ initial: 'G', nameList: ['孤狼', '孤鹰', '孤虎', '孤豹', '孤蛇', '孤鲨', '孤鲸', '孤鹿', '孤雁', '孤鸿'] },{ initial: 'H', nameList: ['海鸥', '海龟', '海豚', '海星', '海马', '海葵', '海参', '海胆', '海螺', '海贝'] },{ initial: 'I', nameList: ['火焰', '火球', '火箭', '火山', '火车', '火柴', '火把', '火鸟'] },{ initial: 'J', nameList: ['金鱼', '金狮', '金刚', '金鹿', '金蛇', '金鹰', '金豹', '金虎', '金狐', '金猫'] },{ initial: 'K', nameList: ['孔雀', '恐龙', '开心', '开怀', '开朗', '开拓', '开口', '开花', '开眼', '开天'] },{ initial: 'L', nameList: ['老虎', '老鹰', '老鼠', '老狼', '老狗', '老猫', '老熊', '老鹿', '老龟', '老蛇'] },{ initial: 'M', nameList: ['玫瑰', '牡丹', '梅花', '茉莉', '木兰', '棉花', '蜜蜂', '蚂蚁', '马蜂', '蟒蛇'] },{ initial: 'N', nameList: ['南山', '南极', '南海', '南京', '南阳', '南风', '南瓜', '南竹', '南花', '南鸟'] },{initial: 'O',nameList: ['熊猫', '欧鹭', '欧洲', '欧阳', '欧文', '欧若拉', '欧米茄', '欧罗巴', '欧菲莉亚', '欧瑞斯']},{ initial: 'P', nameList: ['苹果', '葡萄', '琵琶', '枇杷', '菩提', '瓢虫', '瓢泼', '飘零', '飘渺', '飘飘然'] },{ initial: 'Q', nameList: ['七喜', '强风', '奇迹', '乾坤', '奇才', '晴天', '青竹', '秋水', '轻舞', '清泉'] },{ initial: 'R', nameList: ['瑞雪', '瑞兽', '瑞光', '瑞云', '瑞彩', '瑞气', '瑞香', '瑞草', '瑞莲', '瑞竹'] },{ initial: 'S', nameList: ['三羊', '三狗', '三猫', '三鱼', '三角', '三鹿', '三鹰', '三蛇', '三狐', '三豹'] },{ initial: 'T', nameList: ['太阳', '天空', '田园', '太极', '太湖', '天鹅', '太空', '天使', '坦克', '甜橙'] },{ initial: 'U', nameList: ['乌鸦', '乌鹊', '乌鱼', '乌龟', '乌云', '乌梅', '乌木', '乌金', '乌黑', '乌青'] },{ initial: 'V', nameList: ['五虎', '五狼', '五鹰', '五豹', '五熊', '五蛇', '五鲨', '五鲸', '五鹿', '五马'] },{ initial: 'W', nameList: ['悟空', '微笑', '温暖', '无畏', '温柔', '舞蹈', '问心', '悟道', '未来', '文学'] },{ initial: 'X', nameList: ['西风', '西洋', '西子', '西施', '西岳', '西湖', '西柚', '西竹', '西花', '西鸟'] },{ initial: 'Y', nameList: ['夜猫', '夜鹰', '夜莺', '夜空', '夜色', '夜月', '夜影', '夜翼', '夜狐', '夜狼'] },{ initial: 'Z', nameList: ['珍珠', '紫薇', '紫霞', '紫竹', '紫云', '紫燕', '紫鸢', '紫藤', '紫荆', '紫罗兰'] },]// 随机颜色生成函数 - 为每个联系人头像生成不同的背景色,增加视觉区分度getRandomColor(): ResourceColor {// 生成 0-255 的随机RGB值const r = Math.floor(Math.random() * 256);const g = Math.floor(Math.random() * 256);const b = Math.floor(Math.random() * 256);// 拼接成半透明的随机颜色并返回return `rgba(${r}, ${g}, ${b}, 0.5)`;}// 字母索引数组 - 提供给AlphabetIndexer组件使用的字母列表alphabets: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K','L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']// 滚动控制器 - 用于控制列表的滚动行为scroller: Scroller = new Scroller()// 当前激活的索引位置 - 用于字母索引器的状态同步@State activeIndex: number = 0build() {Column() {// 顶部标题栏 - 包含标题和添加按钮Stack({ alignContent: Alignment.End }) {Text('通讯录').width('100%').textAlign(TextAlign.Center).fontSize(20).onClick(() => {// 点击标题回到顶部 - 滚动到第一个位置this.scroller.scrollToIndex(0, true)})Image($r('app.media.ic_public_add')).width(20)}.width('100%').padding(15).backgroundColor('#fff1f3f5')// 搜索区域 - 模拟搜索框Row() {Row() {Image($r('app.media.ic_public_search')).width(20).fillColor(Color.Gray)Text('搜索').fontColor(Color.Gray)}.backgroundColor(Color.White).width('100%').height(40).borderRadius(5).justifyContent(FlexAlign.Center)}.padding(10).width('100%').backgroundColor('#fff1f3f5')// 主要内容区域 - 使用Stack布局,列表和字母索引器重叠Stack({ alignContent: Alignment.End }) {// 联系人列表 - 核心显示区域List({ scroller: this.scroller }) {// 遍历所有字母分组ForEach(this.contacts, (item: ContactData, index: number) => {// 每个字母分组使用ListItemGroup包装ListItemGroup({ header: this.itemHead(item.initial), // 设置分组头部space: 10 }) {// 遍历该分组下的所有联系人ForEach(item.nameList, (it: string, i: number) => {// 每个联系人的列表项ListItem() {Row({ space: 10 }) {// 联系人头像 - 使用随机颜色作为背景Image($r('app.media.ic_public_lianxiren')).width(40).fillColor(this.getRandomColor())// 联系人姓名Text(it)}}})}// 添加分割线美化界面.divider({startMargin: 60,  // 分割线左边距strokeWidth: 1,   // 分割线宽度color: '#ccc'     // 分割线颜色})})}.sticky(StickyStyle.Header)  // 分组标题粘性显示,滚动时粘在顶部.scrollBar(BarState.Off)     // 隐藏滚动条,提供更清爽的界面.onScrollIndex((index) => {// 滚动监听 - 当列表滚动时更新激活索引,实现左右联动this.activeIndex = index})// 字母索引器 - 右侧的字母快速定位工具AlphabetIndexer({ arrayValue: this.alphabets,     // 字母数组selected: $$this.activeIndex    // 双向绑定当前选中索引}).offset({ x: 0, y: -100 })      // 调整位置,避免遮挡内容.usingPopup(true)               // 启用弹窗显示.selectedColor(Color.Red)       // 选中字母的颜色.selectedBackgroundColor(Color.Green) // 选中字母的背景色.popupColor(Color.Red)          // 弹窗内文字颜色.popupBackground(Color.Brown)   // 弹窗背景色.popupTitleBackground(Color.Yellow) // 弹窗标题背景色.onSelect((index) => {// 点击字母时的回调 - 滚动到对应的分组位置this.scroller.scrollToIndex(index)})}}}// 分组头部组件构建器 - 创建每个字母分组的标题显示组件@BuilderitemHead(text: string) {Text(text).fontSize(20).backgroundColor('#fff1f3f5').width('100%').padding(5)}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95797.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95797.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【总结型】c语言中的位运算

位运算包括 & | ^ ~ << >>按位与 将某些变量中的某些位清0同时保持其他位不变。也可以用来获取变量中的某一位。 例如&#xff1a;将int型变量n低8位全置为0&#xff0c;其余位保持不变。 n n & 0xffffff00 如何判断一个int型变量n的第七位。 n & 0x8…

如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?

url: /posts/4fb9e30bb20956319c783e21897a667a/ title: 如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法? date: 2025-08-16T01:14:26+08:00 lastmod: 2025-08-16T01:14:26+08:00 author: cmdragon summary: APScheduler是Python中强大的任务调度库,支持任务持久化…

GitHub的简单使用方法----(5)

最后一篇简单讲讲git管理远程仓库 1.目的 备份&#xff0c;实现代码共享集中化管理 &#xff08;将本地仓库同步到git远程仓库中&#xff09; git clone 仓库地址 以下图为示例&#xff0c;我打开了一个别人的项目仓库&#xff0c;点击code能看到仓库地址 等待完成即可 如…

C++ STL-string类底层实现

摘要&#xff1a; 本文实现了一个简易的string类&#xff0c;主要包含以下功能&#xff1a; 1. 默认成员函数&#xff1a;构造函数&#xff08;默认/参数化&#xff09;、拷贝构造、赋值重载和析构函数&#xff0c;采用深拷贝避免内存问题&#xff1b; 2. 迭代器支持&#xff1…

【LeetCode每日一题】

每日一题3. 无重复字符的最长子串题目总体思路代码1.两数之和题目总体思路代码15. 三数之和题目总体思路代码2025.8.153. 无重复字符的最长子串 题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3…

sharding-jdbc读写分离配置

一主两从&#xff0c;爆红是正常的&#xff0c;不知为啥 spring:shardingsphere:datasource:names: ds_master,ds_s1,ds_s2ds_master:type: com.zaxxer.hikari.HikariDataSourcedriverClassName: com.mysql.jdbc.DriverjdbcUrl: jdbc:mysql://192.168.135.100:3306/gmall_produ…

【大模型核心技术】Dify 入门教程

文章目录一、Dify 是什么二、安装与部署2.1 云端 SaaS 版&#xff08;快速入门&#xff09;2.2 私有化部署&#xff08;企业级方案&#xff09;三、界面导航与核心模块3.1 控制台概览3.2 核心功能模块详解3.2.1 知识库&#xff08;RAG 引擎&#xff09;3.2.2 工作流编排3.2.3 模…

homebrew 1

文章目录brew(1) – macOS&#xff08;或 Linux&#xff09;上缺失的包管理器概要描述术语表基本命令install *formula*uninstall *formula*listsearch \[*text*|/*text*/]命令alias \[--edit] \[*alias*|*alias**command*]analytics \[*subcommand*]autoremove \[--dry-run]bu…

设计索引的原则有哪些?

MySQL 索引设计的核心原则是 在查询性能与存储成本之间取得平衡。以下是经过实践验证的 10 大设计原则及具体实现策略&#xff1a;一、基础原则原则说明示例/反例1. 高频查询优先为 WHERE、JOIN、ORDER BY、GROUP BY 频繁出现的列建索引✅ SELECT * FROM orders WHERE user_id1…

使用影刀RPA实现快递信息抓取

最近公司项目有个需求&#xff0c;要求抓取快递单号快递信息&#xff0c;比如签收地点、签收日期等。该项目对应的快递查询网站是一个国外的网站&#xff0c;他们有专门的快递平台可以用于查询。该平台提供了快递接口进行查询&#xff0c;但需要付费。同时也提供了免费的查询窗…

蚁剑--安装、使用

用途限制声明&#xff0c;本文仅用于网络安全技术研究、教育与知识分享。文中涉及的渗透测试方法与工具&#xff0c;严禁用于未经授权的网络攻击、数据窃取或任何违法活动。任何因不当使用本文内容导致的法律后果&#xff0c;作者及发布平台不承担任何责任。渗透测试涉及复杂技…

Varjo XR虚拟现实军用车辆驾驶与操作培训

Patria基于混合现实的模拟器提供了根据现代车辆乘员需求定制的培训&#xff0c;与传统显示设置相比&#xff0c;全新的模拟解决方案具有更好的沉浸感和更小的物理空间需求。Patria是芬兰领先的国防、安全和航空解决方案提供商。提供尖端技术和全面的培训系统&#xff0c;以支持…

Java 10 新特性及具体应用

目录 1. 局部变量类型推断&#xff08;JEP 286&#xff09; 2. 不可修改集合&#xff08;JEP 269&#xff09; 3. 并行全垃圾回收&#xff08;JEP 307&#xff09; 4. 应用类数据共享&#xff08;JEP 310&#xff09; 5. 线程局部管控&#xff08;JEP 312&#xff09; 总结…

【力扣 Hot100】刷题日记

D8 全排列(非回溯法) 全排列原题链接 在刷leetcode的时候&#xff0c;看到这道题目并没法使用像STL的next_permutation方法&#xff0c;感叹C便利的同时&#xff0c;又惋惜Java并没有类似的API&#xff0c;那我们只能从原理入手了&#xff0c;仿写此算法。 其实回溯法更应该…

JetPack系列教程(七):Palette——让你的APP色彩“飞”起来!

JetPack系列教程&#xff08;七&#xff09;&#xff1a;Palette——让你的APP色彩“飞”起来&#xff01; 各位开发小伙伴们&#xff0c;还在为APP的配色发愁吗&#xff1f;别担心&#xff0c;今天咱们就来聊聊JetPack家族里的“色彩魔法师”——Palette&#xff01;这个神奇的…

力扣hot100 | 矩阵 | 73. 矩阵置零、54. 螺旋矩阵、48. 旋转图像、240. 搜索二维矩阵 II

73. 矩阵置零 力扣题目链接 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]]…

ARC与eARC是什么?主要用在哪?

在家庭影音设备不断升级的今天&#xff0c;人们对音视频体验的要求越来越高。无论是追剧、玩游戏还是观看电影大片&#xff0c;很多用户不再满足于电视自带的扬声器&#xff0c;而是希望借助回音壁、功放或家庭影院系统&#xff0c;获得更加震撼的沉浸式声音体验。一、ARC是什么…

解锁JavaScript性能优化:从理论到实战

文章目录 前言 一、常见性能瓶颈剖析 二、实战案例与优化方案 (一)DOM 操作优化案例​ (二)事件绑定优化案例​ (三)循环与递归优化案例​ (四)内存管理优化案例​ 三、性能优化工具介绍 总结 前言 性能优化的重要性 在当今数字化时代,Web 应用已成为人们生活和工作…

结构化记忆、知识图谱与动态遗忘机制在医疗AI中的应用探析(上)

往期相关内容推荐: 基于Python的多元医疗知识图谱构建与应用研究(上)

XSS攻击:从原理入门到实战精通详解

一、XSS攻击基础概念1.1 什么是XSS攻击 XSS&#xff08;Cross-Site Scripting&#xff0c;跨站脚本攻击&#xff09;是一种将恶意脚本注入到可信网站中的攻击手段。当用户访问被注入恶意代码的页面时&#xff0c;浏览器会执行这些代码&#xff0c;导致&#xff1a;用户会话被劫…