Trust
Trust
  • 发布:2016-07-26 11:31
  • 更新:2020-09-25 14:57
  • 阅读:36331

【示例】webview模式选项卡实现滑动切换

分类:HTML5+

关于选项卡切换,相信大家都不陌生。hello mui中提供了多种选项卡切换的实现方式,不过大体分为div模式(单页)以及webviedw模式(多个页面)。div模式中又提供了可左右拖动实现切换的模式,如图:

在实际开发中,数据量只会多不会少,因此我们通常都会采用webview模式选项卡。与此同时,许多同学依旧希望能够实现滑动来实现选项卡的切换。就像这样:

可能大家会说,这个滑动并不是那么灵敏。那是因为我控制的角度范围较小(更加精确方便的范围还在进一步测试),实际开发中大家可以根据自己的需求来修改这个范围。
一、main.html
在主页面,我们需要做许多事情,创建自窗口对象(不然切什么换),底部选项点击切换(这是基本的切换),自定义事件切换(子窗口滑动事件来触发)。
其中关键的地方,在于切换。切换,我们要切什么,换什么这才是选项卡切换的核心。
切,有两种切法,点击和滑动。
换,换子窗口,换标题,换底部高亮文字。

<!doctype html>  
<html>  
  
	<head>  
		<meta charset="UTF-8">  
		<title></title>  
		<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />  
		<link href="http://ask.dcloud.net.cn/css/mui.min.css" rel="stylesheet" />  
	</head>  
  
	<body>  
		<header class="mui-bar mui-bar-nav">  
			<h1 class="mui-title">首页</h1>  
		</header>  
		<nav class="mui-bar mui-bar-tab">  
			<a class="mui-tab-item mui-active" data-index="0">  
				<span class="mui-icon mui-icon-home"></span>  
				<span class="mui-tab-label">首页</span>  
			</a>  
			<a class="mui-tab-item" data-index="1">  
				<span class="mui-icon mui-icon-phone"></span>  
				<span class="mui-tab-label">电话</span>  
			</a>  
			<a class="mui-tab-item" data-index="2">  
				<span class="mui-icon mui-icon-email"></span>  
				<span class="mui-tab-label">邮件</span>  
			</a>  
			<a class="mui-tab-item" data-index="3">  
				<span class="mui-icon mui-icon-gear"></span>  
				<span class="mui-tab-label">设置</span>  
			</a>  
		</nav>  
		<script src="js/mui.min.js"></script>  
		<script type="text/javascript">  
			mui.init();  
			mui.plusReady(function() {  
				/**  
				 * 当前窗口对象,即父窗口;  
				 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.currentWebview  
				 */  
				var self = plus.webview.currentWebview();  
				// 子窗口地址数组  
				var subpages = ["home.html", "phone.html", "email.html", "gear.html"];  
				// 子窗口样式  
				var subStyles = {  
					top: "45px",  
					bottom: "50px"  
				};  
				// 子窗口数量  
				var subLen = subpages.length;  
				// 子窗口对象数组  
				var subWvs = [];  
				// 标题栏  
				var title = document.querySelector(".mui-title");  
				// 底部选项  
				var tabs = document.querySelectorAll(".mui-tab-item");  
				// 底部文字  
				var labels = document.querySelectorAll(".mui-tab-label");  
				// 当前页面索引,初始化为0;  
				var activeIndex = 0;  
				// 目标页面索引,初始化为当前页面索引;  
				var targetIndex = activeIndex;  
				// 创建子页面  
				for(var i = 0; i < subLen; i  ) {  
					/**  
					 * 创建窗口对象,并将索引做为额外的参数传递;  
					 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.create  
					 */  
					var subWv = plus.webview.create(subpages[i], cutWebviewId(subpages[i]), subStyles, {  
						index: i  
					});  
					// 窗口对象添加至数组  
					subWvs.push(subWv);  
					if(i > 0) {  
						/**  
						 * 隐藏非第一页的窗口对象  
						 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.hide  
						 */  
						subWv.hide("none");  
					}  
					/**  
					 * 向父窗口添加子窗口  
					 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.append  
					 */  
					self.append(subWv);  
				}  
				// 底部选项卡点击切换事件  
				for(var j = 0, jlen = tabs.length; j < jlen; j  ) {  
					tabs[j].addEventListener("tap", function() {  
						// 获取当前结点的索引  
						targetIndex = this.getAttribute("data-index");  
						// 转换为number类型  
						targetIndex = parseInt(targetIndex, 10);  
						if(targetIndex == activeIndex) {  
							return;  
						}  
						// 切换页面  
						switchPage("tap", activeIndex, targetIndex);  
					});  
				}  
				// 子页面滑动切换事件  
				window.addEventListener("swipe_event", function(event) {  
					// 获取方向以及索引  
					var direction = event.detail.direction;  
					activeIndex = event.detail.index;  
					if(direction == "left") {  
						// 如果是最后一个页面,则不做左滑切换;  
						if(activeIndex == subLen - 1) {  
							console.log("最右边一页了");  
							return;  
						}  
						// 目标页面的索引为后面一位  
						targetIndex = activeIndex   1;  
					} else {  
						// 如果是第一个页面,则不做右滑切换;  
						if(activeIndex == 0) {  
							console.log("最左边一页了");  
							return;  
						}  
						// 目标页面的索引为前面一位  
						targetIndex = activeIndex - 1;  
					}  
					// 切换页面  
					switchPage("switch", activeIndex, targetIndex);  
				});  
  
				/**  
				 * 切换页面  
				 * @param {String} _event 事件类型  
				 * @param {Number} _active 当前页面索引  
				 * @param {Number} _target 目标页面索引  
				 */  
				function switchPage(_event, _active, _target) {  
					/**  
					 * 目标页面展示  
					 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.show  
					 */  
					subWvs[_target].show("fade-in");  
					// 顶部文字替换  
					title.innerText = labels[_target].innerText;  
					// 如果是滑动事件,则手动切换高亮选项;  
					if(_event == "switch") {  
						tabs[_active].classList.remove("mui-active");  
						tabs[_target].classList.add("mui-active");  
					}  
					// 之前展示的页面隐藏  
					subWvs[_active].hide("none");  
					// 更新当前页索引  
					activeIndex = _target;  
				}  
			});  
  
			/**  
			 * 截取url地址,获取窗口的id;  
			 * @param {String} url html文件的路径  
			 * @param {String} wvId webviewObject的id  
			 */  
			function cutWebviewId(url) {  
				var startIndex = url.lastIndexOf("/");  
				var endIndex = url.lastIndexOf(".html");  
				var wvId = url.substring(startIndex   1, endIndex);  
				return wvId;  
			}  
		</script>  
	</body>  
  
</html>

明确了我们要干什么,我们来看下切换的这个函数:

/**  
 * 切换页面  
 * @param {String} _event 事件类型  
 * @param {Number} _active 当前页面索引  
 * @param {Number} _target 目标页面索引  
 */  
function switchPage(_event, _active, _target) {  
	/**  
	 * 目标页面展示  
	 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.show  
	 */  
	subWvs[_target].show("fade-in");  
	// 顶部文字替换  
	title.innerText = labels[_target].innerText;  
	// 如果是滑动事件,则手动切换高亮选项;  
	if(_event == "switch") {  
		tabs[_active].classList.remove("mui-active");  
		tabs[_target].classList.add("mui-active");  
	}  
	// 之前展示的页面隐藏  
	subWvs[_active].hide("none");  
	// 更新当前页索引  
	activeIndex = _target;  
}  

_event代表切的方式,_active代表当前展示的窗口索引,_target代表目标窗口的索引。
首先将目标窗口show出来,然后替换顶部标题的文字内容。然后判定下切的方式,如果是滑动切换,我们需要自己来对classList进行操作,完成选项卡高亮的转换。最后,我们需要把之前展示的选项卡隐藏掉,并且把当前窗口的索引值赋给中间量。
二、sub.js
所有的子页面都引入这个JS文件,内容如下:

mui.init();  
mui.plusReady(function() {  
	// 获取当前窗口对象  
	var self = plus.webview.currentWebview();  
	// 读取传递过来的参数  
	var index = self.index;  
	/**  
	 * 获取父窗口对象  
	 * http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewObject.parent  
	 */  
	var parent = self.parent();  
	// 左滑事件  
	document.addEventListener("swipeleft", function(event) {  
		var angle = event.detail.angle;  
		angle = Math.abs(angle);  
		/**  
		 * 控制滑动的角度,为避免误操作,可自定义限制滑动角度;  
		 */  
		if(angle > 175 && angle < 185) {  
			parentEvent(parent, index, "left");  
		}  
	});  
	// 右滑事件  
	document.addEventListener("swiperight", function(event) {  
		var angle = event.detail.angle;  
		angle = Math.abs(angle);  
		/**  
		 * 控制滑动的角度,为避免误操作,可自定义限制滑动角度;  
		 */  
		if(angle < 4) {  
			parentEvent(parent, index, "right");  
		}  
	});  
});  
  
/**  
 * 触发父窗口自定义事件  
 * @param {Object} wvobj 目标窗口对象  
 * @param {Number} index 索引值  
 * @param {String} direction 方向  
 */  
function parentEvent(wvobj, index, direction) {  
	/**  
	 * 触发自定义事件  
	 * http://dev.dcloud.net.cn/mui/event/#customevent  
	 */  
	mui.fire(wvobj, "swipe_event", {  
		direction: direction,  
		index: index  
	});  
}  

内容简单明了,就是监听左滑和右滑事件,然后去触发父窗口的自定义切换事件。关键点在于event.detail.angle,这个是mui自己封装的一个属性,用来表示滑动的角度(具体的值,大家可以自己滑动时候多测试测试)。大家也可以尝试下,不对滑动角度进行控制,切换会过于灵敏,影响到其他正常的操作。
文笔功力有限,有哪些地方不是很明了,还请见谅,也希望能提出您宝贵的意见,我会继续改进。
最后,附上源码,真机运行即可。

18 关注 分享
BoredApe 赵梦欢 lhyh LuckyJohn 紫苏 mingtianfu 雷小达 yedong0839 z***@163.com 雪之梦技术驿站 w***@163.com 杨婆婆管家家 FindTheself 水灵退散 n***@qq.com 稳定点行不行 段长发 9***@qq.com

要回复文章请先登录注册

plain

plain

不错,用上了。
2020-09-25 14:57
人走板凳凉

人走板凳凉

我刚运行,效果出来了。但是有个问题,怎么让页面跟着手滑动走。这种切换就跟变戏法一样,用户体验差。我就想要微信那种左右滑动效果。
2020-04-02 13:56
p***@126.com

p***@126.com

很不错哦,就是效果不是特别的好,但是功能还是实现了的
2019-11-22 17:29
段长发

段长发


大家可以试试,我加了个给右滑动了个.0感觉灵敏了不止一点点,并且关闭了一些其他监听事件
mui.init({
gestureConfig:{
tap: true, //单击屏幕 默认为true
doubletap: false, //双击屏幕 默认为false,不监听
longtap: false, // 长按屏幕 默认为false,不监听
swipe: true, // 滑动 默认为true
drag: false, //拖动 默认为true,不监听
hold:false,// 按住屏幕 默认为false,不监听
release:false//离开屏幕 默认为false,不监听
}
});


// 左滑事件
document.addEventListener("swipeleft", function(event) {
var angle = event.detail.angle;
angle = Math.abs(angle);
// mui.toast('左滑了');
// console.log('左滑了:'+angle);
/**
* 控制滑动的角度,为避免误操作,可自定义限制滑动角度;
*/
if(angle > 150 && angle < 250) {
parentEvent(parent, index, "left");
}
});
// 右滑事件
document.addEventListener("swiperight", function(event) {
var angle = event.detail.angle;
angle = Math.abs(angle);
// mui.toast('右滑动');
// console.log('右滑动:'+angle);
/**
* 控制滑动的角度,为避免误操作,可自定义限制滑动角度;
*/
if(angle > 4.0) {
parentEvent(parent, index, "right");
}
});
2019-06-05 10:17
Yizhiyu

Yizhiyu

最多四个tab??
2018-07-06 09:47
g***@sohu.com

g***@sohu.com

Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.
2018-03-29 11:33
c***@qq.com

c***@qq.com

sub.js 改为 angle > 150 && angle < 250滑动成功率很高,可以试一试其他数据
2017-12-08 11:12
杰哥seo

杰哥seo

mark
2017-06-19 16:09
4***@qq.com

4***@qq.com

感觉楼主这么写DOM压力好大啊,都放一个里了。而且滑动效果基本上可以忽略了。。。
2017-05-17 16:44
1***@qq.com

1***@qq.com

mark
2017-04-06 10:22