移动端滚动条的问题

移动端滚动条的问题,第1张

1.问题背景:

之前为了让移动端滚动条滚动的更加顺滑,经常利用iscroll框架,来适配移动端的滚动,但是目前iscroll框架作者已经不维护了,之后国内一位程序员根据iscroll的源码,写了一个支持更多特性,滚动性能更高的better-scroll框架

优点:

API基本兼容iscroll,在iscroll的基础上扩展了一些特性以及做了一些性能优化基于原生JS实现,不依赖任何框架体积小,编译后代码只有63kb,压缩后是35kb,gzip后仅有9kb,非常轻量
2.问题描述:

当我们的内容超过浏览器的整个窗口,就会出现滚动,内部利用的原理就是利用浏览器默认可滚动的属性,超出浏览器窗口即滚动

注意:利用这种原理实现的滚动,在移动端是非常卡顿的


3.解决方案:

BetterScroll的引入及使用

代码一如下:

<template>
  <div class="wrapper">
    <ul class="content">
      <li>分类列表1</li>
      <li>分类列表2</li>
      <li>分类列表3</li>
      <li>分类列表4</li>
      <li>分类列表5</li>
      <li>分类列表6</li>
      <li>分类列表7</li>
      <li>分类列表8</li>
      <li>分类列表9</li>
      <li>分类列表10</li>
      <li>分类列表11</li>
      <li>分类列表12</li>
      <li>分类列表13</li>
      <li>分类列表14</li>
      <li>分类列表15</li>
      <li>分类列表16</li>
      <li>分类列表17</li>
      <li>分类列表18</li>
      <li>分类列表19</li>
      <li>分类列表20</li>
    </ul>
  </div>
</template>

<script>
import BScroll from 'better-scroll'
  export default {
    name: "Category",
    data() {
      return {
        scroll: null
      }
    },
    created() {
      this.scroll = new BScroll('.content', {

      })
    },
  }
</script>

<style scoped>
  .content {
    height: 150px;
    background-color: red;
    /* overflow: hidden; */
    /* overflow-y: scroll; */
  }
</style>
3.1 问题一

引入后发现滚动并没有生效,如下图一所示:

3.1.1 问题解决思路

原因分析一:

1.先看一下BetterScroll的滚动原理:BetterScroll 的原理与浏览器相同。我们可以通过一张图片更明显地感受到这一点:绿色部分是包装器,也称为父容器,具有固定的高度。黄色部分是内容,它是父容器的第一个子元素,其高度会随着内容的大小而增长。然后,当内容的高度不超过父容器的高度时,内容不会滚动。一旦超过,内容可以滚动。这就是 BetterScroll 的原理。
2.明白了BetterScroll的原理,我们得知滚动需要在最外层的包装器加滚动,所以需要在created()的生命周期做更改

解决思路: 将代码一中的 this.scroll = new BScroll(‘.content’, {})换成this.scroll = new BScroll(‘.wrapper’, {})
但是上述改动发现滚动如图一所示依然不生效

原因分析二:

1.最外层包裹的wrapper可能在很多地方都用到了这个类名,导致拿不到这个dom结构

解决思路: 用ref标记,再通过$refs来获取dom元素,这样就可以避免类名多次用到而获取不到dom的问题

绝望的是改动后依然如图一一样不生效。控制台报如下错误:

原因分析三: 想了好久,依然找不到问题,因为原因二中的报错就是找不到dom元素的问题,最后看了一下官方文档中的生命周期,发现了问题所在。因为在created()中dom结构还未经编译,此时 *** 作dom,均不生效,而在mounted()中, *** 作dom才有效,真是豁然开朗啊。最后针对官方文档中vue的生命周期图的每一步做了一下深层次分析,标记在了图的旁边。

最后生效后的代码如下:

代码二如下:

生效后如图二所示:


4.功能优化: 4.1 优化一

在我们滑动滚动条时,有时需要一个快捷的按钮,可以直接回到顶部,避免了图片较多时,用户需要不断的滑动滚动条才能回到顶部,增加了用户的体验,所以需要在首页增加一个滑动到某位置时回到顶部的按钮,此处也需要用到better-scroll框架

注意:修饰符.native什么时候可以使用?
在我们需要监听一个组件的原生事件时,必须给对应的事件加上.native修饰符,才能进行监听

	mounted() {
        this.scroll = new BScroll(this.$refs.wrapper, {
            
        })
    },
    methods: {
        scrollTo(x, y, time=300) {
            this.scroll.scrollTo(x, y, time)
        }
    },

封装back-top组件

<div class="home">
  <nav-bar class="home-nav"><div slot="center">购物街</div></nav-bar>

  <scroll class="content" ref="scroll">
    <home-swiper :banners="banners"></home-swiper>
    <recommend-view :recommends="recommends"></recommend-view>
    <feature-view></feature-view>
    <tab-control class="tab-control" :titles="['流行','新款','精选']" @tabClick='tabClick'></tab-control>
    <goods-list :goods="showGoods"></goods-list>
  </scroll>
  
  <back-top @click.native="backClick"></back-top>
</div>
methods: {
   backClick(){
   this.$refs.scroll.scrollTo(0, 0)
},

优化一效果如下图:

4.2 优化二

上述优化还有一个小改进就是,当我们上划到某个位置时,再显示回到顶部的按钮,而不是让他一直显示,这里应该对他进行控制显示和隐藏,实时监听滚动的位置。

Home.vue文件:

<div class="home">
  <nav-bar class="home-nav"><div slot="center">购物街</div></nav-bar>

  <scroll class="content" ref="scroll" :probeType="3" @scroll="contentScroll">
    <home-swiper :banners="banners"></home-swiper>
    <recommend-view :recommends="recommends"></recommend-view>
    <feature-view></feature-view>
    <tab-control class="tab-control" :titles="['流行','新款','精选']" @tabClick='tabClick'></tab-control>
    <goods-list :goods="showGoods"></goods-list>
  </scroll>
  
  <back-top @click.native="backClick" v-show="isShowBackTop"></back-top>
</div>
methods: {
          backClick(){
            this.$refs.scroll.scrollTo(0, 0)
          },
          contentScroll(position) {
            this.isShowBackTop = (-position.y) > 1000
          },
}

Scroll.vue文件:

mounted() {
        // 1.创建BScroll对象
        this.scroll = new BScroll(this.$refs.wrapper, {
            click: true,
            probeType: this.probeType
        })

        // 2.监听滚动的位置
        this.scroll.on('scroll', (position) => {
            this.$emit('scroll',position)
        })
    },

优化二效果如下图:


5.滚动区域的bug分析和解决: 5.1 问题原因分析:

我们将滚动的区域封装成了scroll.vue组件,scroll.vue它在决定里面有多少区域可以滚动时,它是根据内容决定的。better-scroll在计算内容高度的时候,由于内容里面有很多图片,这些图片还没有被加载出来,但是高度已经被计算出来,当图片被加载完成后,高度很明显比之前的高度要高,但是better-scroll并不知道有一个新的高度,导致无法滚动(可滚动区域高度见5.3问题解决截图)。

5.2 bug重现效果图:

我们在滚动时,时不时会出现下面的情况,即滚动出现卡顿无法滚动的情况,稍等片刻,即可以滚动,体验起来比较差

5.3 问题解决:

5.3.1 可滚动区域异常和正常时的高度:


5.3.2 解决思路:

监听每一张图片是否加载完成,只要有一张图片加载完成了,执行一次refresh()

如何监听图片加载完成了?

原生的js监听图片:img.onLoad = function(){}vue中监听:@load=‘方法’调用scroll的refresh()

5.3.3 效果图:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1324841.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存