위 챗 애플 릿 가상 목록 의 구현 예제

머리말
대부분의 애플 리 케 이 션 은 이러한 수요 가 있 습 니 다.페이지 에 긴 목록 이 있 습 니 다.끝까지 내 려 가 야 할 때 배경 데 이 터 를 요청 하고 데 이 터 를 계속 렌 더 링 합 니 다.데이터 목록 이 길 어 지면 뚜렷 한 카드 가 걸 리 고 페이지 의 흰색 화면 이 반 짝 이 는 현상 을 발견 할 수 있 습 니 다.
분석 하 다.
4.567917.배경 데 이 터 를 요청 하려 면 끊 임 없 는 setData 가 필요 하고 데 이 터 를 계속 합병 해 야 하기 때문에 후기 데이터 가 너무 과장 되 었 습 니 다
  • 렌 더 링 된 DOM 구조 가 많 고 렌 더 링 할 때마다 dom 비 교 를 하 며 관련 diff 알고리즘 은 시간 이 많이 걸 립 니 다
  • DOM 수량 이 많 고 사용 하 는 메모리 가 많아 서 페이지 가 하 얀 화면 으로 걸 립 니 다
  • 초기 렌 더 링 방법
    
    /*
     * @Descripttion: 
     * @version: 
     * @Author: shijuwang
     * @Date: 2021-07-14 16:40:22
     * @LastEditors: shijuwang
     * @LastEditTime: 2021-07-14 17:10:13
     */
    //Page Object
    Page({
      data: {
        list: [],          //     
      },
      //options(Object)
      onLoad: function (options) {
        this.index = 0
        const arr = [
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
    
    
    
    
        ]
        this.setData({ list: arr })
      },
    
      onReachBottom: function () {
        const arr = [
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
    
        ]
        let { list } = this.data
        this.setData({
          list: [...list, ...arr]
        })
      },
    
    });
    
    
    // wxml 
    <view class="container">
        <view class="item-list" wx:for="{{list}}">
          <text class="">
              {{item.idx}}
          </text>
        </view>
    </view>
    
    바닥 에 닿 을 때마다 데 이 터 를 다시 요청 하고 배열 을 합 쳐 setData 를 다시 요청 합 니 다.목록 이 책임 질 때 카드 화면 이 나타 납 니 다.매번 setData 의 데이터 가 점점 커지 고 통신 시간 도 증가 하 며 dom 요 소 를 너무 많이 보 여 줍 니 다.다음 그림:

    초보 적 최적화
    1.1 차원 배열 을 2 차원 배열 로 바 꿉 니 다.
  • 일반적인 상황 에서 setData 는 모든 데 이 터 를 다시 렌 더 링 했 습 니 다
  • 페이지 별 요청 은 서버 에 대한 압력 이 상대 적 으로 적 고 페이지 별 증분 렌 더 링 은 setData 에 대한 압력 도 적다
  • 4.567917.setData 는 2 차원 배열 에 대응 하 는 색인 데이터 의 아래 표 시 를 찾 고 setData 로 부분 적 인 리 셋 을 한다4.567917.setData 는 현재 이 화면의 데 이 터 를 할당 합 니 다
    
    // wxml
    <view class="container">
      <block wx:for="{{list}}" wx:for-index="pageNuma">
        <view class="item-list" wx:for="{{item}}">
          <text class="">{{item.idx}}</text>
        </view>
      </block>
    </view>
    // wx.js
    Page({
      data: {
        list: [],          //     
      },
      //options(Object)
      onLoad: function (options) {
        this.index = 0;
        this.currentIndex = 0;          //      pageNuma
        const arr = [
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
    
    
    
    
        ]
        this.setData({ [`list[${this.currentIndex}]`]: arr })
      },
    
      onReachBottom: function () {
        this.currentIndex++;            //   +1
        const arr = [
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
    
        ]
        this.setData({
          [`list[${this.currentIndex}]`]: arr
        })
      },
    });

    이렇게 하면 전체 렌 더 링 은 화면 을 페이지 로 나 누 어 렌 더 링 하 는 것 을 볼 수 있 습 니 다.몇 개의 pageNum 을 요청 하면 몇 개의 화면 을 렌 더 링 하고 화면 에 목록 렌 더 링 을 하지 않 습 니 다.
    한층 더 최적화 하 다.
    2.우 리 는 시각 구역 의 한 화면 만 렌 더 링 하거나 시각 구역 부근의 몇 화면 만 렌 더 링 할 수 있 습 니 다.다른 지역 은 view 로 자 리 를 차지 하고 구체 적 인 렌 더 링 을 하지 않 아 dom 렌 더 링 을 감소 하고 노드 가 너무 많아 서 발생 하 는 문 제 를 줄 일 수 있 습 니 다.
    이 단 계 를 하려 면 다음 과 같은 몇 단계 로 나 누 어야 한다.
  • 현재 화면 높이,렌 더 링 을 가 져 올 때 각 화면 높이,스크롤 거리 계산 을 가 져 옵 니 다
  • 얻 은 모든 렌 더 링 데 이 터 를 저장 하고 모든 화면 높이 를 저장 하 며 onPageScroll 을 통 해 시각 적 인 영역 이 그 화면 에 있 습 니 다
  • 4.567917.시각 구역 을 제외 한 다른 지역 의 데 이 터 는 비어 있 고 view 로 위 치 를 차지한다
    
        is.currentIndex = 0;           //      pageNum
        this.pageHeight = [];            //       
        this.allList = [];               //         
        this.systemHeight = 0;           //     
        this.visualIndex = [];           //       pageNum
    
    
    페이지 에 들 어 갈 때 관련 데 이 터 를 마 운 트 합 니 다:
    
     // wxml
     <view wx:for="{{list}}" wx:for-index="pageNum" id="item{{pageNum}}">
        <view class="item-list" wx:for="{{item}}">
          <text class="">{{item.idx}}</text>
        </view>
      </view>
     onLoad: function (options) {
        this.index = 0;
        this.currentIndex = 0;           //      pageNum
        this.pageHeight = [];            //       
        this.allList = [];               //         
        this.systemHeight = 0;           //     
        const arr = [
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          },
          {
            idx: this.index++
          }
        ]
        this.setData({ [`list[${this.currentIndex}]`]: arr }, () => {
    
          this.setPageHeight();
        });
        this.getSystemInfo();
      },
    
    
    모든 화면 에 view 동적 으로 id 이름 을 설정 합 니 다.렌 더 링 할 때 모든 화면 높이 를 가 져 오고 저장 할 수 있 습 니 다.나중에 시각 영역 에서 차지 하지 않 는 높이 로 사용 할 수 있 습 니 다.
    페이지 하 이 트 를 순환 하고 각 페이지 의 높이 와 현재 스크롤 거 리 를 비교 하여 현재 렌 더 링 된 pageNum 을 가 져 온 다음 에 현재 렌 더 링 된 pageNum-+1 을 선택 하여 이전 화면 과 다음 화면 을 배열 에 넣 고 현재 세 페이지 의 데 이 터 를 보 여 줍 니 다.다른 화면의 데 이 터 는 view 가 차지 하고 높이 는 저장 높이 입 니 다.
    
       //       
      onPageScroll: throttle(function (e) {
        let pageScrollTop = e[0].scrollTop;  
        let that = this;
        //                
        let scrollTop = 0;
        let currentIndex = this.currentIndex;
    
        for (var i = 0; i < this.pageHeight.length; i++) {
          scrollTop = scrollTop + this.pageHeight[i];
    
          if (scrollTop > pageScrollTop + this.systemHeight - 50) {
            this.currentIndex = i;
            this.visualIndex = [i - 1, i, i + 1];
            that.setData({
              visualIndex: this.visualIndex
            })
            break;
          }
        }
      },200)
    
    
    실시 간 모니터링 스크롤,절 류 최적화 처리
    
    const throttle = (fn, interval) => {
      var enterTime = 0; //     
      var gapTime = interval || 300; //    ,  interval   ,   300ms
      return function () {
        var that = this;
        var backTime = new Date(); //     return      
        if (backTime - enterTime > gapTime) {
          fn.call(that, arguments);
          enterTime = backTime; //                     
        }
      };
    }
    
    시각 영역 배열 을 가 져 온 다음 현재 pageNum 이 visualIndex 에 있 는 지 판단 합 니 다.그렇지 않 으 면 view 가 자리 잡 고 저장 높이 를 높 게 가 져 옵 니 다.
    
    <wxs module='filter'>
     var includesList = function(list,currentIndex){
       if(list){
        return list.indexOf(currentIndex) > -1
       }
     }
     module.exports.includesList =  includesList;
    </wxs>
    <view class="container">
     <view wx:for="{{list}}" wx:for-index="pageNum" id="item{{pageNum}}" wx:key="pageNum">
       <block wx:if="{{filter.includesList(visualIndex,pageNum)}}">
         <view class="item-list" wx:for="{{item}}">
           <text class="">{{item.idx}}</text>
         </view>
       </block>
       <block wx:else>
         <view class="item-visible" style="height:{{pageHeight[pageNum]}}px"></view>
       </block>
     </view>
    </view>
    
    시각 영역 에 있 는 배열 의 pageNum 은 현재 배열 을 순환 합 니 다.없 으 면 높이 를 설정 하고 렌 더 링 효 과 는 다음 과 같 습 니 다.

    이런 방법 은 큰 성 과 를 거 두 었 다!
    방법 2
    위 챗 애플 릿 api 사용 하기
    IntersectionObserver
    
      //    
      observePage: function (pageNum) {
        const that = this;
        const observerView = wx.createIntersectionObserver(this).relativeToViewport({ top: 0, bottom: 0});
        observerView.observe(`#item${pageNum}`, (res) => {
          console.log(res,'res');
          if (res.intersectionRatio > 0) {
            that.setData({
              visualIndex: [pageNum - 1, pageNum, pageNum + 1]
            })
    
          }
        })
      }
    
    
    oberserve 를 이용 하여 현재 페이지 가 시각 영역 에 있 는 지 감청 합 니 다.그렇다면 현재 pageNum-+1,pageNum 을 시각 영역 배열 visualIndex 에 넣 고 wxs 에서 시각 영역 배열 에 현재 pageNum 이 존재 하 는 지 판단 합 니 다.그렇다면 렌 더 링,존재 하지 않 으 면 view 로 자 리 를 차지 합 니 다.
    방안 1  스크롤 컴 퓨 팅  >>>코드 세 션:(가상 목록 스크롤)
    방안 2  IntersectionObserver  api>>>코드 세 션:intersectionObserver
    위 챗 애플 릿 가상 목록 의 구현 예제 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 애플 릿 가상 목록 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

    좋은 웹페이지 즐겨찾기