本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
onVisibleAreaChange() 是鸿蒙(HarmonyOS)ArkUI框架中一个重要的组件可见区域变化监听方法,主要用于监听组件在可视区域内的可见比例变化。
一、方法概述
作用
- 监听组件在可视区域内的可见比例变化
- 实现基于可见性的懒加载、曝光统计等场景
- 支持组件进入/离开可视区域时的回调处理
适用组件
- 所有支持事件绑定的组件均可使用
- 常用于
List、Grid、Scroll等滚动容器内的子组件
二、基本语法
onVisibleAreaChange(ratios: Array<number>, event: (isVisible: boolean, currentRatio: number) => void)
参数说明
-
ratios:阈值数组,设置需要监听的比例阈值(0.0-1.0)
- 当组件可见比例达到任一阈值时会触发回调
- 例如
[0.0, 0.5, 1.0]表示监听0%、50%、100%三个阈值点
-
event:回调函数,参数包括:
isVisible:当前是否可见(boolean)currentRatio:当前可见比例(0.0-1.0)
三、核心功能解析
1. 基础使用示例
@Component
struct VisibleExample {
build() {
Column() {
Text('滚动观察我')
.onVisibleAreaChange([0.5], (isVisible: boolean, ratio: number) => {
console.log(`当前可见状态: ${isVisible}, 可见比例: ${ratio}`)
})
}
.height(500)
.width('100%')
}
}
2. 多阈值监听示例
@Component
struct MultiThresholdExample {
build() {
List() {
ForEach(this.data, (item) => {
ListItem() {
Text(item)
.onVisibleAreaChange(
[0.2, 0.5, 0.8],
(isVisible, ratio) => {
console.log(`Item ${item} 可见比例: ${ratio}`)
}
)
}
})
}
}
}
四、实际应用场景
1. 列表项曝光统计
@Component
struct NewsList {
@State newsItems: NewsItem[] = [...]
build() {
List() {
ForEach(this.newsItems, (item) => {
ListItem() {
NewsCard({ data: item })
.onVisibleAreaChange([0.5], (isVisible) => {
if (isVisible) {
this.reportExposure(item.id) // 曝光统计
}
})
}
})
}
}
private reportExposure(id: string) {
// 实现曝光上报逻辑
}
}
2. 图片懒加载
@Component
struct LazyImage {
@State isLoaded: boolean = false
private src: string = 'https://example.com/image.jpg'
build() {
Image(this.isLoaded ? this.src : 'placeholder.png')
.onVisibleAreaChange([0.3], (isVisible) => {
if (isVisible && !this.isLoaded) {
this.isLoaded = true // 触发图片加载
}
})
}
}
3. 滚动动画触发
@Component
struct AnimatedComponent {
@State translateY: number = 100
@State opacity: number = 0
build() {
Column() {
Text('滚动到此处执行动画')
.translate({ y: this.translateY })
.opacity(this.opacity)
.onVisibleAreaChange([0.5], (isVisible) => {
if (isVisible) {
animateTo({ duration: 500 }, () => {
this.translateY = 0
this.opacity = 1
})
}
})
}
}
}
五、优化建议
-
性能优化:
- 避免在回调中执行耗时操作
- 对于大量列表项,考虑防抖处理
-
阈值选择:
- 根据实际需求选择合适的阈值
- 一般建议使用0.5作为默认阈值
-
多次触发问题:
- 同一组件可能多次触发回调
- 需要添加状态判断避免重复处理
-
组件卸载:
- 组件卸载后会自动取消监听
- 无需手动移除监听器
-
与滚动事件的配合:
- 可与
onScroll事件配合使用 - 但不要替代基本的滚动事件处理
- 可与
六、完整示例(列表项曝光统计)
@Entry
@Component
struct VisibleAreaDemo {
@State data: string[] = Array(20).fill('').map((_, i) => `项目 ${i + 1}`)
@State exposedItems: Set<number> = new Set()
build() {
List({ space: 20 }) {
ForEach(this.data, (item, index) => {
ListItem() {
Text(item)
.fontSize(20)
.padding(20)
.backgroundColor(this.exposedItems.has(index) ? '#E1F5FE' : '#FFFFFF')
.onVisibleAreaChange([0.5], (isVisible) => {
if (isVisible && !this.exposedItems.has(index)) {
this.exposedItems.add(index)
console.log(`[曝光] ${item}`)
}
})
}
.borderRadius(12)
.border({ width: 1, color: '#E0E0E0' })
})
}
.padding(10)
.onScroll((scrollOffset: number) => {
console.log(`当前滚动位置: ${scrollOffset}`)
})
}
}
1321

被折叠的 条评论
为什么被折叠?



