H5案例分享:移动端滑屏 touch事件
移動(dòng)端滑屏 touch事件
??移動(dòng)端觸屏滑動(dòng)的效果的效果在電子設(shè)備上已經(jīng)被應(yīng)用的越來(lái)越廣泛,類(lèi)似于PC端的圖片輪播,但是在移動(dòng)設(shè)備上,要實(shí)現(xiàn)這種輪播的效果,就需要用到核心的touch事件。處理touch事件能跟蹤到屏幕滑動(dòng)的每根手指。
以下是四種touch事件
touchstart: //觸摸屏幕時(shí)觸發(fā);即使已經(jīng)有一個(gè)手指放在了屏幕上也會(huì)觸發(fā)。
touchmove: //在屏幕上滑動(dòng)時(shí)連續(xù)的觸發(fā)。在這個(gè)事件發(fā)生期間,調(diào)用preventDefault()可阻止?jié)L動(dòng)。
touchend: //從屏幕上移開(kāi)時(shí)觸發(fā)。
touchcancel: //系統(tǒng)取消touch事件的時(shí)候觸發(fā),這個(gè)好像比較少用。
上面這幾個(gè)事件都會(huì)冒泡,也都可以取消。雖然這些觸摸事件沒(méi)有在DOM規(guī)范中定義,但它們卻是以兼容DOM的方式實(shí)現(xiàn)的。因此,每個(gè)觸摸事件沒(méi)有在DOM規(guī)范中定義,但它們卻是以兼容DOM的方式實(shí)現(xiàn)的。因此,每個(gè)觸摸事件的event對(duì)象都提供了在鼠標(biāo)事件中常見(jiàn)的屬性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey和metaKey。
每個(gè)觸摸事件被觸發(fā)后,會(huì)生成一個(gè)event對(duì)象,event對(duì)象里額外包括以下三個(gè)觸摸列表。
touches://表示當(dāng)前跟蹤的觸摸操作的touch對(duì)象的數(shù)組。
當(dāng)一個(gè)手指在觸屏上時(shí),event.touches.length=1,
當(dāng)兩個(gè)手指在觸屏上時(shí),event.touches.length=2,以此類(lèi)推。
targetTouches://特定于事件目標(biāo)的touch對(duì)象數(shù)組。因?yàn)閠ouch事件是會(huì)冒泡的,所以利用這個(gè)屬性指出目標(biāo)對(duì)象。
changedTouches://表示自上次觸摸以來(lái)發(fā)生了什么改變的touch對(duì)象的數(shù)組。
這些列表里的每次觸摸由touch對(duì)象組成,touch對(duì)象里包含著觸摸信息,主要屬性如下:
clientX://觸摸目標(biāo)在視口中的x坐標(biāo)。
clientY://觸摸目標(biāo)在視口中的y坐標(biāo)。
identifier://標(biāo)識(shí)觸摸的唯一ID。
pageX://觸摸目標(biāo)在頁(yè)面中的x坐標(biāo)。
pageY://觸摸目標(biāo)在頁(yè)面中的y坐標(biāo)。
screenX://觸摸目標(biāo)在屏幕中的x坐標(biāo)。
screenY://觸摸目標(biāo)在屏幕中的y坐標(biāo)。
target://觸摸的DOM節(jié)點(diǎn)目標(biāo)。
注意事項(xiàng):
手指在滑動(dòng)整個(gè)屏幕時(shí),會(huì)影響瀏覽器的行為,比如滾動(dòng)和縮放。所以在調(diào)用touch事件時(shí),要注意禁止縮放和滾動(dòng)。
1.禁止縮放
通過(guò)meta元標(biāo)簽來(lái)設(shè)置。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,minimum-scale=1,user-scalable=no">加上這句代碼后,我們編寫(xiě)的頁(yè)面將不會(huì)隨著用的手勢(shì)而放大縮小。
2.禁止?jié)L動(dòng)
preventDefault是阻止默認(rèn)行為,touch事件的默認(rèn)行為就是滾動(dòng)。
由于觸摸會(huì)導(dǎo)致屏幕動(dòng)來(lái)動(dòng)去,所以可以會(huì)在這些事件的事件處理函數(shù)內(nèi)使用event.preventDefault(),來(lái)阻止屏幕的默認(rèn)滾動(dòng)。
? 這里寫(xiě)的demo的使用的方法是將HTML結(jié)構(gòu)寫(xiě)好后往里傳參就可以了。它接受所有滑動(dòng)頁(yè)面對(duì)象(在這里是document.querySelector('#pages') ) 和要設(shè)定的方向(用X,Y表示橫向或者縱向)以及一個(gè)可選的擴(kuò)展函數(shù)。
縱向滑屏案例:
這里將所有的代碼都封裝進(jìn)一個(gè)PageSlide的原型對(duì)象中,可以當(dāng)成原生JS插件來(lái)使用,
它所要求的HTML的結(jié)構(gòu)為:
<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樣式結(jié)構(gòu)為:
/* 注意加html標(biāo)簽,使得高度100%等于視窗高度 */
html,body{ width:100%; height:100%; margin:0; padding:0; overflow:hidden; }
/*滑動(dòng)頁(yè)面的統(tǒng)一樣式 */
.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 動(dòng)畫(huà) */
.box{ width:100px; height:100px; background:black; }
/* 所有動(dòng)畫(huà)使用類(lèi)控制 */
.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);
?}
}
? 要實(shí)現(xiàn)手指跟隨的滑動(dòng)效果, 關(guān)鍵在于通過(guò)touch事件來(lái)設(shè)置transform:translate3d(x,y,z)的參數(shù),并在滑動(dòng)結(jié)束(touchend)設(shè)置一個(gè)最小滑動(dòng)距離minRange,該距離范圍內(nèi)的滑動(dòng),translate3d的參數(shù)等于touchmove的滑動(dòng)距離,當(dāng)大于minRange時(shí), 則觸發(fā)下一頁(yè)(或上一頁(yè))的整體滑動(dòng),translate3d的X或Y的參數(shù)也就是視窗的寬(橫向滑動(dòng)時(shí))或者高(縱向滑動(dòng)時(shí))。
? 另外,對(duì)于一個(gè)網(wǎng)頁(yè)單頁(yè),還需要解決一個(gè)問(wèn)題,即每個(gè)頁(yè)面中可能有動(dòng)畫(huà)或者其他的事件需要在該頁(yè)面出現(xiàn)時(shí)才開(kāi)始播放,動(dòng)畫(huà)采用css類(lèi)控制, 這里采用在每個(gè)當(dāng)前頁(yè)面中添加一個(gè).play的類(lèi)作為標(biāo)記, 在每個(gè)頁(yè)面的CSS動(dòng)畫(huà)設(shè)置中,同樣加上.play類(lèi)名,這樣就實(shí)現(xiàn)了當(dāng)頁(yè)面出現(xiàn)才開(kāi)始播放本頁(yè)動(dòng)畫(huà)的功能。
JavaScript的代碼如下:
// PageSlide接收三個(gè)參數(shù):頁(yè)面元素,要設(shè)定的滑動(dòng)方向,可選的擴(kuò)展函數(shù)
var PageSlide = function(el, swipe, options) {
??? this.options = options || {}; //可選函數(shù)
??? this.current = 0;? //當(dāng)前頁(yè)面索引
??? this.pageX;? //橫向的手指落點(diǎn)
??? this.pageY;? //縱向的手指落點(diǎn)
??? this.height; //設(shè)備高度
??? this.width; ?//設(shè)備寬度
??? this.flag;? //判斷滑動(dòng)方向的變量
??? this.move;? //滑動(dòng)的距離
??? this.$el = el; //當(dāng)前頁(yè)面的對(duì)象
??? this.swipe = swipe || 'X'; //滑動(dòng)方向參數(shù)
??? this.resize().init().bindEvents(); //初始化
}
PageSlide.prototype.init = function(i) {
??? var current = i ? this.$el.children[i] : this.$el.firstElementChild;
??? if (!current) throw 'ERROR';
//moving類(lèi)名作為當(dāng)前滑動(dòng)頁(yè)面的標(biāo)記,也在樣式中作滑動(dòng)的擴(kuò)展效果
??? current.classList.add('moving');
??? current.style.webkitTransform = 'translate3d(0,0,0)';
//以swipe的值預(yù)設(shè)置其他頁(yè)面的寬高,獲得流暢的交互效果
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
};
//為頁(yè)面綁定各種事件的綁定函數(shù)
PageSlide.prototype.bindEvents = function() {
??? var self = this;
??? window.addEventListener('resize orientationchange', this.resize.bind(this), false);
??? 'touchstart touchmove touchend touchcancel'.split(' ').forEach(function(evn) {
?? //將四個(gè)觸控函數(shù)(申明在后面)綁定到每個(gè)頁(yè)面
??????? self.$el.addEventListener(evn, self[evn].bind(self), false);
??? });
}
//獲得當(dāng)前觸控的頁(yè)面對(duì)象
PageSlide.prototype.getCurrent = function() {
??? return this.$el.children[this.current];
};
//初始化時(shí)獲得設(shè)備的寬高
PageSlide.prototype.resize = function() {
??? this.width = this.$el.parentNode.clientWidth;
??? this.height = this.$el.parentNode.clientHeight;
??? return this;
};
//到達(dá)任意頁(yè)面的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]);
}
// 四個(gè)內(nèi)建的滑動(dòng)事件函數(shù),與前面綁定函數(shù)相呼應(yīng)
PageSlide.prototype.touchstart = function(e) {
??? var touches = e.touches[0];
??? //觸控開(kāi)始
??? this.flag = null;
??? this.move = 0;
??? //記錄落點(diǎn)
??? 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;
??? //添加移動(dòng)樣式
??? 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();
?? //滑動(dòng)結(jié)束前往下一頁(yè)面,next()方法調(diào)用了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();
}
//動(dòng)態(tài)設(shè)定translate3d參數(shù)方法
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)');
};
//設(shè)置當(dāng)前觸控頁(yè)面translate3d參數(shù)為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];
??? }
}
//調(diào)用go()方法前往下一或上一頁(yè)面
PageSlide.prototype.next = function() {
??? this.go(this.current + 1);
};
PageSlide.prototype.prev = function() {
??? this.go(this.current - 1);
};
//重置方法,用于初始化以及當(dāng)前頁(yè)面的重置
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));
}
//去往下一或上一頁(yè)面的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);
??? // 滑動(dòng)完成調(diào)用方法
??? 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)); //問(wèn)題所在
??? this.setCurrent(target, i);
??? this.finish(current, target);
};
//滑動(dòng)完成后刪除當(dāng)前頁(yè)面.play標(biāo)記以及為下一頁(yè)面添加.play標(biāo)記
PageSlide.prototype.finish = function(curr, target) {
??? this.flag = null;
??? setTimeout(function() {
??????? curr && curr.classList.remove('play');
??????? target && target.classList.add('play');
??? }, 3e2);
};
//直達(dá)任意頁(yè)面的方法
/*直達(dá)某一頁(yè)面的方法, 因?yàn)閭€(gè)人研究的需要,寫(xiě)了這個(gè)方法,要從任意頁(yè)面開(kāi)始滑動(dòng)依然能保持正常的滑動(dòng)體驗(yàn),就需要將直達(dá)頁(yè)面的前面所有頁(yè)面的translate3d參數(shù)都設(shè)置為(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);
? }
});
案例演示:
橫向滑屏案例:
橫向滑屏的思路與縱向的類(lèi)似,在這個(gè)demo中只需要將傳入的參數(shù)由“Y”改為“X”就可以了,
// 傳參
document.addEventListener('touchmove', function(e) {
? e.preventDefault();
});
var pages = new PageSlide(document.querySelector('.pages'), 'X', {
? tranSetionEnd: function() {
? ? console.log(this.current);
? }
});
案例演示:
轉(zhuǎn)載于:https://www.cnblogs.com/yangmengsheng/p/5973530.html
總結(jié)
以上是生活随笔為你收集整理的H5案例分享:移动端滑屏 touch事件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 干货丨一组图详解元数据、主数据与参考数据
- 下一篇: netstrem获取302后的地址,可用