移动端 - 局部滚动

栏目: Html · 发布时间: 5年前

内容简介:我司最近在做一个H5,有一个模拟微信对话框的需求,具体需求如下。图1

起因

我司最近在做一个H5,有一个模拟微信对话框的需求,具体需求如下。

  1. 对话内容固定,但需要一句一句显示
  2. 对话内容超过一屏后,需要使对话内容上移
  3. 对话内容结束后,用户可以上下滑动对话框,查看详细对话内容
  4. 图中灰色头像表示获取的用户头像

移动端 - 局部滚动

图1

移动端 - 局部滚动

图2

初步设想

  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初始化
  1. 如果类名分开,父元素后续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)
            }
        }
    });
  1. 以上方法都不能使后续 元素显示

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")
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Anatomy

Web Anatomy

Robert Hoekman Jr.、Jared Spool / New Riders / 2009-12-11 / USD 39.99

At the start of every web design project, the ongoing struggles reappear. We want to design highly usable and self-evident applications, but we also want to devise innovative, compelling, and exciting......一起来看看 《Web Anatomy》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试