移動端 - 局部滾動

原由

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

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

示例: 請看第二屏github

clipboard.png

clipboard.png

初步設想

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

遇到問題

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

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

因而在網上查了幾番,有如下幾種解決方法app

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

改變元素的transform值

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

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

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

(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年前,果斷不敢用~this

使用swiper

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

局部滾動後的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")
    }
相關文章
相關標籤/搜索