移動端 - 局部滾動

起因

我司最近在做一個H5,有一個模擬微信對話框的需求,具體需求如下。

  1. 對話內容固定,但需要一句一句顯示
  2. 對話內容超過一屏後,需要使對話內容上移
  3. 對話內容結束後,用戶可以上下滑動對話框,查看詳細對話內容
  4. 圖中灰色頭像表示獲取的用戶頭像

示例: 請看第二屏

clipboard.png

clipboard.png

初步設想

  1. 使對話內容一句一句顯示,腦子裏立馬閃現出setInterval定時器。
  2. 對話內容超過一屏,使對話內容上移,當然是改變父元素的scrollTop值啦
  3. 用戶可以上下滑動對話框,就類似於滾動條效果,設置父元素高度並且 overflow:hidden,子元素高度auto即可。
  4. 獲取用戶頭像,這個薛微複雜,留做下一篇文章。

遇到問題

局部滾動效果,以上想法(設置父元素高度並且 overflow:hidden)在PC端可以正常滑動,但 在移動端失效
這種寫法,單獨寫沒有問題,但是IOS端出現卡頓現象,可以添加 -webkit-overflow-scrolling:touch; 解決。

但是,我司的H5頁面使用的swiper製作,大概是這個有一些影響,用戶滑動屏幕首先觸發了swiper的事件。(僅做設想,後續做進一步實踐)

於是在網上查了幾番,有以下幾種解決方法

  • 用戶在解發touchmove事件時,改變元素的transform值
  • 使用iscroll.js
  • 使用swiper

改變元素的transform值

改變元素的transform值,需要判斷用戶的滑動方向。
判斷滑動方向時,先了解兩個事件

  • touchstart :用戶手指按在屏幕上時觸發
  • touchmove:用戶滑動屏幕時觸發

瞭解了這兩個事件,我們可以在用戶觸發touchstart事件時,記錄手指位置,在touchmove記錄獲取手指最後停留的位置
判斷 最後停留位置 - 初始位置= pageY- startY = 即用戶滑動方向

(pageY-startY)爲正數時,說明用戶向下滑動;爲負數時,說明用戶向上滑動。

$(".message-wrapper").on("touchstart", function (e) {
     startY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
})
$(".message-wrapper").on("touchmove", function (e) {
     pageY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
     
})

使用iscroll.js

網上有很多關於iscroll的資料,但是我查了一下官方的github,最近的更新在5年前,果斷不敢用~

使用swiper

查了一番,swiper裏的 swiper-scrollbar可以完美的實現這一功能,單獨寫這一功能,在真機測試沒有問題。然後移入到我們的項目中。出現以下幾個問題

局部滾動後的slide元素不顯示

分析原因

出現這個問題的原因,是由於我司的H5項目也是由swiper製作,這意味着每一屏就相當於一個slide,當添加用swiper完成的局部滾動時,會造成後面父元素的slide元素不顯示。

解決辦法

這涉及到多個swiper嵌套使用的問題,具體修改如下:

  1. 當頁面存在多個swiper,初始化時,儘量避免使用一樣的類名,如 .swiper-container,每個swiper有它單獨的類名

            <div class="swiper-container main-swiper"> //父元素swiper
              <div class="swiper-wrapper">
                    <div class="swiper-slide slide1"></div>
                    <div class="swiper-slide slide2">
                        <div class="swiper-container message-warp"> //子元素swiper
                          <div class="swiper-wrapper message-wrapper">
                            <div class="swiper-slide message-slide"></div>
                          </div>
                       </div>
                    </div>
                    <div class="swiper-slide slide3"></div>
              </div>
            </div>
    
    
    //-------------------------------------------------------------swiper初始化   
    
  2. 如果類名分開,父元素後續slide元素依然無法顯示
    將子元素的初始化,寫在父元素初始化之前,加載時,優先初始化子元素swiper

       
        //初始化子swiper
          var scrollSwiper = new Swiper('.message-warp', {
                observer: true,
                observeParents: false,
                scrollbar: '.swiper-scrollbar',
                direction: 'vertical',
                slidesPerView: 'auto',
                mousewheelControl: true,
                freeMode: true,
         })
    
       var swiper = new Swiper('.main-swiper', {
            direction: 'vertical',
            touchRatio: 0.5,
            loop: false,
            on: {
                init: function () {
                    swiperAnimate(this);
                },
                slideChangeTransitionEnd: function (e) {               
                    swiperAnimate(this)
                }
            }
        });
    
  3. 以上方法都不能使後續 元素顯示

    swiper運行時,會先給元素添加visiblity:hidden;使元素隱藏,只給當前頁的visiblity設置爲visible;而swiper中,改元素顯示狀態的依據就是swiper-slide-active;

    swiper默認給當前的slide添加swiper-slide-active類名。當頁面中存在swiper嵌套時,父元素的當前slide會添加該類名,子元素的當前slide也會添加該類名。

    這樣當用戶滑出父元素的當前slide時父元素的swiper-slide-active被移除,而子元素的swiper-slide-active類名並沒有移除,造成swiper混亂,所以父元素後續slide的元素會無法顯示

解決辦法

我的做法是在父元素切換slide後,判斷頁面中swiper-slide-active的個數,如果存在一個以上,則說明子元素的類名沒有移除。
手動將子元素的swiper-slide-active類名移除即可。
暫時還沒有想到更好的方法,如果你有更好的方法,歡迎一起討論。

    if ($(".swiper-slide-active").length == 2) {
        $(".message-slide").removeClass("swiper-slide-active")
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章