DCloud-MUI:窗口管理

ylbtech-DCloud-MUI:窗口管理

經過預加載解決切頁白屏問題,經過封裝原生動畫解決SPA模式的動畫卡頓html

1.返回頂部
一、頁面初始化

在app開發中,若要使用HTML5+擴展api,必須等plusready事件發生後才能正常使用,mui將該事件封裝成了mui.plusReady()方法,涉及到HTML5+的api,建議都寫在mui.plusReady方法中。以下爲打印當前頁面URL的示例:html5

mui.plusReady(function(){
     console.log("當前頁面URL:"+plus.webview.currentWebview().getURL());
});

擴展閱讀
mui.init() mui插件初始化
mui.ready() 當DOM準備就緒時,指定一個函數來執行。
代碼塊激活字符: minitandroid

二、建立子頁面

在mobile app開發過程當中,常常會出現共用的導航欄或者選項卡,每次打開頁面都須要從新渲染,並且容易出現卡頭卡尾的現象。而且此時若使用局部滾動,在android手機上會出現滾動不流暢的問題;web

mui如今提供兩種解決方案:

第一種(官方推薦):在plus環境下,使用原生titleNView以及原生tabbar來替換頁面的導航欄或者選項卡。在頁面打開時,渲染已經完成,讓你的應用更接近原生app。具體作法:原生titleNView參考mui.openWindow示例3,原生tabbar示例參考ask教程示例

第二種:經過雙webview模式解決,此種狀況適用於須要上下拉刷新的列表頁面。將須要滾動的區域經過單獨的webview實現,徹底使用原生滾動。具體作法則是:將目標頁面分解爲主頁面和內容頁面,主頁面顯示卡頭卡尾區域,好比頂部導航、底部選項卡等;內容頁面顯示具體須要滾動的內容,而後在主頁面中調用mui.init方法初始化內容頁面。ajax

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同理。api

示例: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,//等待框背景區域高度,默認根據內容自動計算合適高度
        ......
      }
    }
})

參數:網絡

  • stylesapp

    窗口參數,參考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;

    • createNew參數爲爲fasle,則先查找當前App中是否已存在一樣id的webview,若存在則直接顯示;不然新建立並根據show參數執行顯示邏輯;

    注意:plusReady事件僅在webview首次建立時觸發,使用mui.openWindow方法屢次打開已存在的一樣id的webview時,是不會重複觸發plusReady事件的; 所以若業務寫在plusReady事件中,可能會出現執行結果和預期不一致的狀況;此時可經過自定義事件觸發; 案例參考:mui.plusReady有時會失效;

  • show

    窗口顯示控制參數,具體參數以下:

    • autoShow:目標窗口loaded事件發生後,是否自動顯示,默認爲true;若爲false,則僅建立但不顯示webview;若目標頁面爲預加載頁面,則該參數無效;

    • aniShow表示頁面顯示動畫,好比從右側劃入、從下側劃入等,具體可參考5+規範中的AnimationTypeShow

    • duration:顯示Webview窗口動畫的持續時間,單位爲ms

  • waiting

    系統等待框參數

    mui框架在打開新頁面時等待框的處理邏輯爲:

    顯示等待框-->建立目標頁面webview-->目標頁面loaded事件發生-->關閉等待框;

    所以,只有當新頁面爲新建立頁面(webview)時,會顯示等待框,不然若爲預加載好的頁面,則直接顯示目標頁面,不會顯示等待框。waiting中的具體參數:

    • autoShow:是否自動顯示等待框,默認爲true;若爲false,則不顯示等待框;注意:若waiting框的autoShow爲true,但目標頁面不自動顯示,則需在目標頁面中經過以下代碼關閉等待框: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();
  });
}
四、打開帶原生導航欄的新頁面

使用父子 webview 或者同屏顯示多個 webview 的性能和資源消耗較大。非必要不推薦使用同屏多 webview 的方案,推薦使用原生導航欄方案代替。能夠加快窗體進入速度,內存佔用更少。

經過在 mui.openWindow 的 styles 節點中設置 titleNView 節點的相關參數,可實現繪製原生導航欄控件,具體可參考 5+ webviewStyles 中的 titleNView 節點中的 WebviewTitleNViewStyles 的詳細文檔。示例以下:

mui.openWindow({
  url: webviewUrl,
  id: webviewId,
  styles: {                             // 窗口參數 參考5+規範中的WebviewStyle,也就是說WebviewStyle下的參數均可以在此設置
    titleNView: {                       // 窗口的標題欄控件
      titleText:"標題欄",                // 標題欄文字,當不設置此屬性時,默認加載當前頁面的標題,並自動更新頁面的標題
      titleColor:"#000000",             // 字體顏色,顏色值格式爲"#RRGGBB",默認值爲"#000000"
      titleSize:"17px",                 // 字體大小,默認17px
      backgroundColor:"#F7F7F7",        // 控件背景顏色,顏色值格式爲"#RRGGBB",默認值爲"#F7F7F7"
      progress:{                        // 標題欄控件的進度條樣式
        color:"#00FF00",                // 進度條顏色,默認值爲"#00FF00"  
        height:"2px"                    // 進度條高度,默認值爲"2px"         
      },
      splitLine:{                       // 標題欄控件的底部分割線,相似borderBottom
        color:"#CCCCCC",                // 分割線顏色,默認值爲"#CCCCCC"  
        height:"1px"                    // 分割線高度,默認值爲"2px"
      }
    }
  }
});

說明:老版本的 mui.openWindowWithTitle 已經廢除。

五、關閉頁面

mui框架將窗口關閉功能封裝在mui.back方法中,具體執行邏輯是:

  • 若當前webview爲預加載頁面,則hide當前webview;
  • 不然,close當前webview;

在mui框架中,有三種操做會觸發頁面關閉(執行mui.back方法):

  • 點擊包含.mui-action-back類的控件
  • 在屏幕內,向右快速滑動
  • Android手機按下back按鍵

iOS平臺原生支持從屏幕邊緣右滑關閉

iOS平臺可經過popGesture參數實現從屏幕邊緣右滑關閉webview,參考5+規範,若想禁用該功能,可經過setStyle方法設置popGesture爲none。

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();
    }
  });
}

爲什麼設置了swipeBack: false,在iOS上依然能夠右滑關閉?

iOS平臺原生支持從屏幕邊緣右滑關閉,這個是經過popGesture參數控制的,參考5+規範,若需禁用,可經過setStyle方法設置popGesture爲none。

可否經過addEventListener增長back按鍵監聽實現自定義關閉邏輯?

addEventListener只會增長新的執行邏輯,老的監聽邏輯(mui.back)依然會執行,所以,若需實現自定義關閉邏輯,必定要重寫mui.back。

六、預加載

所謂的預加載技術就是在用戶還沒有觸發頁面跳轉時,提早建立目標頁面,這樣當用戶跳轉時,就能夠當即進行頁面切換,節省建立新頁面的時間,提高app使用體驗。mui提供兩種方式實現頁面預加載。

方式一:經過mui.init方法中的preloadPages參數進行配置。

mui.init({
  preloadPages:[
    {
      url:prelaod-page-url,
      id:preload-page-id,
      styles:{},//窗口參數
      extras:{},//自定義擴展參數
      subpages:[{},{}]//預加載頁面的子頁面
    }
  ],
  preloadLimit:5//預加載窗口數量限制(一旦超出,先進先出)默認不限制
});

方式二:經過mui.preload方法預加載。

var page = mui.preload({
    url:new-page-url,
    id:new-page-id,//默認使用當前頁面的url做爲id
    styles:{},//窗口參數
    extras:{}//自定義擴展參數
});

經過mui.preload()方法預加載,可當即返回對應webview的引用,但一次僅能預加載一個頁面;若需加載多個webview,則需屢次調用mui.preload()方法;

如上兩種方案,各有優劣,需根據具體業務場景靈活選擇;

判斷預加載是否成功

方式1、經過直觀現象分析

預加載頁面會當即打開,不會顯示等待框;非預加載頁面默認會先顯示等待框,再顯示新頁面;

方式2、增長log分析預加載頁面是否已建立

好比:A頁面中預加載B頁面,則在A頁面徹底加載(可經過setTimeout模擬)後,打印當前應用全部webview,看是否包含B頁面的url,以此來分析。

例如:在A頁面增長以下代碼:
mui.plusReady(function(){
    setTimeout(function(){
        var array = plus.webview.all();
        if(array){
            for(var i=0,len=array.length;i<len;i++){
                    console.log(array[i].getURL());
                }
        }
    },5000)
});
七、
2.返回頂部
 
3.返回頂部
 
4.返回頂部
 
5.返回頂部
 
6.返回頂部
 
warn 做者:ylbtech
出處:http://ylbtech.cnblogs.com/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
相關文章
相關標籤/搜索