现在手机端的滑动都是自己重写带惯性欢动的,首先要做这样的效果原生的css属性貌似不太兼容,只能用代码自己来实现。
那么问题来了!技术窃取哪家强,我们一起上58同城,看看他们怎么写的!
上58源代码 http://j1.58cdn.com.cn/m58/m3/js/m5.list.js
HTML代码结构
//这个方法就是实现滑动的代码
conSwipe: function (obj) { var _this = this; var $ul = obj.find("ul");
//很明显这里是UL在作为容器使其滑动,ul外面的盒子(以下简称盒子)固定大小使其内容超出就隐藏,从而达到让ul在他的里面滚动
//首先给ul帮定4个事件,touchstart,touchmove,touchend,transitionend
· //文章下面有触摸事件的知识 $ul.on("touchstart", //当手指触摸到屏幕的时候 function (e) {
//记录触摸点相对于屏幕的垂直位置 this.startY = e.targetTouches[0].screenY; this.startTop = this.y || 0; this.startTime = event.timeStamp;
//是否滚动的标识 this.moved = false;
//获取到这个UL父级的盒子内容高度 this.wrapH = $(this).parents(".f_box_inner")[0].offsetHeight; //应该和$(this).parent().height()一样
//可以理解为能滚动的最大距离,那最大距离是ul外面的盒子大小减去ul内容的高度(其实能滑动的距离就是ul内容的高度然后减去这个盒子的高度) if (!this.maxScrollY) {
//记录ul的内容高度 this.scrollerHeight = this.offsetHeight; //这里应该是解决浏览器兼容问题,把scrollerHeight和offsetHeight设置成相同值 this.maxScrollY = this.wrapH - this.scrollerHeight + 1 } //盒子的高度减去ul下面所有的li总数的高度,ul下面所有li总数高度和ul的scrollHeight的值差不多,这样只是更加精确 this._height = this._height || $(this).parent().height() - $(this).find("li").height() * $(this).find("li").length + 1;
//是不是在滑动 if (this.isInTransition) {
//getComputedStyle的意思是得到指定节点元素的所有style属性值 var matrix = window.getComputedStyle(this, null); matrix = matrix["webkitTransform"].split(")")[0].split(", ");
//这里的意思是得到 ul的translate3d里面的垂直属性值 如:translate3d(0px, -43px, 0px) 得到-43这个ul滑动的距离,其实这个值和$(this)position().top一样 this.y = matrix[13] || matrix[5]; this.y = Math.round(this.y); this.startTop = Math.round(this.y);
//上面可以直接用 $(this).find('ul').css('-webkit-transform')得到值为什么还用getComputedStyle? 2个值都是一样的为什么要重新赋值 $(this).css({ "-webkit-transform": "translate3d(0," + this.y + "px, 0)", "-webkit-transition-duration": "0" }); //是否到了惯性阶 this.isInTransition = false } }); $ul.on("touchmove",//手指移动的时候 function (e) { e.preventDefault(); e.stopPropagation();
//以上2行代码可以理解为在滑动ul的时候禁止屏幕body区域跟着滚动 this.moved = true;
//更新ul滑动的距离=最近1次2个点的screenY 的差加上之前已经滑动过的距离 this.y = e.targetTouches[0].screenY - this.startY + this.startTop;
//如果滑动的距离大于0(上面已经滑到顶了),或者小于能够滑动的最大长度(下滑到底了) if (this.y > 0 || this.y < this.maxScrollY) {
//这个if里面的意思琢磨了半天才明白他的用意,
//滑动过程中正常情况下内容滑动的距离等于手指在上面移动的距离,但是当滑动超出内容的大小的时候滑动的距离就要小于手指移动的距离,造成一种拉不动的效果 var newY = this.y - (e.targetTouches[0].screenY - this.startY) * 2 / 3; this.y = this.y > 0 ? 0 : this.maxScrollY; if (newY > 0 || newY < this.maxScrollY) { this.y = newY } } $(this).css({ "-webkit-transform": "translate3d(0," + this.y + "px, 0)", "-webkit-transition-duration": "0" }); this.isInTransition = false;
//这是从点上去到滑动过程中所运行的时间,如果时间很短就不要执行惯性动作,因为会影响上面的元素的点击事件,如果超过了300毫秒就重新计算值 var timeStamp = event.timeStamp; if (timeStamp - this.startTime > 300) { this.startTime = timeStamp; this.startY = e.targetTouches[0].screenY; this.startTop = this.y } }); $ul.on("touchend",//当手指离开的时候 function (e) {
//注意手指离开的时候已经没有targetTouches属性了,要用changedTouches var dist = e.changedTouches[0].screenY - this.startY;//这个值应该基本上非常小 this.endTime = event.timeStamp; var duration = this.endTime - this.startTime; if (this.moved) { e.preventDefault(); e.stopPropagation(); var newY = Math.round(e.changedTouches[0].screenY); this.isInTransition = true;
//超出内容范围的惯性移动 if (this.y > 0 || this.y < this.maxScrollY) {
(ul,滑动的距离,最大能滑动的距离,?) _this.scrollTo(this, this.y, this.maxScrollY, 完成动画的时间); return } //时间越小惯性越大 if (duration < 300) {
//calculateMoment 这个方法下次更新的时候在分析, var move = _this.calculateMoment(this.y, this.startTop, duration, this.maxScrollY, this.wrapH); this.y = move.destination; var time = move.duration; $(this).css({ "-webkit-transform": "translate3d(0, " + this.y + "px, 0)", "transition-timing-function": "cubic-bezier(0.1, 0.3, 0.5, 1)", "-webkit-transition-duration": time + "ms" }) } return } }); $ul.on("transitionend", function () { this.isInTransition = false; _this.scrollTo(this, this.y, this.maxScrollY, 600) }) },
(ul,滑动的距离,最大能滑动的距离,完成时间) scrollTo: function (obj, y, maxY, time) { if (y > 0 || maxY > 0) { y = 0 } else if (y < maxY) { y = maxY } //以上代码的意思理解为ul距离上面的距离 translate3d(0px, Y, 0px) 就是这个Y的值 obj.isInTransition = true;
///css3 transition这是个过程效果 实现惯性滑动 $(obj).css({ "-webkit-transform": "translate3d(0, " + y + "px, 0)", "transition-timing-function": "cubic-bezier(0.25, 0.46, 0.45, 0.94)", "-webkit-transition-duration": time + "ms" }) }
, calculateMoment: function (current, start, time, lowerMargin, wrapperSize) { var distance = current - start, speed = Math.abs(distance) / time, destination, duration; deceleration = 6e-4; destination = current + speed * speed / (2 * deceleration) * (distance < 0 ? -1 : 1); duration = speed / deceleration; if (destination < lowerMargin) { destination = wrapperSize ? lowerMargin - wrapperSize / 2.5 * (speed / 8) : lowerMargin; distance = Math.abs(destination - current); duration = distance / speed } else if (destination > 0) { destination = wrapperSize ? wrapperSize / 2.5 * (speed / 8) : 0; distance = Math.abs(current) + destination; duration = distance / speed } return { destination: Math.round(destination), duration: duration } }, close: function (e) { e.preventDefault(); e.stopPropagation(); this.mask.hide(); this.box.addClass("hide"); this.nav.find("li").removeClass("select"); this.isShow = false; if ($(window).scrollTop() < this._top) { $("body").removeClass("filter-fixed") } }
如果有不懂的或者好建议可以加专用qq群一起探讨 86594082
移动互联网终端的touch事件,touchstart, touchend, touchmove
http://www.css119.com/archives/1629