使用原生js封装webapp滑动效果(惯性滑动、滑动回弹)


Posted in Javascript onMay 06, 2014

PC 移动端兼容  IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+ 惯性助动,滑动回弹

门面模式

window.onload = function() {
 /*测试数据*/
 var insert = '';
 for (var i = 0; i < 80; i++) {
  insert += '<div style = "width:100%; text-align:center;">滑动测试 ' + i + '</div>';
 }
 document.getElementById("moveArea").innerHTML = insert;
 /*测试数据   */
 var at = new appTouch({
  tContain : 'appArea', //必选:滑动区域id
  tMove : 'moveArea', //必选:移动区域id
  tScroller : 'scroller', //必选:自定义滚动条
  tScrollerArea : 'scrollerArea'//必选:滚动条区域
 }, onmoveend);
 //到顶/底回调
 function onmoveend(m) {
  //console.log(m);
 }
}
/*=====================
 * 名称: appTouch
 * 功能: web app滑动模拟组件
 * 参数: 相关配置
 ======================*/
var appTouch = function(config, callback) {
 this.touchContain = config.tContain;
 this.touchMove = config.tMove;
 this.touchScroller = config.tScroller;
 this.touchScrollerArea = config.tScrollerArea;
 this.callbackfn = callback;
 this.move();
}
appTouch.prototype = {
 move : function(e) {
  var monitor = document.getElementById(this.touchContain), //监听容器
  target = document.getElementById(this.touchMove), //移动目标
  scroller = document.getElementById(this.touchScroller), //自定义滚动条
  scrollerArea = document.getElementById(this.touchScrollerArea), //滚动条区域
  sheight = monitor.offsetHeight / target.offsetHeight * monitor.offsetHeight, //自定义滚动条的长度
  st = (target.offsetHeight - monitor.offsetHeight) / (monitor.offsetHeight - sheight), //移动块对应滚轮单位长度
  tslow = 4, //到顶/底减基数
  tMove = 0, //滑块到顶top值
  tMoveL = tMove + 140, //到顶允许下拉范围
  bMove = monitor.offsetHeight - target.offsetHeight, //滑块到底top值
  bMoveL = bMove - 140, //到底允许上滑范围
  callbackfn = this.callbackfn, //回调函数
  flg = false, //标记是否滑动
  startY, //标记起始位置
  startTop, //标记滑动起始时的高度值
  move = 0;
  //移动距离
  //鼠标事件注册
  addEvent(monitor, 'mousedown', moveStart);
  addEvent(monitor, 'mousemove', moveIn);
  addEvent(monitor, 'mouseup', moveEnd);
  addEvent(window, 'mousemove', moveIn);
  addEvent(window, 'mouseup', moveEnd);
  //移动设备触摸事件注册
  addEvent(monitor, 'touchstart', moveStart);
  addEvent(monitor, 'touchmove', moveIn);
  addEvent(monitor, 'touchend', moveEnd);
  /**
   *外观/门面模式包装
   */
  /*事件监听 */
  function addEvent(el, type, fn) {
   if (el.addEventListener) {
    el.addEventListener(type, fn, false);
   } else if (el.attachEvent) {
    el.attachEvent('on' + type, fn);
   } else {
    el['on' + type] = fn;
   }
  }
  //取消浏览器默认行为
  function stop(e) {
   //Opera/Chrome/FF
   if (e.preventDefault)
    e.preventDefault();
   //IE
   e.returnValue = false;
  }
  //包装结束
  /**
   *操作函数
   */
  //惯性缓动参数
  var lastMoveTime = 0;
  var lastMoveStart = 0;
  var stopInertiaMove = false;
  /*移动触发*/
  function moveStart(e) {
   stop(e);
   flg = true;
   if (e.touches)
    e = e.touches[0];
   startY = e.clientY;
   startTop = target.style.top || 0;
   //惯性缓动
   lastMoveStart = startY;
   lastMoveTime = new Date().getTime();
   stopInertiaMove = true;
   scrollerArea.style.visibility = 'visible';
  }
  /*移动过程中*/
  function moveIn(e) {
   if (flg) {
    stop(e);
    if (e.touches)
     e = e.touches[0];
    move = e.clientY - startY + parseInt(startTop);
    if (move > tMove) {
     (move - tMove) / tslow + tMove > tMoveL ? move = tMoveL : move = (move - tMove) / tslow + tMove
    } else if (move < bMove)
     (move - bMove) / tslow + bMove < bMoveL ? move = bMoveL : move = (move - bMove) / tslow + bMove;
    target.style.top = move + 'px';
    scroller.style.top = -move / st + 'px';
    //惯性缓动
    var nowTime = new Date().getTime();
    stopInertiaMove = true;
    if (nowTime - lastMoveTime > 300) {
     lastMoveTime = nowTime;
     lastMoveStart = e.clientY;
    }
   }
  }
  /*移动结束*/
  function moveEnd(e) {
   stop(e);
   if (e.touches)
    e = e.touches[0];
   //惯性缓动
   var contentTop = target.style.top.replace('px', '');
   var contentY = (parseInt(contentTop) + e.clientY - lastMoveStart);
   var nowTime = new Date().getTime();
   var v = (e.clientY - lastMoveStart) / (nowTime - lastMoveTime);
   //最后一段时间手指划动速度
   stopInertiaMove = false;
   (function(v, startTime, contentY) {
    var dir = v > 0 ? -1 : 1;
    //加速度方向
    var deceleration = dir * 0.005;
    function inertiaMove() {
     if (stopInertiaMove)
      return;
     var nowTime = new Date().getTime();
     var t = nowTime - startTime;
     var nowV = v + t * deceleration;
     var moveY = (v + nowV) / 2 * t;
     // 速度方向变化表示速度达到0了
     if (dir * nowV > 0) {
      if (move > tMove) {
       callbackfn('到顶了');
       target.style.top = tMove + 'px';
       scroller.style.top = tMove + 'px';
      } else if (move < bMove) {
       callbackfn('到底了');
       target.style.top = bMove + 'px';
       scroller.style.top = -bMove / st + 'px';
      }
      setTimeout(function() {
       if (!stopInertiaMove)
        scrollerArea.style.visibility = 'hidden';
      }, 4000);
      return;
     }
     move = contentY + moveY;
     if (move > tMove) {
      t /= 20;
      move = (move - tMove) / 10 + tMove;
     } else if (move < bMove) {
      t /= 20;
      move = (move - bMove) / 10 + bMove;
     }
     target.style.top = move + "px";
     scroller.style.top = -move / st + 'px';
     setTimeout(inertiaMove, 10);
    }
    inertiaMove();
   })(v, nowTime, contentY);
   move = 0;
   flg = false;
  }
  //操作结束
  /**
   *相关初始化
   */
  //滚动条长度初始化
  scroller.style.height = sheight + 'px';
  //初始化结束
 },
 otherInteract : function() {
  //其他功能扩充
 }
}

IE hack css

body,html {background-color:#333; margin: 0; height: 100%; line-height: 2.0; font-family: 'Microsoft YaHei'; overflow-y:hidden;}
#contain{margin: 0 auto; position:relative; width: 100%; max-width: 480px; _width: 480px; height: 100%; cursor: pointer !important;}
#appArea{position: absolute; width: 100%; height: 100%; overflow: hidden;  background-color: #fff;}  
#topInfo{position: absolute;top: 60px;width: 100%; height:60px; text-align: center; font-size: 18px; }
#bottomInfo{position: absolute;bottom: 0;width: 100%;}
#scrollerArea{position: absolute; right: 0; width: 1.5%; height: 100%;visibility: hidden;}
#scroller{position: absolute; top:0; width: 100%;  background-color: #aaa;}
#moveArea{position: absolute; top:0px; width: 100%; background-color: #ddd;}

HTML代码

<!DOCTYPE html>
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
  <link type="text/css" href="css/main.css" rel="stylesheet">
  <title>滑动回弹</title>
  <!--[if lt IE 9]>      <![endif]-->
  <noscript></noscript>
 </head>
 <body>
  <div id="contain">
   <div id="appArea">
    <div id="topInfo">
     logo or animate
    </div>
    <div id="bottomInfo">
     some imformation  2014-4-28
    </div>
    <div id="moveArea"></div>
    <div id="scrollerArea">
     <div id="scroller"></div>
    </div>
   </div>
  </div>
  <script src="js/main.js"></script>
 </body>
</html>
Javascript 相关文章推荐
fancybox1.3.1 基于Jquery的插件在IE中图片显示问题
Oct 01 Javascript
js取滚动条的尺寸的函数代码
Nov 30 Javascript
让网页跳转到指定位置的jquery代码非书签
Sep 06 Javascript
jQuery中has()方法用法实例
Jan 06 Javascript
js跨浏览器的事件侦听器和事件对象的使用方法
Dec 17 Javascript
详述JavaScript实现继承的几种方式(推荐)
Mar 22 Javascript
protractor的安装与基本使用教程
Jul 07 Javascript
微信小程序商品详情页的底部弹出框效果
Nov 16 Javascript
scrapyd schedule.json setting 传入多个值问题
Aug 07 Javascript
微信小程序 导入图标实现过程详解
Oct 11 Javascript
解决Vue中的生命周期beforeDestory不触发的问题
Jul 21 Javascript
ElementUI 修改默认样式的几种办法(小结)
Jul 29 Javascript
一些老手都不一定知道的JavaScript技巧
May 06 #Javascript
jQuery中的$.ajax()方法应用
May 06 #Javascript
jquery判断元素是否隐藏的多种方法
May 06 #Javascript
JQuery调用WebServices的方法和4个实例
May 06 #Javascript
通过JQuery将DIV的滚动条滚动到指定的位置方便自动定位
May 05 #Javascript
JQuery以JSON方式提交数据到服务端示例代码
May 05 #Javascript
使用jQuery重置(reset)表单的方法
May 05 #Javascript
You might like
这东西价格,可以买几台TECSUN S-2000
2021/03/02 无线电
让PHP开发者事半功倍的十大技巧小结
2010/04/20 PHP
php 文章调用类代码
2011/08/11 PHP
PHP中PDO的错误处理
2011/09/04 PHP
PHP标准库 (SPL)――Countable用法示例
2020/06/05 PHP
javascript document.images实例
2008/05/27 Javascript
js 跨域和ajax 跨域问题小结
2009/07/01 Javascript
学习ExtJS form布局
2009/10/08 Javascript
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
jQuery实现的Email中的收件人效果(按del键删除)
2011/03/20 Javascript
js树插件zTree获取所有选中节点数据的方法
2015/01/28 Javascript
jQuery实现切换页面过渡动画效果
2015/10/29 Javascript
基于Javascript实现弹出页面效果
2016/01/01 Javascript
jquery 判断是否支持Placeholder属性的方法
2017/02/07 Javascript
node.js 利用流实现读写同步,边读边写的方法
2017/09/11 Javascript
Nodejs模块载入运行原理
2018/02/23 NodeJs
在vue-cli的组件模板里使用font-awesome的两种方法
2018/09/28 Javascript
小程序实现投票进度条
2019/11/20 Javascript
微信小程序实现下滑到底部自动翻页功能
2020/03/07 Javascript
在vue中使用eslint,配合vscode的操作
2020/11/09 Javascript
python 运算符 供重载参考
2009/06/11 Python
python模块之sys模块和序列化模块(实例讲解)
2017/09/13 Python
numpy.delete删除一列或多列的方法
2018/04/03 Python
python爬取指定微信公众号文章
2018/12/20 Python
Django 重写用户模型的实现
2019/07/29 Python
python实现简单图书管理系统
2019/11/22 Python
python 伯努利分布详解
2020/02/25 Python
Python猜数字算法题详解
2020/03/01 Python
Django多个app urls配置代码实例
2020/11/26 Python
解决Pymongo insert时会自动添加_id的问题
2020/12/05 Python
python自动化办公操作PPT的实现
2021/02/05 Python
Html5新增标签有哪些
2017/04/13 HTML / CSS
详解HTML5 Canvas标签及基本使用
2020/01/10 HTML / CSS
大专生的学习自我评价
2013/12/04 职场文书
计生办班子群众路线教育实践活动个人对照检查材料思想汇报
2014/10/04 职场文书
2015年党建工作总结
2015/03/30 职场文书