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

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

要回复文章请先登录注册

s***@163.com

s***@163.com

你这个动画效果 只能fade in 其他动画完全没用
2016-11-24 21:16
amourz

amourz

回复 Derekwong :
你可以试试5-10度
2016-10-14 16:25
Derekwong

Derekwong

回复 amourz :
请问,角度改到多少比较好滑动,自己试了很多都不太灵敏。
2016-10-14 16:03
amourz

amourz

sub.js里修改下角度参数,就可以比较好的滑动了。谢谢楼主分享
2016-09-09 10:21
amourz

amourz

回复 迷离的IT民工 :
对,左右滑动效果不是很好啊,很涩的感觉,而且10次才有一次起作用
2016-09-09 10:17
迷离的IT民工

迷离的IT民工

demo 可以用, 滑动二十次 也就只有一次起效果,性能低下,几乎还是不能用相当于没有;
2016-08-23 09:57
AYBlue

AYBlue

切换不管用,显示不出来,下载的demo拖服务器里也不行
2016-08-21 19:01
Loyw

Loyw

回复 Trust :
缺什么模块?
2016-08-19 18:06
Trust

Trust (作者)

回复 Loyw :
不要打包啊,真机运行,我那个好多模块都移除了。
2016-08-19 17:50
Loyw

Loyw

云打包安装后 打开白屏、用不了!为什么呢??
2016-08-19 17:50