vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果


Posted in Javascript onApril 08, 2019

vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果

https://github.com/383514580/any-touch

先看demo

demo

说点湿的

 vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果

iscroll其实代码量挺大的(近2100行, 还有另一个类似的库 betterScroll 他的代码量和iscroll差不多, 因为原理都是一样的), 阅读他们的代码

发现里面很多逻辑 其实都是在做手势判断 , 比如拖拽(pan), 和划(swipe), 还有部分元素(表单元素等)需要单独判断点击(tap), 这部分代码接近1/3, 所以我决定用自己开发的手势库(any-touch)实现一个iscroll, 同时配合文字让大家 最终都可以以最少的代码实现一个iscroll .

vue

观察了一段时间推荐排行, 发现大家都对 vue 感兴趣, 所以本次的"iscroll"将以vue组件的形式实现, 同时我也希望借助vue强大的抽象能力, 让最终代码控制在500行以内 , 希望大家喜欢.

本文是个系列文章

本文先实现拖拽和滑动动画, 因为这2部分都依赖 手势 , 借此用最少的代码先实现最核心的功能, 也让大家对后续的内容有信心.

简单说下iscroll原理

添加2个div, 最内的div(子div)通过设置css的transform的translate的值来模拟系统滚动效果.

说完逻辑再说代码

拖拽的时候通过panstart/panmove手势返回的 位移增量 (deltaX/Y)进行位置变化, 同时关闭动画效果.
发生快速划(swipe)的时候, 开启动画, 同时通过计算 目标位置 和 动画时间 来触发滑动动画.
代码

<div class="any-scroll-view">
  <div ref="body" :style="bodyStyle" class="any-scroll-view__body"><slot></slot></div>
</div>
.any-scroll-view {
  position: relative;
  width: 100%;
  height: 90vh; 
  overflow: hidden;

  &__body {
    transition-timing-function: cubic-bezier(0.1, 0.57, 0.1, 1);
    background: #eee;
    position: absolute;
    width: 100%;
    height: 100%;
  }
}
import AnyTouch from 'any-touch';
export default {
  name: 'any-scroll-view',

  props: {
    // 减速度, 单位px/s²
    acceleration: {
      type: Number,
      default: 3600
    }
  },

  data() {
    return {
      scrollTop: 0,
      scrollLeft: 0,
      transitionDuration: 300
    };
  },

  computed: {
    bodyStyle() {
      return {
        transitionDuration: `${this.transitionDuration}ms`,
        transform: `translate(${this.scrollLeft}px, ${
          this.scrollTop
        }px)`
      };
    }
  },

  mounted() {
    const at = new AnyTouch(this.$el);

    // 第一次触碰
    at.on('inputstart', (ev) => {
      this.stopRoll();
    });

    // 拖拽开始
    at.on('panstart', (ev) => {
      this.move(ev);
    });

    // 拖拽中
    at.on('panmove', (ev) => {
      this.move(ev);
    });

    // 快速滑动
    at.on('swipe', (ev) => {
      this.decelerate(ev);
    });

    this.$on('hook:destroy', () => {
      at.destroy();
    });
  },

  methods: {
    // https://github.com/nolimits4web/swiper/blob/master/dist/js/swiper.esm.js#L87
    // https://github.com/nolimits4web/Swiper/blob/master/src/utils/utils.js#L25
    getCurrentTranslate() {
      const style = getComputedStyle(this.$refs.body, null);
      const { transform } = style;
      const array = transform.match(/(\-?)(\d)+(\.\d{0,})?/g);
      return { x: Math.round(array[4]), y: Math.round(array[5]) };
    },

    stopRoll() {
      const { x, y } = this.getCurrentTranslate();
      this.moveTo({ scrollTop: y, scrollLeft: x });
    },

    /**
     * 移动body
     * @param {Object} 拖拽产生的数据
     * @param {Number} deltaX: x轴位移变化
     * @param {Number} deltaY: y轴位移变化
     */
    move({ deltaX, deltaY }, transitionDuration = 0) {
      this.transitionDuration = transitionDuration;
      this.scrollLeft += deltaX;
      this.scrollTop += deltaY;
    },

    /**
     * 移动到
     */
    moveTo({ scrollTop, scrollLeft }, transitionDuration = 0) {
      this.transitionDuration = transitionDuration;
      this.scrollLeft = scrollLeft;
      this.scrollTop = scrollTop;
    },

    /**
     * 拖拽松手后减速移动至停止
     * velocityX/Y的单位是px/ms
     */
    decelerate(ev) {
      const directionSign = { up: -1, right: 1, down: 1, left: -1 }[
        ev.direction
      ];

      // Top? | Left?
      let SCROLL_SUFFIX = 'Top';
      // x ? | y?
      let AXIS_SUFFIX = 'Y';
      if (ev.velocityX > ev.velocityY) {
        SCROLL_SUFFIX = 'Left';
        AXIS_SUFFIX = 'X';
      }

      // 减速时间, 单位ms
      // t = (v₂ - v₁) / a
      const velocity = ev[`velocity${AXIS_SUFFIX}`];
      this.transitionDuration = Math.round(
        ((velocity * 1000) / this.acceleration) * 1000
      );

      // 滑动距离
      // s = (v₂² - v₁²) / (2 * a)
      const scrollAxis = `scroll${SCROLL_SUFFIX}`;
      this[scrollAxis] +=
        directionSign *
        Math.round(
          Math.pow(velocity * 1000, 2) / (2 * this.acceleration)
        );
    }
  }
};

总结

以上所述是小编给大家介绍的vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JavaScript 在线压缩和格式化收藏
Jan 16 Javascript
ext 代码生成器
Aug 07 Javascript
网页中可关闭的漂浮窗口实现可自行调节
Aug 20 Javascript
引用其它js时如何同时处理多个window.onload事件
Sep 02 Javascript
jQuery删除当前节点元素
Dec 07 Javascript
React native ListView 增加顶部下拉刷新和底下点击刷新示例
Apr 27 Javascript
详解vue组件基础
May 04 Javascript
使用vuex缓存数据并优化自己的vuex-cache
May 30 Javascript
vue.js中ref和$refs的使用及示例讲解
Aug 14 Javascript
微信公众号网页分享功能开发的示例代码
May 27 Javascript
vue页面跳转实现页面缓存操作
Jul 22 Javascript
开发一个封装iframe的vue组件
Mar 29 Vue.js
面试题:react和vue的区别分析
Apr 08 #Javascript
vue router 组件的高级应用实例代码
Apr 08 #Javascript
JavaScript中的一些实用小技巧总结
Apr 07 #Javascript
详解vue 不同环境配置不同的打包命令
Apr 07 #Javascript
JavaScript数组去重的几种方法
Apr 07 #Javascript
vue表单验证你真的会了吗?vue表单验证(form)validate
Apr 07 #Javascript
js中Generator函数的深入讲解
Apr 07 #Javascript
You might like
一个很不错的PHP翻页类
2009/06/01 PHP
PHP获取MSN好友列表类的实现代码
2013/06/23 PHP
PHP中多线程的两个实现方法
2016/10/14 PHP
php对xml文件的增删改查操作实现方法分析
2017/05/19 PHP
解决laravel查询构造器中的别名问题
2019/10/17 PHP
Javascript 布尔型分析
2008/12/22 Javascript
分享27款非常棒的jQuery 表单插件
2011/03/28 Javascript
关于jQuery的inArray 方法介绍
2011/10/08 Javascript
ajax与302响应代码测试
2013/10/23 Javascript
JS检测移动端横竖屏的代码
2016/05/30 Javascript
knockoutjs动态加载外部的file作为component中的template数据源的实现方法
2016/09/01 Javascript
node.js实现博客小爬虫的实例代码
2016/10/08 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
jquery实现折叠菜单效果【推荐】
2017/03/08 Javascript
JavaScript hasOwnProperty() 函数实例详解
2017/08/04 Javascript
JS小球抛物线轨迹运动的两种实现方法详解
2017/12/20 Javascript
js实现手机web图片左右滑动效果
2017/12/29 Javascript
使用socket.io制做简易WEB聊天室
2018/01/02 Javascript
vue实现验证码按钮倒计时功能
2018/04/10 Javascript
详解vue-router的导航钩子(导航守卫)
2020/11/02 Javascript
[14:56]教你分分钟做大人:巫医
2014/10/30 DOTA
[01:57]2018DOTA2亚洲邀请赛赛前采访-iG
2018/04/03 DOTA
python paramiko实现ssh远程访问的方法
2013/12/03 Python
Python中MySQLdb和torndb模块对MySQL的断连问题处理
2015/11/09 Python
Python爬虫之正则表达式基本用法实例分析
2018/08/08 Python
Python cv2 图像自适应灰度直方图均衡化处理方法
2018/12/07 Python
python 使用递归实现打印一个数字的每一位示例
2020/02/27 Python
Python接口自动化系列之unittest结合ddt的使用教程详解
2021/02/23 Python
Myprotein葡萄牙官方网站:英国优质运动营养品牌
2016/09/12 全球购物
乌克兰珠宝大卖场:Zlato.ua
2020/09/27 全球购物
弘扬雷锋精神活动演讲稿
2014/03/04 职场文书
三八妇女节活动总结
2014/05/04 职场文书
社区文艺活动方案
2014/08/19 职场文书
中学生教师节演讲稿
2014/09/03 职场文书
2016护理专业求职自荐书
2016/01/28 职场文书
创业计划之特色精品店
2019/08/12 职场文书