关于选项卡切换,相信大家都不陌生。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自己封装的一个属性,用来表示滑动的角度(具体的值,大家可以自己滑动时候多测试测试)。大家也可以尝试下,不对滑动角度进行控制,切换会过于灵敏,影响到其他正常的操作。
文笔功力有限,有哪些地方不是很明了,还请见谅,也希望能提出您宝贵的意见,我会继续改进。
最后,附上源码,真机运行即可。