通过滑动翻页效果实现和移动端click事件问题

前述

本文很短~
主要是为了总结和讲述移动端click和js事件机制导致的一个问题。
(:咳咳,其实几句话就能写完的还要水一篇文章,不愧是我…


正文

最近做了一个小活动,里面要用到一个效果:滑动翻页。大概是这样的:

<!-- HTML代码 -->
<div class="page-container">
	<div class="page" style="background: #dc3b26">1</div>
	<div class="page" style="background: #f3b03d">2</div>
	<div class="page" style="background: #44a2f8">3</div>
</div>

在css中,首先因为是滑动翻页,所以我们要保证“始终只有一屏”,这个可以放在全局样式表里控制,然后是其中的“每一页”都要占满父元素 —— 这里其实用了“div是块元素,无外力情况下竖直排列”的特性。

/** css样式 */
html,
body{
	margin: 0;
	padding: 0;
	width: 100%;
	height: 100vh;
	overflow: hidden;
	font-size: 60px;
}
.page-container{
	width: 100%;
	height: 100%;
}
.page-container .page{
	width: 100%;
	height: 100%;
}

其JS实现也很简单:因为在移动端,所以使用了touchstarttouchmovetouchend事件来实现手势滑动功能:

  • start(刚按下)时记录此时的手指位置——作为初始值;
  • 在move(触摸滑动)时根据实时的手指位置和初始手指位置变量实现要求判断,在本文场景为代表的场景下这一步一般还要求出“移动距离”实时赋值;
  • 在end(手指离开)时(也有直接在move时进行的)进行收尾工作——比如:图片滑动完全划过去、元素跑到结束位置、将事件监听取消;
// 这里是控制全局js的文件
// 全局阻止浏览器默认行为
document.addEventListener("touchstart",function(e){
	if(e.cancelable){
		e.preventDefault();
	}
},{passive: false})
// {passive: false}就是告诉前面可能有需要重置行为的代码
document.addEventListener("touchmove",function(e){
	if(e.cancelable){
		e.preventDefault();
	}
},{passive: false})
// JavaScript代码
let curPageIndex=0;
let pageContainer=document.querySelector(".page-container");
let pageNumber=pageContainer.children.length;  //页面的数量
// 文档的视窗高度(这里就是一屏的高度)
let cHeight=document.documentElement.clientHeight;
// 设置页面容器的margin-top为合适的值,让其显示在视野中
function toPage(){
	pageContainer.style.transition="all .5s ease";
	pageContainer.style.marginTop=-curPageIndex*cHeight+"px";

	// 变化完成后去掉过渡效果 !
	pageContainer.addEventListener("transitionend",function(){
		pageContainer.style.transition="none";
	},{once:true})
}
toPage()

pageContainer.ontouchstart=function(e){
	let y=e.changedTouches[0].clientY;  //手指按下的纵坐标
	pageContainer.ontouchmove=function(e){
		let dis=e.changedTouches[0].clientY-y;  //计算距离
		// 计算page-container的margin-top
		let mtop=-curPageIndex*cHeight+dis
		if(mtop>0){
			mtop=0;
		}else if(mtop<-(pageNumber-1)*cHeight){
			mtop=-(pageNumber-1)*cHeight;
		}
		// 实时改变位置
		pageContainer.style.marginTop=mtop+"px";
	}
	pageContainer.ontouchend=function(e){
		let dis=e.changedTouches[0].clientY-y;
		// 如果滑动距离实在太短,就回到滑动前的位置状态
		if(Math.abs(dis)<=60){
			toPage()
		}else if(dis>0 && curPageIndex>0){
			curPageIndex--;
			toPage()
		}else if(dis<0 && curPageIndex<pageNumber-1){
			curPageIndex++;
			toPage()
		}

		// 手指离开后,取消监听事件
		pageContainer.ontouchmove=null;
		pageContainer.ontouchend=null;
	}
}


至此,功能上似乎很完美。但这时候,我们在第一个page里添加一个button:

<div class="page" style="background: #dc3b26">
	<button onclick="alert('哈哈哈')" class="but">click me!</button>
	1
</div>

然后到页面上查看效果:

无效!

这是因为在上方全局js文件里我们加了“阻止浏览器默认事件”的代码。
——在移动端浏览器中,click事件和mousestart事件是同时被触发的。因为移动端浏览器是没有click事件的,它是由mouse事件模拟的! :也正是这个原因,才有了所谓的“移动端浏览器300ms延迟”的问题 1 。
——还有就是,在微信自带的浏览器中,有一个“触顶下拉回弹”的操作,这其实是不应该的。它也属于浏览器默认事件。
所以一般我们需要禁止掉这些东西。

但是如上面所示,全部禁止掉总会造成一些困扰,怎么办?
H5提供了“自定义属性”,针对本文方法,我们完全可以 —— 在全局事件里检测当前触发的元素有没有某一个自定义属性,如果有,就什么也不拦截;否则就执行禁止默认行为的代码:
比如

<button data-default="true" onclick="alert('哈哈哈')" class="but">click me!</button>

将上面“控制全局js的文件”内容改为如下:

// 全局阻止浏览器默认行为
document.addEventListener("touchstart",function(e){
	if(e.target.dataset.default){
		return;
	}
	if(e.cancelable){
		e.preventDefault();
	}
},{passive: false})
document.addEventListener("touchmove",function(e){
	if(e.target.dataset.default){
		return;
	}
	if(e.cancelable){
		e.preventDefault();
	}
},{passive: false})

就OK了:



其实还有另一种“解法”:既然上面说了,移动端click实际上是通过mouse事件模拟的,那么我们可以从mousestart事件入手;又因为button元素是“第一个页面”内的(子)元素,所以可以用阻止事件冒泡

<!-- button就是普通的button -->
<button class="but">click me!</button>
document.querySelector(".but").addEventListener("touchstart",function(e){
	e.stopPropagation();
	alert('噶哈哈');
},false)

关于捕获和冒泡→

我们首先要知道的是:当我们鼠标按下一个按钮时,并不是“点击了一个按钮”,而是在这个区域内,鼠标(上的按键)被按下,操作系统和浏览器把这个信息对应到了“按钮”所在区域并触发其逻辑。
事实上鼠标点击并没有位置信息,是操作系统一直在监听鼠标移动,根据累积的位移计算出来的坐标,将其传给浏览器。
那么,把这个坐标转换为具体的元素上的事件的过程,就可称作“捕获”。那“冒泡”呢?这个不好解释,但有一点想必你是明白的:当你按下电视开关时,你也按到了电视!
这就是很多文章会讲到的“冒泡过程由内向外,捕获过程由外向内”,或者说是“洋葱模型”。
还有一点就是:事件addEventListener的第三个参数 true/false ,即为“是捕获/冒泡”。(别多想,这只是浏览器提供的事件模型之一。无论是否监听,在一个事件发生时,捕获和冒泡总是先后发生的)

到此这篇关于滑动翻页效果实现和移动端click事件问题的文章就介绍到这了,更多相关滑动翻页效果内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2021-01-24

NGUI实现滑动翻页效果实例代码

废话不多说了,直接给大家上干货了. 具体代码如下所示: using UnityEngine; using System.Collections; public class PageView : MonoBehaviour { const int ITEM_NUM = 2; //总页数 const int PAGE_WIDTH = 2048; //页宽 const float DRAG_SPEED = 0.5f; //翻页时间 const int DRAG_OFFECT = 30; //滑动的起点

jQuery基于$.ajax设置移动端click超时处理方法

本文实例讲述了jQuery基于$.ajax设置移动端click超时处理方法.分享给大家供大家参考,具体如下: 这里介绍jquery click事件如何在移动端自动转换成touchstart事件. 因为移动端click事件会比touchstart事件慢几拍 移动设备某个元素上事件执行顺序是: touchstart touchmove touchend click{mousedown->mousemove->mouseup} click事件在移动设备上虽然会识别但却是最后一个执行的,所以如果不把c

Android自定义左右或上下滑动翻页效果

本文实例为大家分享了Android自定义左右或上下滑动翻页展示的具体代码,供大家参考,具体内容如下 该自定义的效果和ViewPage+Fragment差不多 上下滑动翻页,继承ScrollView public class SlideScrollView extends ScrollView implements PageSlide{ private TotalSlide totalSlide; public SlideScrollView(AppCompatActivity context)

使用jQueryMobile实现滑动翻页效果的方法

本文实例讲述了使用jQueryMobile实现滑动翻页效果的方法.分享给大家供大家参考.具体分析如下: 滑动手势在移动设备是很流行的,在移动设备中滑动翻页中很常见 虽然这个功能可以在jQueryMobile中实现,但是个人与之前一篇[jQuery手机浏览器中拖拽动作的艰难性分析]中的观点一致,由于这是在手机浏览器中浏览,而不是安卓的一个独立APP,所以不要经常除点击以外的移动设备手势,以免跟手机浏览器与手机系统本身的手势发生冲突. 那么,使用jQueryMobile实现滑动翻页的效果到底怎么做呢

解析Android中实现滑动翻页之ViewFlipper的使用详解

1)View切换的控件-ViewFlipper介绍 ViewFilpper类继承于ViewAnimator类.而ViewAnimator类继承于FrameLayout. 查看ViewAnimator类的源码可以看出此类的作用主要是为其中的View切换提供动画效果.该类有如下几个和动画相关的方法. setInAnimation:设置View进入屏幕时候使用的动画.该方法有两个重载方法,即可以直接传入Animation对象,也可以传入定义的Animation文件的resourceID. setOut

android ViewPager实现滑动翻页效果实例代码

实现ViewPager的滑动翻页效果可以使用ViewPager的setPageTransformer方法,如下: import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.View; public class ReadViewPager extends ViewPager { public ReadV

javaScript+turn.js实现图书翻页效果实例代码

为了实现图书翻页的效果我们在网上可以看到很多教程 在这里推荐turn.js 网上的turn.js 有api 不过是英文的  很多人看起来不方便 .关于代码也是奇形怪状在这里我将详细讲解如何使用turn.js实现翻页效果 ,本篇文章只是讲解 turn.js 如何使用!!!!!!! 文章最后提供源码下载,结合源码看本文,turn.js更简单! 首先附上个人的文件路径 对于css   和 js文件不需要过多的解释   在这里要注意的是pages文件夹   这里个文件夹下放的是需要预览的图片文件   

微信小程序实现滑动翻页效果(完整代码)

微信小程序实现滑动翻页效果,效果图如下所示: 源码: <view class="mainFrame"> <swiper class="container" indicator-dots="{{indicatorDots}}" indicator-dots="{{indicatordots}}" autoplay="{{autoplay}}" interval="{{interva

Android ViewPager实现左右滑动翻页效果

本文实例为大家分享了ViewPager实现左右滑动翻页效果展示的具体代码,供大家参考,具体内容如下 代码如下: package com.example.demo; import java.util.ArrayList; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import a

android实现滑动标签页效果的代码解析

实现效果: 实现功能: ViewPager+Fragment实现加载界面 SQLite数据获取并显示到ListView上 ListView的item监听并携带数据跳转到其他界面 使用SharedPreference存储部分测试数据 实现过程: 各方法和变量的作用请详见代码注释. listview的数据显示请见Android Studio获取SQLite数据并显示到ListView上Fragment+ViewParger实现界面加载 首先要创建两个类并继承Fragment,在viewpager中实

Unity UGUI实现滑动翻页效果

本文实例为大家分享了Unity UGUI实现滑动翻页效果的具体代码,供大家参考,具体内容如下 这个问题真的是老生常谈的事情了,不过在这里还是要说一下,以便以后之需 首先看一下效果图 最后在Content下面是一些Image using UnityEngine; using System.Collections; using UnityEngine.UI; using System.Collections.Generic; using UnityEngine.EventSystems; using

vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】

说到h5的翻页,很定第一时间想到的是swiper.但是我当时想到的却是,vue里边怎么用swiper?! vue-awesome-swiper就是其中一个前辈们产出的结晶.就看首尾两个单词,就知道他是vue和swiper的爱情之子了. vue-awesome-swiper官网是中文文档,妈妈再也不用担心我读api啦."基于 Swiper4.适用于 Vue 的轮播组件".在产品催着进度的紧张环境下,在四处搜寻解决方案的情况下,这句话简直发着光啊. 具体怎么用,官方文档写的很清楚,但我还是