今天想说的是如何本身操刀作一个js的下拉刷新(js + h5 + css3)。既然是下拉,那么应用场景固然就是在手持设备上。在JavaScript的世界里,老是跟不少实用又华丽丽的效果接轨,这是一门颇有色彩的编程语言。目前网络上也有不少很是优秀的js滑动插件,好比iscroll(最开始咱们就是用这款插件,真心很好用,并且解决了不少html的问题)。固然,我要讲的彻底没办法和iscroll媲美,仅仅是简简单单的一角而已,主要目的在于对这点小知识的总结和分享。javascript
以前也有讲过,移动设备上对CSS3和Html5的支持至关的不错,并且使用Css3咱们能够轻松的实现滑动效果,不只不用担忧性能问题,并且效果上也是无可挑剔的。那么究竟须要作成什么样的效果呢?css
效果?嘿嘿,固然是相似淘宝那样的。html
(这里是用chrome模拟iphone5上的效果,关于如何模拟 这里 有讲过的,再也不赘述。)前端
当往下拖动页面的时候出现红色箭头所指向的灰色区域,随着往下拖动的节奏,橘黄色的圈不断的被填满,而后停顿几秒页面刷新(不太明白的话就本身试试吧)。 额额,但是楼上的图片貌似不是很适合作分析。下面以一个极为粗糙的页面作整个思路分析。java
布局很重要!jquery
整个过程当中,布局是决定编码难度及js代码量的重要因素,科学的布局能够带来飞通常的感受(固然,不一样的效果布局上有所不一样也是正常的)。css3
查看粗制滥造的在线Demo 请戳这里web
图1 所展现的是整个须要滑动的页面的布局结构。整个布局使用的是一个div(蓝色框部分)里包含 加载数据的提示部分(简称“提示部分”)(红色框部分) 和须要刷新的内容部分(简称“内容部分”)(文字部分)两个div的结构。若是外层div向下移动,那么里面的提示部分和内容部分天然就跟着向下移动了(这样是否是比同时使用js去控制两个元素上下移动简单多了?)。ajax
图2 所展现的是正常的内容页面(滑动完成以后,也是滑动以前的效果),布局上主要是利用css3的transform属性控制提示部分的隐藏和显示。当translateY为负时,整个div向上移动(图2的效果),为0时,整个提示部分就彻底展现出来(图1的效果)。chrome
对于上面的描述若是没看懂也别再看了(正在努力突破自我表达极限)。直接上代码:
<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>test</title> </head> <body style="background-color: beige;"> <div id="container" style="width:100%;border:solid 1px blue; transform:translate(0px,-61px)"> <div style="height:50px; line-height:50px; text-align:center; width:100%; border:solid 1px red;"> 努力加载中... </div> <div style="width:100%; line-height:30px;background-color:#F2F2F2; font-size:17px; font-family:'Adobe Garamond Pro'"> JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,普遍用于客户端的脚本语言,最先是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增长动态功能。 在1995年时,由Netscape公司的Brendan Eich,在网景导航者浏览器上首次设计实现而成。由于Netscape与Sun合做,Netscape管理层但愿它外观看起来像Java,所以取名为JavaScript。但实际上它的语法风格与Self及Scheme较为接近。[1] 为了取得技术优点,微软推出了JScript,CEnvi推出ScriptEase,与JavaScript一样可在浏览器上运行。为了统一规格,由于JavaScript兼容于ECMA标准,所以也称为ECMAScript。 JavaScript是一种属于网络的脚本语言,已经被普遍用于Web应用开发,经常使用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。一般JavaScript脚本是经过嵌入在HTML中来实现自身的功能的。[3] 是一种解释性脚本语言(代码不进行预编译)。[4] 主要用来向HTML(标准通用标记语言下的一个应用)页面添加交互行为。[4] 能够直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。[4] 跨平台特性,在绝大多数浏览器的支持下,能够在多种平台下运行(如Windows、Linux、Mac、Android、iOS等)。 Javascript脚本语言同其余语言同样,有它自身的基本数据类型,表达式和算术运算符及程序的基本程序框架。Javascript提供了四种基本的数据类型和两种特殊数据类型用来处理数据和文字。而变量提供存放信息的地方,表达式则能够完成较复杂的信息处理。[5] </div> </div> </body> </html> <!--JQuery是那么的好用,这种状况下怎么能没有它呢!--> <script type="text/javascript" src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
布局上大体就是这样的结构,那么~
JavaScript该作什么呢?
一、根据滑动轨迹动态调整滑块位置(transfrom=>translate);
二、根据滑动的距离判断是否执行刷新(或数据加载)。
固然,若是滑动结束后使用ajax从新加载页面数据,还将涉及到一个页面向上滑动并隐藏提示部分的效果。
大体思路:
(前提条件:当前元素已滑动至顶部)
一、当鼠标左键按下(移动设备上的touchstart事件)的时候记录下当前鼠标位置的 Y轴坐标;
二、当鼠标移动的时候(touchmove事件),记录下鼠标的Y 轴坐标判断滑动轨迹并进行相应的滑块移动;
三、当鼠标左键松开(touchend事件)的时候,经过对比鼠标开始和结束的Y轴坐标的距离判断是否应该刷新页面(或从新加载数据)。
亮代码,秀画风:
/* *obj--滑动对象 *offset--滑动距离(当滑动距离大于等于offset时将调用callback) *callback--滑动完成后的回调函数 */ var slide = function (obj, offset, callback) { var start, end, isLock = false,//是否锁定整个操做 isCanDo = false,//是否移动滑块 isTouchPad = (/hp-tablet/gi).test(navigator.appVersion), hasTouch = 'ontouchstart' in window && !isTouchPad; //将对象转换为jquery的对象 obj = $(obj); var objparent = obj.parent(); /*操做方法*/ var fn = { //移动容器 translate: function (diff) { obj.css({ "-webkit-transform": "translate(0," + diff + "px)", "transform": "translate(0," + diff + "px)" }); }, //设置效果时间 setTranslition: function (time) { obj.css({ "-webkit-transition": "all " + time + "s", "transition": "all " + time + "s" }); }, //返回到初始位置 back: function () { fn.translate(0 - offset); //标识操做完成 isLock = false; } }; //滑动开始 obj.bind("touchstart", function (e) { if (objparent.scrollTop() <= 0 && !isLock) { var even = typeof event == "undefined" ? e : event; //标识操做进行中 isLock = true; isCanDo = true; //保存当前鼠标Y坐标 start = hasTouch ? even.touches[0].pageY : even.pageY; //消除滑块动画时间 fn.setTranslition(0); } }); //滑动中 obj.bind("touchmove", function (e) { if (objparent.scrollTop() <= 0 && isCanDo) { var even = typeof event == "undefined" ? e : event; //保存当前鼠标Y坐标 end = hasTouch ? even.touches[0].pageY : even.pageY; if (start < end) { even.preventDefault(); //消除滑块动画时间 fn.setTranslition(0); //移动滑块 fn.translate(end - start - offset); } } }); //滑动结束 obj.bind("touchend", function (e) { if (isCanDo) { isCanDo = false; //判断滑动距离是否大于等于指定值 if (end - start >= offset) { //设置滑块回弹时间 fn.setTranslition(1); //保留提示部分 fn.translate(0); //执行回调函数 if (typeof callback == "function") { callback.call(fn, e); } } else { //返回初始状态 fn.back(); } } }); }
代码分析:
一、参数:obj,要滑动的对象;offset,提示部分的transform的值(代码中是 transform:translate(0px,-61px) ,那么这里就是61);callback,回调函数,在下拉完成后调用的函数(页面刷新或数据加载)。
二、为何是transform不是margin?
由于transform不会引发重绘,相比margin更流畅,性能更好。可是transfrom有个比较好玩的地方,若是translateY的值为负数(当前元素上移xx像素)下方元素不会跟着上移(margin会上移),在这点上它和margin是有区别的。 注意,这里的-webkit-transform的存在是有必要的,由于有些浏览器识别不了transform,好比微信内置浏览(个人手机上是这样的)。为了兼容性,多扣几个字母是值得的。
三、关于transition设置为0s。
为何要在touchstart的时候把transition的值设置为0秒呢?transition的做用是为元素属性的变化添加过渡效果,例如一个框变大,咱们设置为transition为1s,那么这个框就是在1s内变大到指定大小。第一个参数表示设置过渡效果的 CSS 属性的名称(如:margin,transform;all表示全部),第二个参数表示过渡的时间。 代码中设置transition的目的是在于滑动结束后(手指离开屏幕)为滑块回弹添加过渡效果,这样看上去就不会那么突兀。固然,这个过渡效果一样会应用到数据加载完成后提示部分的隐藏上。设置为0是为了取消在滑动过程当中的滑块过渡效果,咱们手指往下滑动的时候,滑块会跟这向下移动,这样就有了滑动滑块的效果。若是这个时候不取消transition就会出现滑块抖动的效果(嘿嘿,有兴趣的话能够试试这种感受。)。整个过程当中transition是至关重要的。
四、关于isLock和isCanDo.
这两个变量的做用在于防止二次滑动,在第一次滑动后数据加载完成以前不容许有第二次的滑动。当滑动开始的时候讲isLock和isCanDo都设置为True,表示容许后面两个事件里的代码能够正常运行,当滑动结束后isCanDo设置为false表示在isLock被设置为True以前(整个操做完成以前)全部的事件代码均不可用(不执行下拉数据加载等相关动做)。
五、如何使用?
这个比较就简单,但也比较重要。
$(function () { slide("#container", 61, function (e) { var that = this; setTimeout(function () { that.back.call(); }, 2000); }); });
代码中的setTimeout是用于模拟ajax加载数据的效果,加载数据这部分就没有再单独写过了。JavaScript的回调函数是用着最顺手的特性之一。这里在数据加载完成后须要调用一个back方法,这个方法目的就是重置slide里的各类状态。关于这种传来传去的方式给人的感受有点像作地下工做,不太容易被发现,可暂时也没有想到更好的解决方案。
最后:
若是各位有什么好的方法或想法,欢迎你们在楼下@我☺。