本篇博文是继续 HBuilder+MUI开发移动APP - MUI(2)博文。
上面这幅图是博文MUI(1)中实现的效果,在博文MUI(1)中提到了2个页面,一个页面是index.html,另一个页面是index_list.html页面。上面这幅图中红色框子是index.html页面,蓝色框子是index_list.html页面。两个页面本来是独立的两个页面,但是组合在一起之后就形成了如上面这幅图所示的效果。在一个页面中显示另一个页面。
实现方法很简单,
1 <script type="text/javascript" charset="utf-8"> 2 mui.init({ 3 subpages: [{ 4 url: "html/index_list.html", //子页面HTML地址,支持本地地址和网络地址 5 id: "index_list", //子页面标志 6 styles: { 7 top: '45px', //子页面顶部位置,mui标题栏默认高度为45px 8 bottom: '0px' //子页面底部位置,默认为0px,可不定义 9 } 10 }] 11 }); 12 </script>
其实index_list.html页面是index.html页面的子页面,官方文档中说:在mobile app开发过程中,经常遇到卡头卡尾的页面,此时若使用局部滚动,在Android手机上会出现滚动不流畅的问题;mui的解决思路是:将需要滚动的区域通过单独的webview实现,完全使用原生滚动。具体做法是:将目标页面分解为主页面和内容页面,主页面显示卡头卡尾区域,比如顶部导航,底部选项卡等;内容页显示具体需要滚动的内容,然后在主页面中调用mui.init方法初始化内容页面。
官方文档中的这段说明,通俗来说就是将一个页面分解出来,比如把头部导航放在一个页面上,内容部分放到另一个页面上面,然后再将这两个页面结合在一起。上面官方文档说明中提到一个名称webview,关于webview在官方文档中也有说明:UI模块管理应用界面,用于操作加载HTML页面的原生窗口,调用系统原生控件等。由于此模块功能太多,现已根据功能分拆更新为Key、NativeUI、Navigatori等,并对接口和功能做了一些优化调整,请使用新API。模块管理应用窗口界面,实现多窗口的逻辑控制管理操作。通过plus.webview可获取应用界面管理对象。
如果暂时没有听懂或者不理解什么是webview也没事,写的多了就会慢慢理解了,多写多思考。
a.html页面中显示b.html页面,那么在a.html页面中这么写即可:
1 mui.init({ 2 subpages:[{ 3 url:your-subpage-url,//子页面HTML地址,支持本地地址和网络地址 4 id:your-subpage-id,//子页面标志 5 styles:{ 6 top:subpage-top-position,//子页面顶部位置 7 bottom:subpage-bottom-position,//子页面底部位置 8 width:subpage-width,//子页面宽度,默认为100% 9 height:subpage-height,//子页面高度,默认为100% 10 ...... 11 }, 12 extras:{}//额外扩展参数 13 }] 14 });
首先如上面这串代码所示,url处写b页面地址,id自己定义,默认为b页面url,下面的styles是b页面在a页面中显示的样式,比如b页面显示在a页面距离顶部导航栏45px处等等。extras是扩展参数,用不到可以不写。按照这个格式可以实现在a页面中显示b页面。
头部导航栏是header,底部选项卡是nav,例如头部导航栏举例:
1 <!-- 头部header开始 --> 2 <header class="mui-bar mui-bar-nav"> 3 <a class="mui-icon mui-icon-bars mui-pull-left"></a> 4 <a id="info" class="mui-icon mui-icon-info-filled mui-pull-right" style="color: #999;"></a> 5 <h1 class="mui-title">首页</h1> 6 </header> 7 <!-- 头部header结束 -->
这幅图是博文MUI(2)中实现的效果,博文MUI(2)在博文MUI(1)的基础之上又添加了一个页面策划菜单页面index_menu.html页面,这幅图红色框是index.html页面,绿色框是index_menu.html页面。而在绿色框的右侧外围红色框的右侧这部分区域是遮罩,博文MUI(2)中提到的遮罩效果。
1 <div class="mui-content"> 2 <div class="title">侧滑导航</div> 3 <div class="content"> 4 这个页面是侧滑导航页面,是单独的一个页面,作为侧滑页面出现。关闭这个侧滑菜单的方式:1.点击这个侧滑菜单页面之外的任意位置;2.点击下面这个红色按钮<span id="android-only">;3.Android手机按back键;4.Android手机按menu键</span>。 5 </div> 6 <p style="margin: 10px 15px;"> 7 <button id="close-btn" type="button" class="mui-btn mui-btn-danger mui-btn-block" style="padding: 5px 20px;">关闭侧滑菜单</button> 8 </p> 9 </div>
因为苹果手机不具备安卓手机的返回按键和菜单按键,所以需要设置当在苹果手机上面运行时隐藏上面代码中的第3点和第4点,需要单独设置样式和js代码进行判断并作出相应措施。
<span id="android-only">;3.Android手机按back键;4.Android手机按menu键</span>
相应的js代码:
1 mui.init();//初始化 2 var aniShow = null; 3 /*因为back按键和menu按键在ios平台不存在,所以ios平台下面需要隐藏,避免尴尬症。*/ 4 if(!mui.os.android) { 5 var span = document.getElementById("android-only"); 6 if(span) { 7 span.style.display = "none"; 8 } 9 aniShow = "pop-in";//页面显示动画 10 }
如果不是安卓手机平台那么作出相应措施,其实这些细节就需要我们程序员机制的机制咯。小编没有苹果手机,所以没有做苹果手机的测试。
1 /*关闭侧滑菜单*/ 2 function close() { 3 mui.fire(mui.currentWebview.opener(), "menu:close"); 4 } 5 /*点击"关闭侧滑菜单"按钮处理逻辑*/ 6 document.getElementById("close-btn").addEventListener('tap', close); 7 /*在Android4.4.2中的swipe事件,需要preventDefault一下,否则触发不正常*/ 8 window.addEventListener('dragstart', function(e) { 9 mui.gestures.touch.lockDirection = true; //锁定方向 10 mui.gestures.touch.startDirection = e.detail.direction; 11 }); 12 window.addEventListener('swipe', function(e) { 13 if(!mui.isScrolling) { 14 e.detail.gesture.preventDefault(); 15 } 16 }); 17 //监听左滑事件,若菜单已展开,左滑要关闭菜单 18 window.addEventListener('swipeleft', function(e) { 19 if(Math.abs(e.detail.angle) > 170) { 20 close(); 21 } 22 });
侧滑菜单页面中有一个按钮,其id为close-btn,对这个id进行监听,如果单击这个按钮,那么执行关闭侧滑菜单命令。
function close() {mui.fire(mui.currentWebview.opener(), "menu:close");}
关于这行代码乍一看平淡无奇,但是仔细观察:mui.fire官方文档中这样说明:通过mui.fire()
方法可触发目标窗口的自定义事件,格式为:.fire(target, event, data)
target Type:WebviewObject需要传值的目标webview;event Type;String自定义事件名称;data Type:JSONjson格式的数据。
官方文档在这一块还有一个温馨提示:
目标webview必须触发loaded事件后才能使用自定义事件
若新创建一个webview,不等该webview的loaded事件发生,就立即使用webview.evalJS()或mui.fire(webview,'eventName',{}),则可能无效;
currentWebview是获取当前窗口的webviewObject对象,返回值是:WebviewObject :Webview窗口对象。
Webview窗口对象,用于操作加载HTML页面的窗口;opener: 获取当前Webview窗口的创建者。
index.html页面中采用了plus.webview.currentWebview();创建菜单页面webview。那么就是返回到index.html页面,触发close事件后。
不用担心后期会再回到这篇博文的,会再次重新解释的,相信小编。
1 var menu = null, 2 main = null, 3 showMenu = false; 4 mui.plusReady(function() { 5 /*plus.screen.lockOrientation("portrait-primary");//仅仅支持竖屏显示*/ 6 main = plus.webview.currentWebview(); 7 main.addEventListener('maskClick', closeMenu); 8 //处理侧滑导航,为了避免和子页面初始化等竞争资源,延迟加载侧滑页面 9 setTimeout(function() { 10 menu = mui.preload({ 11 id: 'index_menu', 12 url: 'html/index_menu.html', 13 styles: { 14 left: '0px', 15 width: '70%', 16 zindex: -1 17 }, 18 show: { 19 aniShow: 'none' 20 } 21 }); 22 }, 200); 23 });
index.html页面中通过上面这篇代码加载了侧滑菜单页面,虽然在开始的时候并没有显示出来侧滑菜单,但是已经加载了。
1 var isInTransition = false; 2 /*显示侧滑菜单*/ 3 function openMenu() { 4 if(isInTransition) { 5 return; 6 } 7 if(!showMenu) { 8 //侧滑菜单处于隐藏状态,则立即显示处理 9 isInTransition = true; 10 menu.setStyle({ 11 mask: 'rgba(0,0,0,0)' 12 }); 13 //menu设置透明遮罩防止点击 14 menu.show('none', 0, function() { 15 //主窗体开始侧滑并显示遮罩 16 main.setStyle({ 17 mask: 'rgba(0,0,0,0.4)', //遮罩蒙版 18 left: '70%', 19 transition: { //一组用于定义页面或控件转换效果的属性 20 duration: 150 21 } 22 }); 23 mui.later(function() { 24 isInTransition = false; 25 menu.setStyle({ 26 mask: 'none' 27 }); 28 //移除menu的mask 29 }, 160); 30 showMenu = true; 31 }); 32 } 33 }
既然已经加载了,那么当我们点击打开侧滑菜单的时候就会很快显示在我们的眼前。好了上面这串代码就是实现打开侧滑菜单。
什么是mask呢?官方文档中这样给我们说明:
遮罩蒙版
在popover、侧滑菜单等界面,经常会用到蒙版遮罩;比如popover弹出后,除popover控件外的其它区域都会遮罩一层蒙版,用户点击蒙版不会触发蒙版下方的逻辑,而会关闭popover同时关闭蒙版;再比如侧滑菜单界面,菜单划出后,除侧滑菜单之外的其它区域都会遮罩一层蒙版,用户点击蒙版会关闭侧滑菜单同时关闭蒙版。
遮罩蒙版常用的操作包括:创建、显示、关闭,如下代码:
var mask = mui.createMask(callback);//callback为用户点击蒙版时自动执行的回调;
mask.show();//显示遮罩
mask.close();//关闭遮罩
注意:关闭遮罩仅会关闭,不会销毁;关闭之后可以再次调用mask.show();
打开遮罩;
mui默认的蒙版遮罩使用.mui-backdrop
类定义(如下代码),若需自定义遮罩效果,只需覆盖定义.mui-backdrop
即可;
.mui-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 998;
background-color: rgba(0,0,0,.3);
}
还有一个later是什么呢?不要着急,官方文档中有说明:
结合官方文档和前两篇博文提供的源代码,自己思考一下,敲一敲,试试看。
感觉无聊,想听一首音乐。没有添加其他页面,只是在index_list.html页面进行代码添加而已。
1 <!doctype html> 2 <html> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title></title> 7 <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> 8 <link href="../css/mui.min.css" rel="stylesheet" /> 9 </head> 10 11 <body> 12 <div class="mui-content"> 13 <div class="mui-popup-text" style="padding-left: 2em;padding-top: 15px;">你好,这里是另一个页面!欢迎您的到来。<br/>今天无聊放首本地歌曲听听。</div> 14 <div style="padding-left: 2em;padding-top: 15px;"> 15 <button id="musicStart" type="button" class="mui-btn mui-btn-primary">GO!</button><br /><br /> 16 <button id="musicPause" type="button" class="mui-btn mui-btn-primary">PAUSE!</button><br /><br /> 17 <button id="musicResume" type="button" class="mui-btn mui-btn-primary">RESUME!</button><br /><br /> 18 <button id="musicStop" type="button" class="mui-btn mui-btn-primary">STOP!</button><br /><br /> 19 </div> 20 </div> 21 <script src="../js/mui.min.js"></script> 22 <script type="text/javascript"> 23 mui.init(); //初始化 24 // 扩展API加载完毕后调用onPlusReady回调函数 25 document.addEventListener('plusready', onPlusReady, false); 26 // 扩展API加载完毕,现在可以正常调用扩展API 27 function onPlusReady() {} 28 var music = null; 29 //开始播放 30 document.getElementById("musicStart").addEventListener('tap',function (){ 31 if(plus.audio == undefined) { 32 alert("Device not ready!"); 33 } 34 music = plus.audio.createPlayer("../upload/file/music/caichunjia-qiangwei.mp3"); 35 music.play(function() { 36 alert("Audio play success!"); 37 }, function(e) { 38 alert("Audio play error!" + e.message); 39 }); 40 }); 41 //暂停播放 42 document.getElementById("musicPause").addEventListener('tap',function(){ 43 music.pause(); 44 }); 45 //恢复播放 46 document.getElementById("musicResume").addEventListener('tap',function(){ 47 music.resume(); 48 }); 49 //停止播放 50 document.getElementById("musicStop").addEventListener('tap',function(){ 51 music.stop(); 52 }); 53 </script> 54 </body> 55 56 </html>
暂时只支持播放本地音乐,播放、暂停、恢复、停止四个功能键。存在bug,尚未完善,后期会完善,这个后期不是后会无期的意思,不要误会,小编一定会完善的。
下面附上官方文档:http://www.html5plus.org/doc/zh_cn/audio.html
手机测试截图:测试手机系统参数:Android4.2.2.