使用原生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 相关文章推荐
JQuery 动态扩展对象之另类视角
May 25 Javascript
基于jquery的返回顶部效果(兼容IE6)
Jan 17 Javascript
javascript椭圆旋转相册实现代码
Jan 16 Javascript
jQuery学习笔记 操作jQuery对象 CSS处理
Sep 19 Javascript
css3元素简单的闪烁效果实现(html5 jquery)
Dec 28 Javascript
JavaScript字符串删除重复字符的方法
Dec 25 Javascript
基于jQuery实现二级下拉菜单效果
Feb 01 Javascript
js动态生成form 并用ajax方式提交的实现方法
Sep 09 Javascript
深入理解Commonjs规范及Node模块实现
May 17 Javascript
jQuery实现的上传图片本地预览效果简单示例
Mar 29 jQuery
详解node Async/Await 更好的异步编程解决方案
May 10 Javascript
一些手写JavaScript常用的函数汇总
Apr 16 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
用PHP调用Oracle存储过程
2006/10/09 PHP
PHPMyadmin 配置文件详解(配置)
2009/12/03 PHP
php图片加中文水印实现代码分享
2012/10/31 PHP
PHP设计模式之解释器模式的深入解析
2013/06/13 PHP
php利用新浪接口查询ip获取地理位置示例
2014/01/20 PHP
浅谈php函数serialize()与unserialize()的使用方法
2014/08/19 PHP
php获取四位字母和数字的随机数的实现方法
2015/01/09 PHP
php查询mysql大量数据造成内存不足的解决方法
2015/03/04 PHP
PHP获取远程图片并保存到本地的方法
2015/05/12 PHP
详解PHP的Yii框架中自带的前端资源包的使用
2016/03/31 PHP
PHP基于curl post实现发送url及相关中文乱码问题解决方法
2017/11/25 PHP
PHP多进程通信-消息队列使用
2019/03/08 PHP
php数组遍历类与用法示例
2019/05/24 PHP
javascript 多种搜索引擎集成的页面实现代码
2010/01/02 Javascript
JavaScript下利用fso判断文件是否存在的代码
2010/12/11 Javascript
jquery实现每个数字上都带进度条的幻灯片
2013/02/20 Javascript
js函数名与form表单元素同名冲突的问题
2014/03/07 Javascript
iframe如何动态创建及释放其所占内存
2014/09/03 Javascript
Javascript基础教程之变量
2015/01/18 Javascript
jquery实现带缩略图的可定制高度画廊效果(5种)
2015/08/28 Javascript
通过隐藏iframe实现无刷新上传文件操作
2016/03/16 Javascript
使用nodejs中httpProxy代理时候出现404异常的解决方法
2016/08/15 NodeJs
jQuery实现两列等高并自适应高度
2016/12/22 Javascript
详解nodejs 文本操作模块-fs模块(三)
2016/12/22 NodeJs
angularjs中ng-attr的用法详解
2016/12/31 Javascript
TypeScript入门-基本数据类型
2017/03/28 Javascript
微信小程序报错:this.setData is not a function的解决办法
2017/09/27 Javascript
angular动态表单制作
2018/02/23 Javascript
OpenLayers3实现测量功能
2020/09/25 Javascript
python 遍历目录(包括子目录)下所有文件的实例
2018/07/11 Python
python pyenv多版本管理工具的使用
2019/12/23 Python
管道维修工岗位职责
2013/12/27 职场文书
社区八一活动方案
2014/02/03 职场文书
服装设计专业自荐信
2014/06/17 职场文书
高中班主任心得体会
2016/01/07 职场文书
公文写作:新员工转正申请书范本3篇!
2019/08/07 职场文书