移动端滑屏 touch事件

移动端触屏滑动的效果的效果在电子设备上已经被应用的越来越广泛,类似于PC端的图片轮播,但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件。处理touch事件能跟踪到屏幕滑动的每根手指。

以下是四种touch事件

touchstart: //触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
touchmove: //在屏幕上滑动时连续的触发。在这个事件发生期间,调用preventDefault()可阻止滚动。
touchend: //从屏幕上移开时触发。
touchcancel: //系统取消touch事件的时候触发,这个好像比较少用。
上面这几个事件都会冒泡,也都可以取消。虽然这些触摸事件没有在DOM规范中定义,但它们却是以兼容DOM的方式实现的。因此,每个触摸事件没有在DOM规范中定义,但它们却是以兼容DOM的方式实现的。因此,每个触摸事件的event对象都提供了在鼠标事件中常见的属性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey和metaKey。

每个触摸事件被触发后,会生成一个event对象,event对象里额外包括以下三个触摸列表。
touches://表示当前跟踪的触摸操作的touch对象的数组。
当一个手指在触屏上时,event.touches.length=1,
当两个手指在触屏上时,event.touches.length=2,以此类推。
targetTouches://特定于事件目标的touch对象数组。因为touch事件是会冒泡的,所以利用这个属性指出目标对象。
changedTouches://表示自上次触摸以来发生了什么改变的touch对象的数组。

这些列表里的每次触摸由touch对象组成,touch对象里包含着触摸信息,主要属性如下:
clientX://触摸目标在视口中的x坐标。
clientY://触摸目标在视口中的y坐标。
identifier://标识触摸的唯一ID。
pageX://触摸目标在页面中的x坐标。
pageY://触摸目标在页面中的y坐标。
screenX://触摸目标在屏幕中的x坐标。
screenY://触摸目标在屏幕中的y坐标。
target://触摸的DOM节点目标。

注意事项:

手指在滑动整个屏幕时,会影响浏览器的行为,比如滚动和缩放。所以在调用touch事件时,要注意禁止缩放和滚动。

1.禁止缩放

通过meta元标签来设置。

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,minimum-scale=1,user-scalable=no">

加上这句代码后,我们编写的页面将不会随着用的手势而放大缩小。

2.禁止滚动

preventDefault是阻止默认行为,touch事件的默认行为就是滚动。
由于触摸会导致屏幕动来动去,所以可以会在这些事件的事件处理函数内使用event.preventDefault(),来阻止屏幕的默认滚动。

这里写的demo的使用的方法是将HTML结构写好后往里传参就可以了。它接受所有滑动页面对象(在这里是document.querySelector('#pages') ) 和要设定的方向(用X,Y表示横向或者纵向)以及一个可选的扩展函数。

纵向滑屏案例
这里将所有的代码都封装进一个PageSlide的原型对象中,可以当成原生JS插件来使用,

它所要求的HTML的结构为

 
 

<div class="pages">
<div class="page page1">page1</div>
<div class="page page2">page2<div class="myAnimation"></div></div>
<div class="page page3">page3</div>
<div class="page page4">page4</div>
<div class="page page5">page5</div>
<div class="page page6">page6</div>
</div>

 
 

CSS样式结构为

/* 注意加html标签,使得高度100%等于视窗高度 */
html,body{ width:100%; height:100%; margin:0; padding:0; overflow:hidden; }

/*滑动页面的统一样式 */
.pages{ width: 100%; height: 100%; position: relative; }
.page { font-size:100px; position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; }

.page1{background:pink;}
.page2{background:lightgreen;}
.page3{background:skyblue;}
.page4{background:red;}
.page5{background:green;}
.page6{background:blue;}

/* the box 动画 */
.box{ width:100px; height:100px; background:black; }

/* 所有动画使用类控制 */
.play .myAnimation{ animation:move 1s ease 1 both; -webkit-animation: move 1s ease 1 both; }
@-webkit-keyframes move{
 100%{
   -webkit-transform:translate3d(150px,0,0);
   transform:translate3d(150px,0,0);
   -ms-transform: translate3d(150px,0,0);
 }
}

要实现手指跟随的滑动效果, 关键在于通过touch事件来设置transform:translate3d(x,y,z)的参数,并在滑动结束(touchend)设置一个最小滑动距离minRange,该距离范围内的滑动,translate3d的参数等于touchmove的滑动距离,当大于minRange时, 则触发下一页(或上一页)的整体滑动,translate3d的X或Y的参数也就是视窗的宽(横向滑动时)或者高(纵向滑动时)。

另外,对于一个网页单页,还需要解决一个问题,即每个页面中可能有动画或者其他的事件需要在该页面出现时才开始播放,动画采用css类控制, 这里采用在每个当前页面中添加一个.play的类作为标记, 在每个页面的CSS动画设置中,同样加上.play类名,这样就实现了当页面出现才开始播放本页动画的功能。

JavaScript的代码如下

// PageSlide接收三个参数:页面元素,要设定的滑动方向,可选的扩展函数

var PageSlide = function(el, swipe, options) {

this.options = options || {}; //可选函数

this.current = 0;  //当前页面索引

this.pageX;  //横向的手指落点

this.pageY;  //纵向的手指落点

this.height; //设备高度

this.width;  //设备宽度

this.flag;  //判断滑动方向的变量

this.move;  //滑动的距离

this.$el = el; //当前页面的对象

this.swipe = swipe || 'X'; //滑动方向参数

this.resize().init().bindEvents(); //初始化

}

PageSlide.prototype.init = function(i) {

var current = i ? this.$el.children[i] : this.$el.firstElementChild;

if (!current) throw 'ERROR';

//moving类名作为当前滑动页面的标记,也在样式中作滑动的扩展效果

current.classList.add('moving');

current.style.webkitTransform = 'translate3d(0,0,0)';

//以swipe的值预设置其他页面的宽高,获得流畅的交互效果

for(var i = 1; i <this.$el.children.length ; i++){

this['set' + this.swipe](this.$el.children[i],  (this.swipe === 'X' ? this.width : this.height))

};

setTimeout(function() {

current.classList.remove('moving')

current.classList.add('play')

}, 3e2);

return this

};

//为页面绑定各种事件的绑定函数

PageSlide.prototype.bindEvents = function() {

var self = this;

window.addEventListener('resize orientationchange', this.resize.bind(this), false);

'touchstart touchmove touchend touchcancel'.split(' ').forEach(function(evn) {

//将四个触控函数(申明在后面)绑定到每个页面

self.$el.addEventListener(evn, self[evn].bind(self), false);

});

}

//获得当前触控的页面对象

PageSlide.prototype.getCurrent = function() {

return this.$el.children[this.current];

};

//初始化时获得设备的宽高

PageSlide.prototype.resize = function() {

this.width = this.$el.parentNode.clientWidth;

this.height = this.$el.parentNode.clientHeight;

return this;

};

//到达任意页面的random()方法

PageSlide.prototype.random = function() {

var count = this.$el.children.length;

var current = this.current;

var arr = [];

var num;

for (var i = 0; i < count; i++) {

if (i !== current) arr.push(i.toString())

};

num = Math.floor(Math.random() * arr.length);

this.direct(+arr[num]);

}

// 四个内建的滑动事件函数,与前面绑定函数相呼应

PageSlide.prototype.touchstart = function(e) {

var touches = e.touches[0];

//触控开始

this.flag = null;

this.move = 0;

//记录落点

this.pageX = touches.pageX;

this.pageY = touches.pageY;

};

PageSlide.prototype.touchmove = function(e) {

var touches = e.touches[0];;

var X = touches.pageX - this.pageX;

var Y = touches.pageY - this.pageY;

var current = this.getCurrent();

var next = current.nextElementSibling;

var prev = current.previousElementSibling;

//添加移动样式

if (!this.flag) {

this.flag = Math.abs(X) > Math.abs(Y) ? 'X' : 'Y';

if (this.flag === this.swipe) {

current.classList.add('moving');

next && next.classList.add('moving');

prev && prev.classList.add('moving');

};

};

if (this.flag === this.swipe) {

e.preventDefault();

e.stopPropagation();

switch (this.swipe) {

case 'X':

//swipe horizontal

this.move = X;

this.setX(current, X);

next && (this.setX(next, X + this.width));

prev && (this.setX(prev, X - this.width));

break;

case 'Y':

//swipe vertical

this.move = Y;

this.setY(current, Y);

next && (this.setY(next, Y + this.height));

prev && (this.setY(prev, Y - this.height));

break;

}

}

}

PageSlide.prototype.touchend = function(e) {

var minRange = 50;

var move = this.move;

var current = this.getCurrent();

var next = current.nextElementSibling;

var prev = current.previousElementSibling;

current.classList.remove('moving');

next && next.classList.remove('moving');

prev && prev.classList.remove('moving');

if (!this.flag) return;

e.preventDefault();

//滑动结束前往下一页面,next()方法调用了go()方法

if (move < -minRange && next) return this.next();

if (move > minRange && prev) return this.prev();

this.reset();

}

PageSlide.prototype.touchcancel = function(e) {

var current = this.getCurrent();

var next = current.nextElementSibling;

var prev = current.previousElementSibling;

current.classList.remove('moving');

next && next.classList.remove('moving');

prev && prev.classList.remove('moving');

this.reset();

}

//动态设定translate3d参数方法

PageSlide.prototype.setX = function(el, x, unit) {

el && (el.style.webkitTransform = 'translate3d(' + x + (unit || 'px') + ',0,0)');

};

PageSlide.prototype.setY = function(el, y, unit) {

el && (el.style.webkitTransform = 'translate3d(0,' + y + (unit || 'px') + ',0)');

};

//设置当前触控页面translate3d参数为0的方法

PageSlide.prototype.setCurrent = function(el, i) {

el && (el.style.webkitTransform = 'translate3d(0,0,0)');

if (i) {

this.current = i;

this.$current = this.$el.children[i];

}

}

//调用go()方法前往下一或上一页面

PageSlide.prototype.next = function() {

this.go(this.current + 1);

};

PageSlide.prototype.prev = function() {

this.go(this.current - 1);

};

//重置方法,用于初始化以及当前页面的重置

PageSlide.prototype.reset = function() {

var width = this.width;

var height = this.height;

var swipe = this.swipe;

var current = this.getCurrent();

var prev = current.previousElementSibling;

var next = current.nextElementSibling;

this.setCurrent(current);

prev && (this['set' + swipe](prev, -(swipe === 'X' ? width : height)));

next && (this['set' + swipe](next, swipe === 'X' ? width : height));

}

//去往下一或上一页面的go方法

PageSlide.prototype.go = function(i) {

var onFinish = this.options.onFinish;

var current = this.getCurrent();

var total = this.$el.childElementCount;

var target = this.$el.children[i];

var d = i < this.current ? -1 : 1;

if (i === this.current || i < 0 || i >= total) return;

if (onFinish && (typeof onFinish === 'function')) onFinish.call(this, i);

// 滑动完成调用方法

typeof this.options.tranSetionEnd ==='function' && this.options.tranSetionEnd.call(this);

this.current = i;

this['set' + this.swipe](current, -d * (this.swipe === 'X' ? this.width : this.height)); //问题所在

this.setCurrent(target, i);

this.finish(current, target);

};

//滑动完成后删除当前页面.play标记以及为下一页面添加.play标记

PageSlide.prototype.finish = function(curr, target) {

this.flag = null;

setTimeout(function() {

curr && curr.classList.remove('play');

target && target.classList.add('play');

}, 3e2);

};

//直达任意页面的方法

/*直达某一页面的方法, 因为个人研究的需要,写了这个方法,要从任意页面开始滑动依然能保持正常的滑动体验,就需要将直达页面的前面所有页面的translate3d参数都设置为(0,-height,0)  */

PageSlide.prototype.direct = function(i){

if(i&&typeof(i)==='number'){

this.go(i);

for(var j = 0; j< i ;j++) {

this['set' + this.swipe](this.$el.children[j], -1 * (this.swipe === 'X' ? this.width : this.height));

};

}

else  return;

};

// 传参

document.addEventListener('touchmove', function(e) {

e.preventDefault();

});

var pages = new PageSlide(document.querySelector('.pages'), 'Y', {

tranSetionEnd: function() {

console.log(this.current);

}

});

案例演示:

横向滑屏案例

横向滑屏的思路与纵向的类似,在这个demo中只需要将传入的参数由“Y”改为“X”就可以了,

// 传参
document.addEventListener('touchmove', function(e) {
  e.preventDefault();
});
var pages = new PageSlide(document.querySelector('.pages'), 'X', {
  tranSetionEnd: function() {
    console.log(this.current);
  }
});

案例演示:

H5案例分享:移动端滑屏 touch事件的更多相关文章

  1. H5案例分享:移动端touch事件判断滑屏手势的方向

    移动端touch事件判断滑屏手势的方向 方法一 当开始一个touchstart事件的时候,获取此刻手指的横坐标startX和纵坐标startY: 当触发touchmove事件时,在获取此时手指的横坐标 ...

  2. H5案例分享:JS手势框架 —— Hammer.js

    JS手势框架 -- Hammer.js 一.hammer.js简介 hammerJS是一个开源的,轻量级的触屏设备javascript手势库,它可以在不需要依赖其他东西的情况下识别触摸,鼠标事件.允许 ...

  3. 移动端滑屏全应用【一】cssHandler操作基础动画函数封装

    前言: 大家都知道,在移动端进行操作结点移动时,我们都会使用操作transform来代替top等用以提高性能,必要的时候还可开启3d加速.我们都会使用getComputedStyle来获取结点的最终样 ...

  4. 移动端笔记——jQuery touch事件

    判断移动端还是pc端 function IsPC() { var userAgentInfo = navigator.userAgent; var Agents = new Array("A ...

  5. 移动端开发用touch事件还是click事件

    前端开发现在包含了跨浏览器,跨平台(不同操作系统)和跨设备(不同尺寸的设备)开发. 在移动开发的过程中,到底选取touch事件还是click事件?对了,请不要鄙视click,click在移动端开发用着 ...

  6. WPF触屏Touch事件在嵌套控件中的响应问题

    前几天遇到个touch事件的坑,记录下来以增强理解. 具体是 想把一个listview嵌套到另一个listview,这时候如果list view(子listview)的内容过多超过容器高度,它是不会出 ...

  7. H5案例分享:html5移动开发细微之美

    html5移动开发细微之美 1.H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 <meta name="viewport" content="width=dev ...

  8. H5案例分享:使用JS判断客户端、浏览器、操作系统类型

    使用JS判断客户端.浏览器.操作系统类型 一.JS判断客户端类型 JS判断客户端是否是iOS或者Android手机移动端 通过判断浏览器的userAgent,用正则来判断手机是否是ios和Androi ...

  9. JS移动端滑屏事件

    来看看在pc上面的几个事件:onmousedown,onmousemove,onmouseup 我相信大家对这几个事件一定不陌生,第一个onmousedown表示鼠标按下,第二个onmousemove ...

随机推荐

  1. POJ1336 The K-League[最大流 公平分配问题]

    The K-League Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 715   Accepted: 251 Descri ...

  2. Matlab的68个小常识

    1.det(A)可以计算矩阵A的行列式值.inv(A)可以计算矩阵A的逆 2.rref(A)可以将矩阵A化为行简化阶梯梯形矩阵 3.eps是系统定义的容许误差,eps=2.2204*10-16 4.p ...

  3. Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds...

    仰天长啸   Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds... 当启动tomcat时候出现 ...

  4. 如何使用eclipse打开已有工程

    在开始使用Eclipse的时候,会发现一个问题,那就是如何打开一个现有的Eclipse工程,开始在菜单中找了好久也没找到. 其实,Eclipse生成的结果不像VC,Jcreator那样可以直接打开,若 ...

  5. 潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师

    潭州学院-JavaVIP的Javascript的高级进阶-KeKe老师 讲的不错,可以学习 下面是教程的目录截图: 下载地址:http://www.fu83.cn/thread-283-1-1.htm ...

  6. js实现弹框及自动关闭

    <SCRIPT LANGUAGE="javascript"> < !-- window.open (''page.html'',''newwindow'',''h ...

  7. 由12306动态验证码想到的ASP.NET实现动态GIF验证码(附源码)

    背景: 12306网站推出“彩色动态验证码机制”,新版验证码不但经常出现字符叠压,还不停抖动,不少人大呼“看不清”,称“那个验证码,是毕加索的抽象画么!”铁总客服则表示:为了能正常购票只能这样.而多家 ...

  8. 中文乱码?不,是 HTML 实体编码!

    When question comes 在 如何用 Nodejs 分析一个简单页面 一文中,我们爬取了博客园首页的 20 篇文章标题,输出部分拼接了一个字符串: var $ = cheerio.loa ...

  9. 吉特仓库管理系统-ORM框架的使用

    最近在园子里面连续看到几篇关于ORM的文章,其中有两个印象比较深刻<<SqliteSugar>>,另外一篇文章是<<我的开发框架之ORM框架>>, 第一 ...

  10. 2016 Web开发资源工具大搜罗

    来源于:https://zhuanlan.zhihu.com/p/22730771 作者:余博伦链接:https://zhuanlan.zhihu.com/p/22730771来源:知乎著作权归作者所 ...