如何监听Swiper滑动索引位置
================

#### 问题现象

需要在Swiper组件滑动切换后获取新的索引的场景下，如何通过监听获取Swiper组件的索引位置？

#### 背景知识

*   [onChange](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#onchange)事件可以在子组件索引变化时触发并且返回索引值，通过onChange方法即可监听当前页面的下标位置。
*   [onAnimationStart](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#onanimationstart9)回调在切换动画开始时触发，其参数类型为[OnSwiperAnimationStartCallback](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#onswiperanimationstartcallback18)，其中的参数index为当前显示元素的索引，而切换动画结束回调[onAnimationEnd](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#onanimationend9)也包含index参数。

#### 解决方案

*   方案一：onChange事件可以在子组件索引变化时触发并且返回索引值，当Swiper滑动时，即可获取当前页面的索引值，监听当前页面的下标位置。调用onChange示例代码如下：
    
    class MyDataSource implements IDataSource {
      private list: number\[\] = \[\];
    
      constructor(list: number\[\]) {
        this.list = list;
      }
    
      totalCount(): number {
        return this.list.length;
      }
    
      getData(index: number): number {
        return this.list\[index\];
      }
    
      registerDataChangeListener(): void {
      }
    
      unregisterDataChangeListener() {
      }
    }
    
    @Entry
    @Component
    struct SwiperOnChange {
      private swiperController: SwiperController = new SwiperController();
      private data: MyDataSource = new MyDataSource(\[\]);
    
      aboutToAppear(): void {
        let list: number\[\] = \[\];
        for (let i = 1; i <= 15; i++) {
          list.push(i);
        }
        this.data = new MyDataSource(list);
      }
    
      build() {
        Column({ space: 5 }) {
          Swiper(this.swiperController) {
            LazyForEach(this.data, (item: string) => {
              Text(item.toString())
                .width('90%')
                .height(160)
                .backgroundColor(0xAFEEEE)
                .textAlign(TextAlign.Center)
                .fontSize(30);
            }, (item: string) => item);
          }
          .cachedCount(2)
          .index(5)
          .autoPlay(true)
          .interval(4000)
          .loop(true)
          .duration(1000)
          .itemSpace(0)
          .onChange((index: number) => {
            console.info(\`onChangeIndex + ${index}\`);
          })
          .indicator( _// 设置圆点导航点样式_
            new DotIndicator()
              .itemWidth(8)
              .itemHeight(8)
              .selectedItemWidth(16)
              .selectedItemHeight(8)
              .color(Color.Gray)
              .selectedColor(Color.Blue)
              .maxDisplayCount(9))
          .displayArrow({
         _   // 设置导航点箭头样式_
            showBackground: true,
            isSidebarMiddle: true,
            backgroundSize: 24,
            backgroundColor: Color.White,
            arrowSize: 18,
            arrowColor: Color.Blue
          }, false)
          .curve(Curve.Linear);
        }.width('100%')
        .margin({ top: 5 });
      }
    }
    
*   方案二：通过监听[属性](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#属性-1)index获取视窗内页面的索引，能够监听index参数的事件有：
    
    onAnimationStart事件，onAnimationEnd事件，[onGestureSwipe](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#ongestureswipe10)事件以及[onContentDidScroll](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper#oncontentdidscroll12)事件。以onAnimationStart事件为例获取index索引，示例代码如下：
    
    class MyOwnDataSource implements IDataSource {
      private list: number\[\] = \[\];
    
      constructor(list: number\[\]) {
        this.list = list;
      }
    
      totalCount(): number {
        return this.list.length;
      }
    
      getData(index: number): number {
        return this.list\[index\];
      }
    
      registerDataChangeListener(): void {
      }
    
      unregisterDataChangeListener() {
      }
    }
    
    @Entry
    @Component
    struct SwiperOnAnimationStart {
      private swiperController: SwiperController = new SwiperController();
      private data: MyOwnDataSource = new MyOwnDataSource(\[\]);
    
      aboutToAppear(): void {
        let list: number\[\] = \[\];
        for (let i = 1; i <= 15; i++) {
          list.push(i);
        }
        this.data = new MyOwnDataSource(list);
      }
    
      build() {
        Column({ space: 5 }) {
          Swiper(this.swiperController) {
            LazyForEach(this.data, (item: string) => {
              Text(item.toString())
                .width('90%')
                .height(160)
                .backgroundColor(0xAFEEEE)
                .textAlign(TextAlign.Center)
                .fontSize(30);
            }, (item: string) => item);
          }
          .cachedCount(2)
          .index(5)
          .autoPlay(true)
          .interval(4000)
          .loop(true)
          .duration(1000)
          .itemSpace(0)
          .onAnimationStart((index: number, targetIndex: number, extraInfo: SwiperAnimationEvent) => {
            console.info(\`index: + ${index}\`);
            console.info(\`targetIndex: + ${targetIndex}\`);
            console.info(\`current offset: + ${extraInfo.currentOffset}\`);
            console.info(\`target offset: + ${extraInfo.targetOffset}\`);
            console.info(\`velocity: + ${extraInfo.velocity}\`);
          })
          .indicator( _// 设置圆点导航点样式_
            new DotIndicator()
              .itemWidth(8)
              .itemHeight(8)
              .selectedItemWidth(16)
              .selectedItemHeight(8)
              .color(Color.Gray)
              .selectedColor(Color.Blue)
              .maxDisplayCount(9))
          .displayArrow({
           _ // 设置导航点箭头样式_
            showBackground: true,
            isSidebarMiddle: true,
            backgroundSize: 24,
            backgroundColor: Color.White,
            arrowSize: 18,
            arrowColor: Color.Blue
          }, false)
          .curve(Curve.Linear);
        }.width('100%')
        .margin({ top: 5 });
      }
    }
    

#### 常见FAQ

Q：如何通过监听判断Swiper组件是否要切换到下一界面？

A：onAnimationStart事件的参数targetIndex为切换动画目标元素的索引，监听该参数即可判断Swiper是否要切换到下一界面。

Q：需要在Swiper组件切换时立即改变其他组件状态，目前通过在onChange里用index更新其他变量来实现，但是onChange触发有明显延迟，怎么解决？

A：onChange事件在页签切换动画结束后才能收到回调，如果需要在切换动画过程中就获取新的index，可以使用切换动画开始时就触发的onAnimationStart事件，通过获取切换动画目标元素的索引targetIndex来实现。