頁面初始化
mui框架將很多功能配置都集中在mui.init方法中,要使用某項功能,只需要在mui.init方法中完成對應參數配置即可,目前支持在mui.init方法中配置的功能包括:創建子頁面、關閉頁面、手勢事件配置、預加載、下拉刷新、上拉加載。
在app開發中,若要使用HTML5+擴展api,必須等plusready事件發生后才能正常使用,mui將該事件封裝成了mui.plusReady()
方法,涉及到HTML5+的api,建議都寫在mui.plusReady方法中。如下為打印當前頁面URL的示例:
mui.plusReady(function(){ console.log("當前頁面URL:"+plus.webview.currentWebview().getURL()); });
創建子頁面
在mobile app開發過程中,經常遇到卡頭卡尾的頁面,此時若使用局部滾動,在android手機上會出現滾動不流暢的問題; mui的解決思路是:將需要滾動的區域通過單獨的webview實現,完全使用原生滾動。具體做法則是:將目標頁面分解為主頁面和內容頁面,主頁面顯示卡頭卡尾區域,比如頂部導航、底部選項卡等;內容頁面顯示具體需要滾動的內容,然后在主頁面中調用mui.init方法初始化內容頁面。
mui.init({ subpages:[{ url:your-subpage-url,//子頁面HTML地址,支持本地地址和網絡地址 id:your-subpage-id,//子頁面標志 styles:{ top:subpage-top-position,//子頁面頂部位置 bottom:subpage-bottom-position,//子頁面底部位置 width:subpage-width,//子頁面寬度,默認為100% height:subpage-height,//子頁面高度,默認為100% ...... }, extras:{}//額外擴展參數 }] });
參數說明:styles表示窗口屬性,參考5+規范中的WebviewStyle;特別注意,height和width兩個屬性,即使不設置,也默認按100%計算;因此若設置了top值為非"0px"的情況,建議同時設置bottom值,否則5+ runtime根據高度100%計算,可能會造成頁面真實底部位置超出屏幕范圍的情況;left、right同理。
示例:Hello mui的首頁其實就是index.html加list.html合並而成的,如下:



index.html的作用就是顯示固定導航,list.html顯示具體列表內容,列表項的滾動是在list.html所在webview中使用原生滾動,既保證了滾動條不會穿透頂部導航,符合app的體驗,也保證了列表流暢滾動,解決了區域滾動卡頓的問題。 list.html就是index.html的子頁面,創建代碼比較簡單,如下:
mui.init({ subpages:[{ url:'list.html', id:'list.html', styles:{ top:'45px',//mui標題欄默認高度為45px; bottom:'0px'//默認為0px,可不定義; } }] });
打開新頁面
做web app,一個無法避開的問題就是轉場動畫;web是基於鏈接構建的,從一個頁面點擊鏈接跳轉到另一個頁面,如果通過有刷新的打開方式,用戶要面對一個空白的頁面等待;如果通過無刷新的方式,用Javascript移入DOM節點(常見的SPA解決方案),會碰到很高的性能挑戰:DOM節點繁多,頁面太大,轉場動畫不流暢甚至導致瀏覽器崩潰; mui的解決思路是:單webview只承載單個頁面的dom,減少dom層級及頁面大小;頁面切換使用原生動畫,將最耗性能的部分交給原生實現.
mui.openWindow({
url:new-page-url,
id:new-page-id,
styles:{
top:newpage-top-position,//新頁面頂部位置
bottom:newage-bottom-position,//新頁面底部位置
width:newpage-width,//新頁面寬度,默認為100%
height:newpage-height,//新頁面高度,默認為100%
......
},
extras:{
.....//自定義擴展參數,可以用來處理頁面間傳值
},
createNew:false,//是否重復創建同樣id的webview,默認為false:不重復創建,直接顯示
show:{
autoShow:true,//頁面loaded事件發生后自動顯示,默認為true
aniShow:animationType,//頁面顯示動畫,默認為”slide-in-right“;
duration:animationTime//頁面動畫持續時間,Android平台默認100毫秒,iOS平台默認200毫秒;
},
waiting:{
autoShow:true,//自動顯示等待框,默認為true
title:'正在加載...',//等待對話框上顯示的提示內容
options:{
width:waiting-dialog-widht,//等待框背景區域寬度,默認根據內容自動計算合適寬度
height:waiting-dialog-height,//等待框背景區域高度,默認根據內容自動計算合適高度
......
}
}
})
參數說明:
- styles表示窗口參數,參考5+規范中的WebviewStyle;特別注意,height和width兩個屬性,即使不設置,也默認按100%計算;因此若設置了top值為非"0px"的情況,建議同時設置bottom值,否則5+ runtime根據高度100%計算,可能會造成頁面真實底部位置超出屏幕范圍的情況;left、right同理。
- extras:新窗口的額外擴展參數,可用來處理頁面間傳值;例如:
var webview = mui.openWindow({url:'info.html',extras:{name:'mui'}});console.log(webview.name);
,會輸出"mui"字符串;注意:擴展參數僅在打開新窗口時有效,若目標窗口為預加載頁面,則通過mui.openWindow方法打開時傳遞的extras參數無效。 - createNew:是否重復創建相同id的webview;為優化性能、避免app中重復創建webview,mui v1.7.0開始增加createNew參數,默認為false;判斷邏輯如下:若createNew為true,則不判斷重復,每次都新建webview;若為fasle,則先計算當前App中是否已存在同樣id的webview,若存在則直接顯示;否則新創建並根據show參數執行顯示邏輯;該參數可能導致的影響:若業務寫在plusReady事件中,而plusReady事件僅首次創建時會觸發,則下次再次通過
mui.openWindow
方法打開同樣webview時,是不會再次觸發plusReady事件的,此時可通過自定義事件觸發;案例參考:http://ask.dcloud.net.cn/question/6514; - show表示窗口顯示控制。autoShow:目標窗口loaded事件發生后,是否自動顯示;若目標頁面為預加載頁面,則該參數無效;aniShow表示頁面顯示動畫,比如從右側划入、從下側划入等,具體可參考5+規范中的AnimationTypeShow
-
waiting表示系統等待框;mui框架在打開新頁面時等待框的處理邏輯為:顯示等待框-->創建目標頁面webview-->目標頁面loaded事件發生-->關閉等待框;因此,只有當新頁面為新創建頁面(webview)時,會顯示等待框,否則若為預加載好的頁面,則直接顯示目標頁面,不會顯示等待框。waiting中的參數:autoShow表示自動顯示等待框,默認為true,若為false,則不顯示等待框;注意:若顯示了等待框,但目標頁面不自動顯示,則需在目標頁面中通過如下代碼關閉等待框
plus.nativeUI.closeWaiting();
。title表示等待框上的提示文字,options表示等待框顯示參數,比如寬高、背景色、提示文字顏色等,具體可參考5+規范中的WaitingOption。
示例1:Hello mui中,點擊首頁右上角的圖標,會打開關於頁面,實現代碼如下:
//tap為mui封裝的單擊事件,可參考手勢事件章節 document.getElementById('info').addEventListener('tap', function() { //打開關於頁面 mui.openWindow({ url: 'examples/info.html', id:'info' }); });
因沒有傳入styles參數,故默認全屏顯示;也沒有傳入show參數,故使用slide-in-right動畫,新頁面從右側滑入。
示例2:從A頁面打開B頁面,B頁面為一個需要從服務端加載的列表頁面,若在B頁面loaded事件發生時就將其顯示出來,因服務器數據尚未加載完畢,列表頁面為空,用戶體驗不好;可通過如下方式改善用戶體驗(最好的用戶體驗應該是通過預加載的方式):第一步,B頁面loaded事件發生后,不自動顯示;
//A頁面中打開B頁面,設置show的autoShow為false,則B頁面在其loaded事件發生后,不會自動顯示; mui.openWindow({ url: 'B.html', show:{ autoShow:false } });
第二步,在B頁面獲取列表數據后,再關閉等待框、顯示B頁面
//B頁面onload從服務器獲取列表數據; window.onload = function(){ //從服務器獲取數據 .... //業務數據獲取完畢,並已插入當前頁面DOM; //注意:若為ajax請求,則需將如下代碼放在處理完ajax響應數據之后; mui.plusReady(function(){ //關閉等待框 plus.nativeUI.closeWaiting(); //顯示當前頁面 mui.currentWebview.show(); }); }
關閉頁面
mui框架將窗口關閉功能封裝在mui.back
方法中,具體執行邏輯是:
- 若當前webview為預加載頁面,則hide當前webview;
- 否則,close當前webview;
在mui框架中,有三種操作會觸發頁面關閉(執行mui.back方法):
- 點擊包含
.mui-action-back
類的控件 - 在頁面上,向右快速滑動
- Android手機按下back按鍵
hbuilder中敲mheader
生成的代碼塊,會自動生成帶有返回導航箭頭的標題欄,點擊返回箭頭可關閉當前頁面,原因就是因為該返回箭頭包含.mui-action-back
類,代碼如下:
<header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-icon mui-icon-left-nav mui-pull-left"></a> <h1 class="mui-title">標題</h1> </header>
若希望在頂部導航欄之外的其它區域添加關閉頁面的控件,只需要在對應控件上添加.mui-action-back
類即可,如下為一個關閉按鈕示例:
<button type="button" class='mui-btn mui-btn-danger mui-action-back'>關閉</button>
mui框架封裝的頁面右滑關閉功能,默認未啟用,若要使用右滑關閉功能,需要在mui.init();
方法中設置swipeBack參數,如下:
mui.init({ swipeBack:true //啟用右滑關閉功能 });
mui框架默認會監聽Android手機的back按鍵,然后執行頁面關閉邏輯; 若不希望mui自動處理back按鍵,可通過如下方式關閉mui的back按鍵監聽;
mui.init({ keyEventBind: { backbutton: false //關閉back按鍵監聽 } });
除了如上三種操作外,也可以直接調用mui.back()
方法,執行窗口關閉邏輯;
mui.back()
僅處理窗口邏輯,若希望在窗口關閉之前再處理一些其它業務邏輯,則可將業務邏輯抽象成一個具體函數,然后注冊為mui.init方法的beforeback參數;beforeback的執行邏輯為:
- 執行beforeback參數對應的函數若返回false,則不再執行
mui.back()
方法; - 否則(返回true或無返回值),繼續執行
mui.back()
方法;
示例:從列表打開詳情頁面,從詳情頁面再返回后希望刷新列表界面,此時可注冊beforeback參數,然后通過自定義事件通知列表頁面刷新數據,示例代碼如下:
mui.init({ beforeback: function(){ //獲得列表界面的webview var list = plus.webview.getWebviewById('list'); //觸發列表界面的自定義事件(refresh),從而進行數據刷新 mui.fire(list,'refresh'); //返回true,繼續頁面關閉邏輯 return true; } });
注意:beforeback的執行返回必須是同步的(阻塞模式),若使用nativeUI這種異步js(非阻塞模式),則可能會出現意想不到的結果;比如:通過plus.nativeUI.confirm()
彈出確認框,可能用戶尚未選擇,頁面已經返回了(beforeback同步執行完畢,無返回值,繼續執行mui.back()
方法,nativeUI不會阻塞js進程):在這種情況下,若要自定義業務邏輯,就需要復寫mui.back
方法了;如下為一個自定義示例,每次都需要用戶確認后,才會關閉當前頁面
//備份mui.back,mui.back已將窗口關閉邏輯封裝的比較完善(預加載及父子窗口),因此最好復用mui.back var old_back = mui.back; mui.back = function(){ var btn = ["確定","取消"]; mui.confirm('確認關閉當前窗口?','Hello MUI',btn,function(e){ if(e.index==0){ //執行mui封裝好的窗口關閉邏輯; old_back(); } }); }
注意:自定義關閉邏輯時,一定要重寫mui.back,不能簡單通過addEventListener增加back按鍵監聽, 因為addEventListener只會增加新的執行邏輯,老的監聽邏輯依然會執行;
Ajax
mui框架基於htm5plus的XMLHttpRequest,封裝了常用的Ajax函數,支持GET、POST請求方式,支持返回json、xml、html、text、script數據類型; 本着極簡的設計原則,mui提供了mui.ajax方法,並在mui.ajax方法基礎上,進一步簡化出最常用的mui.get()、mui.getJSON()、mui.post()三個方法。
mui.ajax()方法通過HTTP請求加載遠程數據,是mui框架底層Ajax的實現方法,使用方法:mui.ajax(url[,setting])
,其中url表示請求發送的目標地址,setting是一個json對象,支持的參數主要包括:
參數 | 類型 | 描述 |
data | Object | 發送到服務器的數據,可以是json對象或字符串 |
dataType | String | 預期服務器返回的數據類型;如果不指定,mui將自動根據HTTP包的MIME頭信息自動判斷;支持設置的dataType可選值:
|
error | Function | 請求失敗時觸發的函數,該函數接收三個參數:
|
success | Function | 請求成功時觸發的回調函數,該函數接收三個參數:
|
timeout | Number | 請求超時時間(毫秒),默認值為0,表示永不超時;若超過設置的超時時間(非0的情況),依然未收到服務器響應,則觸發error回調 |
type | String | 請求方式,目前僅支持'GET'和'POST',默認為'GET'方式 |
代碼示例:如下為通過post方式向某服務器發送鑒權登錄的代碼片段
mui.ajax('http://server-name/login.php',{ data:{ username:'username', password:'password' }, dataType:'json',//服務器返回json格式數據 type:'post',//HTTP請求類型 timeout:10000,//超時時間設置為10秒; success:function(data){ //服務器返回響應,根據響應結果,分析是否登錄成功; ... }, error:function(xhr,type,errorThrown){ //異常處理; console.log(type); } });
mui.post()
方法是對mui.ajax()
的一個簡化方法,直接使用POST請求方式向服務器發送數據、且不處理timeout和異常(若需處理異常及超時,請使用mui.ajax()
方法),使用方法: mui.post(url[,data][,success][,dataType])
,如上登錄鑒權代碼換成mui.post()
后,代碼更為簡潔,如下:
mui.post('http://server-name/login.php',{ username:'username', password:'password' },function(data){ //服務器返回響應,根據響應結果,分析是否登錄成功; ... },'json' );
mui.get()
方法和mui.post()
方法類似,只不過是直接使用GET請求方式向服務器發送數據、且不處理timeout和異常(若需處理異常及超時,請使用mui.ajax()
方法),使用方法: mui.get(url[,data][,success][,dataType])
,如下為獲得某服務器新聞列表的代碼片段,服務器以json格式返回數據列表
mui.get('http://server-name/list.php',{category:'news'},function(data){ //獲得服務器響應 ... },'json' );
如上mui.get()
方法和如下mui.ajax()
方法效果是一致的:
mui.ajax('http://server-name/list.php',{ data:{ category:'news' }, dataType:'json',//服務器返回json格式數據 type:'get',//HTTP請求類型 success:function(data){ //獲得服務器響應 ... } });
mui.getJSON()
方法是在mui.get()
方法基礎上的更進一步簡化,限定返回json格式的數據,其它參數和mui.get()
方法一致,使用方法: mui.get(url[,data][,success])
,如上獲得新聞列表的代碼換成mui.getJSON()
方法后,更為簡潔,如下:
mui.getJSON('http://server-name/list.php',{category:'news'},function(data){ //獲得服務器響應 ... } );
手勢事件
在開發移動端的應用時,會用到很多的手勢操作,比如滑動、長按等,為了方便開放者快速集成這些手勢,mui內置了常用的手勢事件,目前支持的手勢事件見如下列表:
分類 | 參數 | 描述 |
---|---|---|
點擊 | tap | 單擊屏幕 |
doubletap | 雙擊屏幕 | |
長按 | longtap | 長按屏幕 |
hold | 按住屏幕 | |
release | 離開屏幕 | |
滑動 | swipeleft | 向左滑動 |
swiperight | 向右滑動 | |
swipeup | 向上滑動 | |
swipedown | 向下滑動 | |
拖動 | dragstart | 開始拖動 |
drag | 拖動中 | |
dragend | 拖動結束 |
手勢事件配置
根據使用頻率,mui默認會監聽部分手勢事件,如點擊、滑動事件;為了開發出更高性能的moble App,mui支持用戶根據實際業務需求,通過mui.init方法中的gestureConfig參數,配置具體需要監聽的手勢事件,。
mui.init({ gestureConfig:{ tap: true, //默認為true doubletap: true, //默認為false longtap: true, //默認為false swipe: true, //默認為true drag: true, //默認為true hold:false,//默認為false,不監聽 release:false//默認為false,不監聽 } });
注意:dragstart、drag、dragend共用drag開關,swipeleft、swiperight、swipeup、swipedown共用swipe開關
事件監聽
同標准click事件一樣,上述手勢事件支持添加到任意DOM對象上,如下為一個示例:
elem.addEventListener("swipeleft",function(){ console.log("你正在向左滑動"); });
預加載
所謂的預加載技術就是在用戶尚未觸發頁面跳轉時,提前創建目標頁面,這樣當用戶跳轉時,就可以立即進行頁面切換,節省創建新頁面的時間,提升app使用體驗。mui提供兩種方式實現頁面預加載。
方式一:通過mui.init方法中的preloadPages參數進行配置.
mui.init({ preloadPages:[ { url:prelaod-page-url, id:preload-page-id, styles:{},//窗口參數 extras:{},//自定義擴展參數 subpages:[{},{}]//預加載頁面的子頁面 } ] });
該種方案使用簡單、可預加載多個頁面,但不會返回預加載每個頁面的引用,若要獲得對應webview引用,還需要通過plus.webview.getWebviewById
方式獲得;另外,因為mui.init是異步執行,執行完mui.init方法后立即獲得對應webview引用,可能會失敗,例如如下代碼:
mui.init({ preloadPages:[ { url:'list.html', id:'list' } ] }); var list = plus.webview.getWebviewByid('list');//這里可能返回空;
方式二:通過mui.preload方法預加載.
var page = mui.preload({ url:new-page-url, id:new-page-id,//默認使用當前頁面的url作為id styles:{},//窗口參數 extras:{}//自定義擴展參數 });
通過mui.preload()
方法預加載,可立即返回對應webview的引用,但一次僅能預加載一個頁面;若需加載多個webview,則需多次調用mui.preload()
方法;
如上兩種方案,各有優劣,需根據具體業務場景靈活選擇;
下拉刷新
為實現下拉刷新功能,大多H5框架都是通過DIV模擬下拉回彈動畫,在低端android手機上,DIV動畫經常出現卡頓現象(特別是圖文列表的情況); mui通過雙webview解決這個DIV的拖動流暢度問題;拖動時,拖動的不是div,而是一個完整的webview(子webview),回彈動畫使用原生動畫;在iOS平台,H5的動畫已經比較流暢,故依然使用H5方案。兩個平台實現雖有差異,但mui經過封裝,可使用一套代碼實現下拉刷新。
主頁面內容比較簡單,只需要創建子頁面即可:
mui.init({ subpages:[{ url:pullrefresh-subpage-url,//下拉刷新內容頁面地址 id:pullrefresh-subpage-id,//內容頁面標志 styles:{ top:subpage-top-position,//內容頁面頂部位置,需根據實際頁面布局計算,若使用標准mui導航,頂部默認為48px; .....//其它參數定義 } }] });
內容頁面需按照如下DOM結構構建:
<!--下拉刷新容器--> <div id="refreshContainer" class="mui-content mui-scroll-wrapper"> <div class="mui-scroll"> <!--數據列表--> <ul class="mui-table-view mui-table-view-chevron"> </ul> </div> </div>
其次,通過mui.init方法中pullRefresh參數配置下拉刷新各項參數,如下:
mui.init({ pullRefresh : { container:"#refreshContainer",//下拉刷新容器標識,querySelector能定位的css選擇器均可,比如:id、.class等 down : { contentdown : "下拉可以刷新",//可選,在下拉可刷新狀態時,下拉刷新控件上顯示的標題內容 contentover : "釋放立即刷新",//可選,在釋放可刷新狀態時,下拉刷新控件上顯示的標題內容 contentrefresh : "正在刷新...",//可選,正在刷新狀態時,下拉刷新控件上顯示的標題內容 callback :pullfresh-function //必選,刷新函數,根據具體業務來編寫,比如通過ajax從服務器獲取新數據; } } });
最后,根據具體業務編寫刷新函數,需要注意的是,加載完新數據后,需要執行endPulldownToRefresh()方法;
function pullfresh-function() { //業務邏輯代碼,比如通過ajax從服務器獲取新數據; ...... //注意,加載完新數據后,必須執行如下代碼,注意:若為ajax請求,則需將如下代碼放置在處理完ajax響應數據之后 mui('#refreshContainer').pullRefresh().endPulldownToRefresh(); }
上拉加載
mui的上拉加載實現比較簡單,檢測5+ runtime提供的滾動條滾動到底事件(plusscrollbottom),顯示“正在加載”提示-->開始加載業務數據-->隱藏"正在加載"提示。使用方式類似下拉刷新,首先、通過mui.init方法中pullRefresh參數配置上拉加載各項參數,如下:
mui.init({ pullRefresh : { container:refreshContainer,//待刷新區域標識,querySelector能定位的css選擇器均可,比如:id、.class等 up : { contentrefresh : "正在加載...",//可選,正在加載狀態時,上拉加載控件上顯示的標題內容 contentnomore:'沒有更多數據了',//可選,請求完畢若沒有更多數據時顯示的提醒內容; callback :pullfresh-function //必選,刷新函數,根據具體業務來編寫,比如通過ajax從服務器獲取新數據; } } });
其次,根據具體業務編寫加載函數,需要注意的是,加載完新數據后,需要執行endPullupToRefresh()方法;
function pullfresh-function() { //業務邏輯代碼,比如通過ajax從服務器獲取新數據; ...... //注意,加載完新數據后,必須執行如下代碼,true表示沒有更多數據了,兩個注意事項: //1、若為ajax請求,則需將如下代碼放置在處理完ajax響應數據之后 //2、注意this的作用域,若存在匿名函數,需將this復制后使用,參考hello mui中的代碼示例; this.endPullupToRefresh(true|false); }
注意:
- 因為使用的是滾動到底事件,因此若當前頁面內容過少,沒有滾動條的話,就不會觸發上拉加載
- 多次上拉加載后,若已沒有更多數據可加載時,調用
this.endPullupToRefresh(true);
,之后滾動條滾動到底時,將不再顯示“上拉顯示更多”的提示語,而顯示“沒有更多數據了”的提示語; - 若實際業務中,有重新觸發上拉加載的需求(比如當前類別已無更多數據,但切換到另外一個類別后,應支持繼續上拉加載),此時調用上拉加載的重置函數即可,如下代碼:
//pullup-container為在mui.init方法中配置的pullRefresh節點中的container參數; mui('#pullup-container').pullRefresh().refresh(true);
輸入增強
mui目前提供的輸入增強包括:快速刪除和語音輸入兩項功能。要刪除輸入框中的內容,使用輸入法鍵盤上的刪除按鍵,只能逐個刪除字符,mui提供了快速刪除能力,只需要在對應input控件上添加.mui-input-clear
類,當input控件中有內容時,右側會有一個刪除圖標,點擊會清空當前input的內容;另外,為了方便快速輸入,mui集成了HTML5+的語音輸入,只需要在對應input控件上添加.mui-input-speech
類,就會在該控件右側顯示一個語音輸入的圖標,點擊會啟用科大訊飛語音輸入界面。
開關事件
mui提供了開關控件樣式,點擊滑動兩種手勢都可以對開關控件進行操作,在開關控件進行切換時,會觸發toggle事件,通過事件的detail.isActive屬性可以判斷當前開關狀態。可通過監聽toggle事件,在開關切換時執行特定業務邏輯。如下為使用示例:
document.getElementById("mySwitch").addEventListener("toggle",function(event){ if(event.detail.isActive){ console.log("你啟動了開關"); }else{ console.log("你關閉了開關"); } })
若要獲得當前開關狀態,可通過判斷當前開關控件是否包含.mui-active
類來實現,若包含,則為打開狀態,否則即為關閉狀態;如下為代碼示例:
var isActive = document.getElementById("mySwitch").classList.contains("mui-active"); if(isActive){ console.log("打開狀態"); }else{ console.log("關閉狀態"); }
若使用js打開、關閉開關控件,可使用switch插件的toggle()
方法,如下為示例代碼:
mui("#mySwitch").switch().toggle();
slide事件
mui提供了圖片輪播、可拖動式圖文表格、可拖動式選項卡、左右滑動9宮格組件,這些組件都用到了mui框架的slide插件,有較多共同點。首先,Dom內容構造基本相同,都必須有一個.mui-slider
的父容器;其次,當拖動切換顯示內容時,均會觸發slide事件(可拖動式選項卡在點擊選項卡標題時,也會觸發slide事件),通過該事件的detail.slideNumber參數可以獲得當前顯示項的索引(第一項索引為0,第二項為1,以此類推),利用該事件,可在顯示內容切換時,動態處理一些業務邏輯。
如下為一個可拖動式選項卡示例,為提高頁面加載速度,頁面加載時,僅顯示第一個選項卡的內容,第二、第三選項卡內容為空。
<div class="mui-slider"> <!--選項卡標題區--> <div class="mui-slider-indicator mui-segmented-control mui-segmented-control-inverted"> <a class="mui-control-item" href="#item1">待辦公文</a> <a class="mui-control-item" href="#item2">已辦公文</a> <a class="mui-control-item" href="#item3">全部公文</a> </div> <div class="mui-slider-progress-bar mui-col-xs-4"></div> <div class="mui-slider-group"> <!--第一個選項卡內容區--> <div id="item1" class="mui-slider-item mui-control-content mui-active"> <ul class="mui-table-view"> <li class="mui-table-view-cell">待辦公文1</li> <li class="mui-table-view-cell">待辦公文2</li> <li class="mui-table-view-cell">待辦公文3</li> </ul> </div> <!--第二個選項卡內容區,頁面加載時為空--> <div id="item2" class="mui-slider-item mui-control-content"></div> <!--第三個選項卡內容區,頁面加載時為空--> <div id="item3" class="mui-slider-item mui-control-content"></div> </div> </div>
當切換到第二、第三個選項卡時,再動態獲取相應內容進行顯示:
var item2Show = false,item3Show = false;//子選項卡是否顯示標志 document.querySelector('.mui-slider').addEventListener('slide', function(event) { if (event.detail.slideNumber === 1&&!item2Show) { //切換到第二個選項卡 //根據具體業務,動態獲得第二個選項卡內容; var content = .... //顯示內容 document.getElementById("item2").innerHTML = content; //改變標志位,下次直接顯示 item2Show = true; } else if (event.detail.slideNumber === 2&&!item3Show) { //切換到第三個選項卡 //根據具體業務,動態獲得第三個選項卡內容; var content = .... //顯示內容 document.getElementById("item3").innerHTML = content; //改變標志位,下次直接顯示 item3Show = true; } });
圖片輪播、可拖動式圖文表格等均可按照同樣方式監聽內容變化,比如我們可以在圖片輪播界面顯示當前正在看的是第幾張圖片:
document.querySelector('.mui-slider').addEventListener('slide', function(event) { //注意slideNumber是從0開始的; document.getElementById("info").innerText = "你正在看第"+(event.detail.slideNumber+1)+"張圖片"; });
自定義事件
用戶開發應用中會大量使用事件功能。除了瀏覽器內置的事件及mui框架內置的事件(比如手勢事件)外,mui同時支持用戶觸發和綁定自定義事件。通過自定義事件,用戶可以輕松實現頁面間數據傳遞。
監聽自定義事件
添加自定義事件監聽操作和標准js事件監聽類似,可直接通過window對象添加,如下:
window.addEventListener('customEvent',function(event){ //通過event.detail可獲得傳遞過來的參數內容 .... });
觸發自定義事件
通過mui.fire方法可觸發目標窗口的自定義事件:
mui.fire(targetPage,'customEvent',{ //自定義事件參數 });
示例:假設如下場景:從新聞列表頁面進入新聞詳情頁面,新聞詳情頁面為共用頁面,通過傳遞新聞ID通知詳情頁面需要顯示具體哪個新聞,詳情頁面再動態向服務器請求數據,mui要實現類似需求可通過如下步驟實現:
- 在列表頁面中預加載詳情頁面(假設為detail.html)
- 列表頁面在點擊新聞標題時,首先,獲得該新聞id,觸發詳情頁面的newsId事件,並將新聞id作為事件參數傳遞過去;然后再打開詳情頁面;
- 詳情頁面監聽newsId自定義事件
列表頁面代碼如下:
//初始化預加載詳情頁面 mui.init({ preloadPages:[{ id:'detail.html', url:'detail.html' } ] }); var detailPage = null; //添加列表項的點擊事件 mui('.mui-content').on('tap', 'a', function(e) { var id = this.getAttribute('id'); //獲得詳情頁面 if(!detailPage){ detailPage = plus.webview.getWebviewById('detail.html'); } //觸發詳情頁面的newsId事件 mui.fire(detailPage,'newsId',{ id:id }); //打開詳情頁面 mui.openWindow({ id:'detail.html' }); });
詳情頁面代碼如下:
//添加newId自定義事件監聽 window.addEventListener('newsId',function(event){ //獲得事件參數 var id = event.detail.id; //根據id向服務器請求新聞詳情 ..... });
圖片輪播
mui框架內置了圖片輪播插件,通過該插件封裝的JS API,用戶可以設定是否自動輪播及輪播周期,如下為代碼示例:
//獲得slider插件對象 var gallery = mui('.mui-slider'); gallery.slider({ interval:5000//自動輪播周期,若為0則不自動播放,默認為0; });
因此若希望圖片輪播不要自動播放,而是用戶手動滑動才切換,只需要通過如上方法,將slideshowDelay參數設為0即可。
若要跳轉到第x張圖片,則可以使用圖片輪播插件的gotoItem方法,例如:
//獲得slider插件對象 var gallery = mui('.mui-slider'); gallery.slider().gotoItem(index);//跳轉到第index張圖片,index從0開始;
圖片輪播涉及的另外一個問題:是否支持循環播放,比如有1、2、3、4四張圖片,從第1張圖片起,依次向左滑動切換圖片,當切換到第4張圖片時,繼續向左滑動,接下來會有兩種效果:
- 支持循環:左滑,直接切換到第1張圖片;
- 不支持循環:左滑,無反應,繼續顯示第4張圖片,用戶若要顯示第1張圖片,必須連續向右滑動切換到第1張圖片;
當顯示第1張圖片時,繼續右滑是否顯示第4張圖片,是同樣問題;這個問題的實現需要通過.mui-slider-loop
類及DOM節點來控制;若不支持循環,代碼比較簡單,如下:
<div class="mui-slider"> <div class="mui-slider-group"> <div class="mui-slider-item"><a href="#"><img src="1.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="2.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="3.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="4.jpg" /></a></div> </div> </div>
若要支持循環,則需要在.mui-slider-group
節點上增加.mui-slider-loop
類,同時需要重復增加2張圖片,圖片順序變為:4、1、2、3、4、1,代碼示例如下:
<div class="mui-slider"> <div class="mui-slider-group mui-slider-loop"> <!--支持循環,需要重復圖片節點--> <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="4.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="1.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="2.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="3.jpg" /></a></div> <div class="mui-slider-item"><a href="#"><img src="4.jpg" /></a></div> <!--支持循環,需要重復圖片節點--> <div class="mui-slider-item mui-slider-item-duplicate"><a href="#"><img src="1.jpg" /></a></div> </div> </div>
注意:mui框架會默認初始化當前頁面的圖片輪播組件;若輪播組件內容為js動態生成時(比如通過ajax動態獲取的營銷信息),則需要在動態DOM生成后,手動調用圖片輪播的初始化方法;代碼如下:
//獲得slider插件對象 var gallery = mui('.mui-slider'); gallery.slider({ interval:5000//自動輪播周期,若為0則不自動播放,默認為0; });
側滑導航
mui提供了兩種側滑導航實現:webview模式和div模式,兩種模式各有優劣,適用於不同的場景。
webview模式
主頁面和菜單內容在不同的webview中,兩個頁面根據內容需求分別組織DOM結構,mui對其DOM結構無特殊要求,故其有如下優點:
- 菜單內容是單獨的webview,故可被多個頁面復用;
- 菜單內容在單獨的webview中,菜單區域的滾動不影響主界面,故可使用原生滾動,滾動更為流暢;
另一方面,webview模式也有其缺點:
- 不支持拖動手勢(跟手拖動);
- 主頁面、菜單不同webview實現,因此若需交互(如:點擊菜單觸發主頁面內容變化),需使用自定義事件實現跨webview通訊;
div模式
主頁面和菜單內容在同一個webview下,嵌套在特定結構的div中,通過div的移動動畫模擬菜單移動;故該模式有如下優點:
- 支持拖動手勢(跟手拖動);
- 主頁面、菜單在一個頁面中,可通過JS輕松實現兩者交互(如:點擊菜單觸發主頁面內容變化),沒有跨webview通訊的煩惱;
另一方面,div模式也有其缺點:
- 不支持菜單內容在多頁面的復用,需每個頁面都生成對應的菜單節點;
- 主界面和菜單內容的滾動互不影響,因此會使用div區域滾動,在低端Android手機且滾動內容較多時,可能會稍顯卡頓;
div模式支持不同的動畫效果,每種動畫效果需遵從不同的DOM構造;下面我們以右滑菜單為例(左滑菜單僅需將菜單父節點上的mui-off-canvas-left
換成mui-off-canvas-right
即可),說明每種動畫對應的DOM結構。
動畫1:主界面移動、菜單不動
<!-- 側滑導航根容器 --> <div class="mui-off-canvas-wrap mui-draggable"> <!-- 菜單容器 --> <aside class="mui-off-canvas-left"> <div class="mui-scroll-wrapper"> <div class="mui-scroll"> <!-- 菜單具體展示內容 --> ... <div> </div> </aside> <!-- 主頁面容器 --> <div class="mui-inner-wrap"> <!-- 主頁面標題 --> <header class="mui-bar mui-bar-nav"> <a class="mui-icon mui-action-menu mui-icon-bars mui-pull-left"></a> <h1 class="mui-title">標題</h1> </header> <div class="mui-content mui-scroll-wrapper"> <div class="mui-scroll"> <!-- 主界面具體展示內容 --> ... </div> </div> </div> </div>
動畫2:主界面不動、菜單移動
該種動畫要求的DOM結構和動畫1的DOM結構基本相同,唯一差別就是需在側滑導航根容器class上增加一個mui-slide-in
類
動畫3:主界面、菜單同時移動
該種動畫要求的DOM結構較特殊,需將菜單容器放在主頁面容器之下
<!-- 側滑導航根容器 --> <div class="mui-off-canvas-wrap mui-draggable"> <!-- 主頁面容器 --> <div class="mui-inner-wrap"> <!-- 菜單容器 --> <aside class="mui-off-canvas-left"> <div class="mui-scroll-wrapper"> <div class="mui-scroll"> <!-- 菜單具體展示內容 --> ... <div> </div> </aside> <!-- 主頁面標題 --> <header class="mui-bar mui-bar-nav"> <a class="mui-icon mui-action-menu mui-icon-bars mui-pull-left"></a> <h1 class="mui-title">標題</h1> </header> <!-- 主頁面內容容器 --> <div class="mui-content mui-scroll-wrapper"> <div class="mui-scroll"> <!-- 主界面具體展示內容 --> ... </div> </div> </div> </div>
mui支持多種方式顯示div模式的側滑菜單:1、在主界面向右拖動(drag);2、點擊含有mui-action-menu
類的控件;3、Android手機按menu鍵;4、通過JS API觸發,如下:
mui('.mui-off-canvas-wrap').offCanvas('show');
同樣,mui支持多種方式關閉div模式的側滑菜單:1、在手機屏幕上任意位置向左拖動(drag);2、點擊主界面內任意位置;3、Android手機按menu鍵;4、Android手機按back鍵;5、通過JS API觸發,如下:
mui('.mui-off-canvas-wrap').offCanvas('close');
彈出菜單
mui框架內置了彈出菜單插件,彈出菜單顯示內容不限,但必須包裹在一個含.mui-popover
類的div中,如下即為一個彈出菜單內容:
<div id="popover" class="mui-popover"> <ul class="mui-table-view"> <li class="mui-table-view-cell"><a href="#">Item1</a></li> <li class="mui-table-view-cell"><a href="#">Item2</a></li> <li class="mui-table-view-cell"><a href="#">Item3</a></li> <li class="mui-table-view-cell"><a href="#">Item4</a></li> <li class="mui-table-view-cell"><a href="#">Item5</a></li> </ul> </div>
要顯示、隱藏如上菜單,mui推薦使用錨點方式,例如:
<a href="#popover" class="mui-btn mui-btn-primary mui-btn-block">打開彈出菜單</a>
點擊如上定義的按鈕,即可顯示彈出菜單,再次點擊彈出菜單之外的其他區域,均可關閉彈出菜單;這種使用方式最為簡潔。
若希望通過js的方式控制彈出菜單,則通過如下一個方法即可:
//傳入toggle參數,用戶也無需關心當前是顯示還是隱藏狀態,mui會自動識別處理; mui('.mui-popover').popover('toggle');
遮罩蒙版
在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); }