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

【示例】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