移动端滑屏 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. 解决“只能通过Chrome网上应用商店安装该程序”的方法

    摘要 : 最近有些用户反映某个Chrome插件在安装的时候,提示"只能通过Chrome网上应用商店安装该程序",为了解决这一问题,Chrome插件网带来了相关的解决方法. 某些用户 ...

  2. 关于SSH的一些tricks

    改善SSH登录速度 登录慢的原因有很多, 慢的症状也很多, 有些是出login慢, 有些是出password慢, 有些是输入完password后进提示符慢, 根据 http://superuser.c ...

  3. Struts2 contentType属性列表

    Struts2 contentType属性列表 博客分类: Struts 2   'ez' => 'application/andrew-inset', 'hqx' => 'applica ...

  4. 关于SQL SERVER数据库学习总结

    对于SQL SERFVER数据库也学了有一阵子了,自己也对自己所学做了一些总结. 我们首先学习数据库设计的一些知识点和用SQL语句建库. 设计数据库步骤:需求分析阶段,概要设计阶段,详细设计阶段, 建 ...

  5. 《Java程序设计》 课程教学

    <Java程序设计> 课程教学 给学生 考核方式 100分构成 翻转课堂考核12次(5*12 = 60):每次考试20-30道题目,考试成绩规格化成5分(比如总分20分就除以4) 注意:不 ...

  6. Dump中查看DataTime时间方法

    例如: 步骤一:根据DumpVC命令获取时间对象信息.需要MT 和 Value参数. 步骤二:根据得到上上面值,执行:? & 0x3FFFFFFFFFFFFFFF.注意:0n 签名是零,不是英 ...

  7. AppBox升级进行时 - 扁平化的权限设计

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. AppBox v2.0中的权限实现 AppBox v2.0中权限管理中涉及三个 ...

  8. Xamarin Mono For Android 4.6.07004 完整离线安装破解版(C#开发Android、IOS工具)

      Xamarin是由Miguel de Icaza成立的一家新的独立公司,目的是给Mono一个继续奋斗的机会.Mono for Android (原名:MonoDroid)可以让开发人员使用 Mic ...

  9. 分享 Ionic 开发 Hybrid App 中遇到的问题以及后期发布 iOS/Android 的方方面面

    此篇文章主要整理了最近在使用 Ionic 开发 Hybrid App 过程中遇到的一些疑难点以及后期发布生成 iOS 和 Android 版本过程中的种种问题. 文章目录 Ionic 简介和项目需求介 ...

  10. 【强烈推荐】数据库迁移利器:Migrator.Net

    简介 很郁闷,写了一天的遇到LiveWriter错误,可恶啊 几年前在做项目中第一次接触到了Migrator.Net,就深深被吸引住了,至此以后在新的大项目中,我都会使用Migrator.Net来创建 ...