给你的H5页面加上惯性滚动吧!

这篇具有很好参考价值的文章主要介绍了给你的H5页面加上惯性滚动吧!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在移动端,如果你使用过 overflow: scroll 生成一个滚动容器,会发现它的滚动是比较卡顿,呆滞的。为什么会出现这种情况呢?

因为我们早已习惯了目前的主流操作系统和浏览器视窗的滚动体验,比如滚动到边缘会有回弹,手指停止滑动以后还会按惯性继续滚动一会,手指快速滑动时页面也会快速滚动。而这种原生滚动容器却没有,就会让人感到卡顿。

首先,让我们来看一下它是怎样让滚动更流畅的吧。

<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app"></div>
    <template id="tpl">
      <div
        class="wrapper"
        ref="wrapper"
        @touchstart.prevent="onStart"
        @touchmove.prevent="onMove"
        @touchend.prevent="onEnd"
        @touchcancel.prevent="onEnd"
        @mousedown.prevent="onStart"
        @mousemove.prevent="onMove"
        @mouseup.prevent="onEnd"
        @mousecancel.prevent="onEnd"
        @mouseleave.prevent="onEnd"
        @transitionend="onTransitionEnd"
      >
        <ul class="list" ref="scroller" :style="scrollerStyle">
          <li class="list-item" v-for="item in list">{{item}}</li>
        </ul>
      </div>
    </template>
    <style>
      body,
      ul {
        margin: 0;
        padding: 0;
      }

      ul {
        list-style: none;
      }

      .wrapper {
        width: 100vw;
        height: 100vh;
        overflow: hidden;
      }

      .list {
        background-color: #70f3b7;
      }

      .list-item {
        height: 40px;
        line-height: 40px;
        width: 100%;
        text-align: center;
        border-bottom: 1px solid #ccc;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

    <script>
      console.log(Vue, "sss");
      new Vue({
        el: "#app",
        template: "#tpl",
        computed: {
          list() {
            let list = [];
            for (let i = 0; i < 100; i++) {
              list.push(i);
            }
            return list;
          },
          scrollerStyle() {
            return {
              transform: `translate3d(0, ${this.offsetY}px, 0)`,
              "transition-duration": `${this.duration}ms`,
              "transition-timing-function": this.bezier,
            };
          },
        },
        data() {
          return {
            minY: 0,
            maxY: 0,
            wrapperHeight: 0,
            duration: 0,
            bezier: "linear",
            pointY: 0, // touchStart 手势 y 坐标
            startY: 0, // touchStart 元素 y 偏移值
            offsetY: 0, // 元素实时 y 偏移值
            startTime: 0, // 惯性滑动范围内的 startTime
            momentumStartY: 0, // 惯性滑动范围内的 startY
            momentumTimeThreshold: 300, // 惯性滑动的启动 时间阈值
            momentumYThreshold: 15, // 惯性滑动的启动 距离阈值
            isStarted: false, // start锁
          };
        },
        mounted() {
          this.$nextTick(() => {
            this.wrapperHeight =
              this.$refs.wrapper.getBoundingClientRect().height;
            this.minY =
              this.wrapperHeight -
              this.$refs.scroller.getBoundingClientRect().height;
          });
        },
        methods: {
          onStart(e) {
            const point = e.touches ? e.touches[0] : e;
            this.isStarted = true;
            this.duration = 0;
            this.stop();
            this.pointY = point.pageY;
            this.momentumStartY = this.startY = this.offsetY;
            this.startTime = new Date().getTime();
          },
          onMove(e) {
            if (!this.isStarted) return;
            const point = e.touches ? e.touches[0] : e;
            const deltaY = point.pageY - this.pointY;
            this.offsetY = Math.round(this.startY + deltaY);
            const now = new Date().getTime();
            // 记录在触发惯性滑动条件下的偏移值和时间
            if (now - this.startTime > this.momentumTimeThreshold) {
              this.momentumStartY = this.offsetY;
              this.startTime = now;
            }
          },
          onEnd(e) {
            if (!this.isStarted) return;
            this.isStarted = false;
            if (this.isNeedReset()) return;
            const absDeltaY = Math.abs(this.offsetY - this.momentumStartY);
            const duration = new Date().getTime() - this.startTime;
            // 启动惯性滑动
            if (
              duration < this.momentumTimeThreshold &&
              absDeltaY > this.momentumYThreshold
            ) {
              const momentum = this.momentum(
                this.offsetY,
                this.momentumStartY,
                duration
              );
              this.offsetY = Math.round(momentum.destination);
              this.duration = momentum.duration;
              this.bezier = momentum.bezier;
            }
          },
          onTransitionEnd() {
            this.isNeedReset();
          },
          momentum(current, start, duration) {
            const durationMap = {
              noBounce: 2500,
              weekBounce: 800,
              strongBounce: 400,
            };
            const bezierMap = {
              noBounce: "cubic-bezier(.17, .89, .45, 1)",
              weekBounce: "cubic-bezier(.25, .46, .45, .94)",
              strongBounce: "cubic-bezier(.25, .46, .45, .94)",
            };
            let type = "noBounce";
            // 惯性滑动加速度
            const deceleration = 0.003;
            // 回弹阻力
            const bounceRate = 10;
            // 强弱回弹的分割值
            const bounceThreshold = 300;
            // 回弹的最大限度
            const maxOverflowY = this.wrapperHeight / 6;
            let overflowY;

            const distance = current - start;
            const speed = (2 * Math.abs(distance)) / duration;
            let destination =
              current + (speed / deceleration) * (distance < 0 ? -1 : 1);
            if (destination < this.minY) {
              overflowY = this.minY - destination;
              type =
                overflowY > bounceThreshold ? "strongBounce" : "weekBounce";
              destination = Math.max(
                this.minY - maxOverflowY,
                this.minY - overflowY / bounceRate
              );
            } else if (destination > this.maxY) {
              overflowY = destination - this.maxY;
              type =
                overflowY > bounceThreshold ? "strongBounce" : "weekBounce";
              destination = Math.min(
                this.maxY + maxOverflowY,
                this.maxY + overflowY / bounceRate
              );
            }

            return {
              destination,
              duration: durationMap[type],
              bezier: bezierMap[type],
            };
          },
          // 超出边界时需要重置位置
          isNeedReset() {
            let offsetY;
            if (this.offsetY < this.minY) {
              offsetY = this.minY;
            } else if (this.offsetY > this.maxY) {
              offsetY = this.maxY;
            }
            if (typeof offsetY !== "undefined") {
              this.offsetY = offsetY;
              this.duration = 500;
              this.bezier = "cubic-bezier(.165, .84, .44, 1)";
              return true;
            }
            return false;
          },
          // 停止滚动
          stop() {
            const matrix = window
              .getComputedStyle(this.$refs.scroller)
              .getPropertyValue("transform");
            this.offsetY = Math.round(+matrix.split(")")[0].split(", ")[5]);
          },
        },
      });
    </script>
  </body>
</html>

可以发现,在增加惯性滚动,边缘回弹等效果之后,明显流畅、舒服了很多。那么,这些效果是怎么实现的呢?在用户滑动操作结束时,还会继续惯性滚动一段。首先看一下源码中的函数,这是 touchend 事件的处理函数,也就是用户滚动操作结束时的逻辑。文章来源地址https://www.toymoban.com/news/detail-840871.html

到了这里,关于给你的H5页面加上惯性滚动吧!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为你的网站加上Loading等待加载效果吧 | Loading页面加载添加教程

    为你的网站加上Loading等待加载效果吧 | Loading页面加载添加教程 效果图 : 教程开始 新建一个loading样式css 将以下代码放进去 然后引用这个文件 code #Loadanimation{    background-color:#fff;    height:100%;    width:100%;    position:fixed;    z-index:1;    margin-top:0px;top:0px;     } #Loadanimation

    2024年02月09日
    浏览(75)
  • vue3 h5进入页面后自动滚动到底部

    背景: 在做h5项目中的聊天页面时,需求是进入页面自动滚到底部,方便用户看到最新消息(因为消息是正序排列的,最新消息自然展示在底部)。  直接上代码: 主要代码:

    2024年02月16日
    浏览(22)
  • 【Web3 系列开发教程——创建你的第一个 NFT(7)】创建一个 NFT DApp,给你的 NFT 赋予属性,例如图片

    在本文中,你将构建一个 NFT 铸币机,并学习如何通过使用 Metamask 和 Web3 工具将你的智能合约连接到 React 前端,来创建一个NFT dApp。 我认为,对于具备 Web2 开发背景的开发者来说,最大的挑战之一是 弄清楚如何将你的智能合约连接到前端项目并与之交互。 通过构建 NFT 铸币

    2024年01月16日
    浏览(35)
  • 小程序开发实战案例五 | 小程序如何嵌入H5页面

    在接入小程序过程中会遇到需要将 H5 页面集成到小程序中情况,今天我们就来聊一聊怎么把 H5 页面塞到小程序中。   本篇文章将会从下面这几个方面来介绍: 小程序承载页面的前期准备 小程序如何承载 H5 小程序和 H5 页面如何通讯 小程序和 H5 页面的相互跳转   首先介绍下

    2024年01月19日
    浏览(26)
  • h5开发网站-页面内容不够高时,如何定位footer始终位于页面的最底部

    在使用h5开发页面时,会遇到这个情况:当整个页面高度不足以占满显示屏一屏,页脚不是在页面最底部,影响用户视觉。想让页脚始终在页面最底部,我们可能会想到用: 1.min-height来控制content中间内容区高度,来让页面高度能够占满显示屏一屏,但是大型网站页面比较多的

    2024年02月09日
    浏览(20)
  • uniapp 开发 APP 使用 web-view 引入H5 app与 h5 页面通信

    uniapp 可以同时兼容 APP 和 H5,但有时候有些功能在 APP 中实现不了而在 H5 中可以实现,就可以采用 web-view 的方式在 APP 模式下显示 H5 页面。但是 APP 和 H5 储存的参数是不能共享的,例如token,就涉及到 APP 与 H5 之间的参数传递。 H5 向 APP 传参:引入 webview.js ,调用 uni.postMes

    2024年02月13日
    浏览(21)
  • 怎么给你的vitepress添加图片放大预览效果

    基于markdown-it 可设置自定义属性的插件 效果预览地址传送 Step. 1: 安装依赖 Step. 2: 引入插件 Step. 3: 配置 vitepress config.js文件 Step. 4: 引入图片灯箱js和css文件 配置 .vitepress/config.js 文件 加入 head 配置 Step. 5: 渲染效果

    2024年02月14日
    浏览(18)
  • 给你的项目启动提提速:Lazy Initialization

    前言   在一个名为种花家的小镇上,生活着一群热爱编程的人。他们致力于构建出高效、可维护的软件系统,而 Spring Boot 框架成为了他们的不二之选。这个小镇上的人们每天都在用 Spring Boot 框架创造着令人瞩目的应用程序。   然而,随着时间的推移,他们的应用程序变

    2024年02月03日
    浏览(24)
  • UniApp开发安卓以及H5实现页面级权限管理,避免用户浏览器直接输入url访问页面

    前言:uni-app如何像vue-router中的beforeEach一样实现跳转拦截功能呢? 为此uniapp官方提供了专门的API方法 uni.addInterceptor 举个栗子 我们发现底部有四个菜单分别是:首页、分类、购物车、我的;按常理来说首页和分类是不需要登陆就能查看的。另外两个则需要先登陆才能查看没登

    2024年01月16日
    浏览(30)
  • uniapp 开发H5页面,实现语音识别功能--前端,不包含后端转换

    一、背景 微信小程序开发,内嵌h5页面,不能调用微信内部的插件 二、实现方式 通过安装  js-audio-recorder  插件实现既定需求 三、具体步骤 1、安装插件 npm i js-audio-recorder 2、引入 在需要使用的页面中引入:import Recorder from \\\'js-audio-recorder\\\'; 3、具体配置

    2024年04月13日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包