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 相关文章推荐
分享20款好玩的jQuery游戏
Apr 17 Javascript
TextArea不支持maxlength的解决办法(jquery)
Sep 13 Javascript
HTTP 304错误的详细讲解
Nov 13 Javascript
jquery分页插件jpaginate在IE中不兼容问题
Apr 22 Javascript
jQuery新的事件绑定机制on()示例应用
Jul 18 Javascript
超漂亮的Bootstrap 富文本编辑器summernote
Apr 05 Javascript
Jquery ui datepicker设置日期范围,如只能隔3天【实现代码】
May 04 Javascript
JavaScript中对象的不同创建方法
Aug 12 Javascript
Javascript使用function创建类的两种方法(推荐)
Nov 19 Javascript
详解Vue 方法与事件处理器
Jun 20 Javascript
AngularJS实现动态切换样式的方法分析
Jun 26 Javascript
微信小程序实现自定义加载图标功能
Jul 19 Javascript
面试题: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
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
2009/04/24 PHP
PHP的foreach中使用引用时需要注意的一个问题和解决方法
2014/05/29 PHP
全面解读PHP的Yii框架中的日志功能
2016/03/17 PHP
php格式化json函数示例代码
2016/05/12 PHP
基于PHP制作验证码
2016/10/12 PHP
php实现的网页版剪刀石头布游戏示例
2016/11/25 PHP
php与c 实现按行读取文件实例代码
2017/01/03 PHP
phpcms实现验证码替换及phpcms实现全站搜索功能教程详解
2017/12/13 PHP
PHP+redis实现的购物车单例类示例
2019/02/02 PHP
Laravel框架控制器的middleware中间件用法分析
2019/09/30 PHP
php框架CI(codeigniter)自动加载与自主创建对象操作实例分析
2020/06/06 PHP
JavaScript RegExp方法获取地址栏参数(面向对象)
2009/03/10 Javascript
jQuery模拟select实现下拉菜单功能
2016/06/20 Javascript
详解Vue使用 vue-cli 搭建项目
2017/04/20 Javascript
JS中cookie的使用及缺点讲解
2017/05/13 Javascript
JS基于正则实现数字千分位用逗号分隔的方法
2017/06/16 Javascript
js实现城市级联菜单的2种方法
2017/06/23 Javascript
详谈js中标准for循环与foreach(for in)的区别
2017/11/02 Javascript
Vue瀑布流插件的使用示例
2018/09/19 Javascript
Vue中使用matomo进行访问流量统计的实现
2019/11/05 Javascript
[05:56]第十六期——新进3大C之小兔基
2014/06/24 DOTA
[03:16]DOTA2完美大师赛主赛事首日集锦
2017/11/23 DOTA
Python操作sqlite3快速、安全插入数据(防注入)的实例
2014/04/26 Python
windows系统中python使用rar命令压缩多个文件夹示例
2014/05/06 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
python 使用pandas计算累积求和的方法
2019/02/08 Python
Ubuntu配置Pytorch on Graph (PoG)环境过程图解
2020/11/19 Python
MONNIER Frères英国官网:源自巴黎女士奢侈品配饰电商平台
2018/12/06 全球购物
机修工岗位职责
2013/11/24 职场文书
幼儿园安全检查制度
2014/01/30 职场文书
人事专员工作职责
2014/02/22 职场文书
工程师岗位职责规定
2014/02/26 职场文书
小学生作文批改评语
2014/12/25 职场文书
离婚协议书样本
2015/01/26 职场文书
紧急通知
2015/04/17 职场文书
简单总结SpringMVC拦截器的使用方法
2021/06/28 Java/Android