mui初級入門教程(六)— 模板頁面實現原理及多端適配指南

文章來源:小青年原創
發佈時間:2016-07-26
關鍵詞:mui,webview,template,os,多端適配
轉載需標註本文原始地址: http://zhaomenghuan.github.io...css

寫在前面

自歷來公司實習,天天都淹沒在問題中,一直沒有抽出空寫寫文章,今天輪到我完善文檔和總結,就想着抽空把文檔中的內容寫寫,可是文檔限於篇幅,並且不能話嘮,天然博客是最好的方式去分享。哈哈,廢話很少說,將整理的內容貼出來,稍做解釋,方便你們查閱。html

template(模板頁面)

hello mui示例App中無等待窗體切換的實現是基於模板頁面,點擊一個連接,不顯示雪花等待框,當即打開一個「正在加載...」的頁面,以後真實內容快速填充「正在加載...」區域。這種模板頁面適用了通用性較強的頁面,咱們沒必要要爲每一個頁面建立父子webview,而是將公用的父頁面提取出來做爲模板頁面,同時在頁面爲加載前能夠顯示個性化加載頁面,能夠極大的提高用戶體驗。模板父頁面預加載,點擊後當即顯示,不用展現雪花等待框,也不會出現白屏現象;共用子頁面,有效控制webview數量,避免切頁時頻繁建立、銷燬webview。html5

實現思路

這裏咱們以列表到詳情頁的狀況爲例說明,詳情頁html結構:android

<ul class="mui-table-view">
    <li class="mui-table-view-cell">
        <a class="mui-navigate-right" href="list1.html">
            Item 1
        </a>
    </li>
    <li class="mui-table-view-cell">
        <a class="mui-navigate-right" href="list2.html">
             Item 2
        </a>
    </li>
    <li class="mui-table-view-cell">
        <a class="mui-navigate-right" href="list3.html">
             Item 3
        </a>
    </li>
</ul>

1.預加載一個模板父頁面,用以當頁面尚未加載出來的時候展現加載動畫,以及做爲公用子頁面的頭部,原理至關於tabbar webview模式的父頁面;預加載或者建立一個公用子頁面,同時將這個子頁面填充到模板父頁面;ios

// 預加載模板父頁面
var template = mui.preload({
    url:'template.html',
    id:'template',
    styles:{
        popGesture:"hide"
    }
});
// 預加載公用子頁面
var subWebview = mui.preload({
    url:'',
    id:'sub_template',
    styles:{
        top: '45px',
        bottom: '0px'
    }
});
// 將子頁面填充到父頁面
template.append(subWebview);

2.點擊列表連接時,直接顯示模板父頁面,並動態修改模板父頁面的標題;共用子頁面經過loadURL方法加載對應目標頁面;git

mui('.mui-table-view').on('tap','li a',function(){    
    var self = this;
    // 修改共用父模板的標題
    mui.fire(template, 'updateHeader', {
        title: self.innerText,
        href: self.href
    });
    // 加載子頁面地址
    if(subWebview.getURL()==self.href){
        subWebview.show();
    }else{
        subWebview.loadURL(self.href);
        // 子頁面加載完成顯示
        subWebview.addEventListener('loaded', function() {
            setTimeout(function(){
                subWebview.show();  
            },50);
        });    
    }
    // 顯示模板父頁面
    template.show('slide-in-right', 150);            
})

3.模板父頁面接收參數和返回列表頁的處理方法github

var titleElem = document.getElementById("title");
var contentWebview = null,self = null;

mui.plusReady(function () {
    self = plus.webview.currentWebview();
});

// 自定義事件接收參數修改模板父頁面頭部
window.addEventListener("updateHeader", function(e) {
    var title = e.detail.title;
    var href = e.detail.target;
    var aniShow = e.detail.aniShow;
    
    titleElem.innerHTML = title;
    titleElem.className = "mui-title mui-fadein";
    
    if(mui.os.android&&aniShow&&parseFloat(mui.os.version)>=4.4){
        if(contentWebview==null){
            contentWebview = self.children()[0];
        }
        if (contentWebview.getURL() != href) {
            contentWebview.loadURL(href);
        } else {
            contentWebview.show();
        }
        setTimeout(function () {
            self.show(aniShow);
        },10);
    }
});

// 返回事件(隱藏模板父頁面,並在窗體動畫結束後,隱藏共用子頁面)
mui.back = function() {
    self.hide('auto');
    setTimeout(function() {
        titleElem.className = 'mui-title mui-fadeout';
        titleElem.innerText = '';
        if(contentWebview==null){
            contentWebview = self.children()[0];
        }
        contentWebview.hide("none");
    }, 350);
}

另外須要說明的是,咱們這種方式是建立兩個webview做爲視圖容器實現,在web環境下webview的方法不能執行,hello mui裏面爲每一個詳情頁面建立一個頭部,可是咱們會發如今app環境下執行並無出現這個頭部,這是覺得在hello mui演示demo中的app.css中有這麼一段代碼:web

.mui-plus.mui-android header.mui-bar{
    display: none;
}
.mui-plus.mui-android .mui-bar-nav~.mui-content{
    padding: 0;
}

因爲iOS系統性能已經足夠好,轉場切換不會白屏,hello mui演示demo中iOS沒有使用模板頁面。當咱們引入mui.js文件,在5+環境執行,mui.js會自動將.mui-plus.mui-plus-android類添加到body上,咱們能夠經過這個方法進行環境判斷,是否顯示某些內容。segmentfault

運行環境判斷

若是是寫文檔,寫到上面天然就戛然而止,可是寫文章,但願把這個相關的問題順便多聊幾句,由於一旦有人遇到相關的問題,多說了幾句就說不定解決的。瀏覽器

說到系統判斷,這裏不得不說一下mui.os這個工具方法,mui經過封裝html5中的navigator.userAgentAPI進行判斷系統和版本號:

  • 5+環境下判斷方法:

    • mui.os.plus 返回是否在5+基座中運行
      等效於:navigator.userAgent.indexOf("Html5Plus")>-1

    • mui.os.stream 返回是否爲流應用
      等效於:navigator.userAgent.indexOf("StreamApp")>-1

  • Android環境下判斷方法:

    • mui.os.android 返回是否爲安卓手機
      等效於:navigator.userAgent.indexOf("Android")>-1

    • mui.os.isBadAndroid android非Chrome環境
      等效於:!(/Chrome\/\d/.test(window.navigator.appVersion))

    • mui.os.version 安卓版本
      等效於:navigator.userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)[2]

  • IOS環境下判斷方法:

    • mui.os.ios 返回是否爲蘋果設備
      等效於:navigator.userAgent.indexOf("iPhone")>-1&&navigator.userAgent.indexOf("iPad")>-1

    • mui.os.iphone 返回是否爲蘋果手機
      等效於:navigator.userAgent.indexOf("iPhone")>-1

    • mui.os.ipad 返回是否爲ipad
      等效於:navigator.userAgent.indexOf("iPad")>-1

    • mui.os.version 返回手機版本號
      等效於:navigator.userAgent.match(/(iPhone\sOS)\s([\d_]+)/).[2].replace(/_/g, '.')||navigator.userAgent.match(/(iPad\sOS)\s([\d_]+)/).[2].replace(/_/g, '.')

  • 微信環境下判斷方法:

    • mui.os.wechat 返回是否爲微信端
      等效於:navigator.userAgent.indexOf("MicroMessenger")>-1

    • mui.os.wechat.version 返回微信版本
      等效於:navigator.userAgent.match(/(MicroMessenger)\/([\d\.]+)/i)[2].replace(/_/g, '.')

這裏咱們能夠經過mui.os.*方法進行判斷,可是不少時候咱們須要更簡單的方法去判斷,好比咱們但願某一部份內容只在5+環境下顯示,有些內容只在非5+環境下執行,或者有些內容只在微信環境下使用,使用mui.os.*有時候顯得仍是不夠方便,那這裏就說一個更簡單的方法,就是咱們上面講到的經過設置class類的CSS方法。

mui源碼咱們可以知道,mui中定義mui.os.*系列方法,同時經過mui.os.*方法判斷環境,將.mui-plus.mui-plus-stream.mui-ios.mui-android.mui-wechatmui-ios-versionmui-android-versionmui-wechat-version綁定在document.body.classList中,咱們能夠經過這些樣式類判斷當前的運行判斷,因而能夠作出一些適配。

.mui-plus-visible,
.mui-wechat-visible{
    display: none!important;
}
.mui-plus-hidden,
.mui-wechat-hidden{
    display: block!important;
}
.mui-plus .mui-plus-visible,
.mui-wechat .mui-wechat-visible{
    display: block!important;
}
.mui-plus .mui-tab-item.mui-plus-visible,
.mui-wechat .mui-tab-item.mui-wechat-visible{
    display: table-cell!important;
}
.mui-plus .mui-plus-hidden,
.mui-wechat .mui-wechat-hidden{
    display: none!important;
}

當咱們知道這些類的時候,在作適配的時候能夠解決不少小問題,以下面這個例子:

<div class="mui-input-row mui-plus-visible">
    <label>mui-plus-visible</label>
    <input type="text" class="mui-input-speech mui-input-clear" placeholder="我在web環境下隱藏5+環境下顯示">
</div>
<div class="mui-input-row mui-plus-hidden">
    <label>mui-plus-hidden</label>
    <input type="text" class="mui-input-clear" placeholder="我在web環境下顯示5+環境下隱藏">
</div>

咱們可使用.mui-plus-visible將只能在5+環境下正常使用的內容在web環境下隱藏,反過來咱們可使用 .mui-plus-hidden將在web中正常顯示的內容在5+環境下隱藏。在5+環境下咱們使用加強版的語音輸入,在普通web環境下使用h5的普通輸入框。

開發一次,多端發佈,我想這種不少人但願看到的,目前mui中不少組件已經實如今多平臺自動切換到合適的模式,使用最合適的姿式,可是對於業務要求各不相同的開發者,想要實現多端發佈,不是簡單的一兩句的問題,仍是得熟悉各個平臺的差別化,同時對於h5,mui,html5+中的實現方法的差別要全部瞭解的前提下,纔可以作到真正的多端發佈。

多端發佈注意事項

上面講解了多端發佈的時候系統及版本判斷的方法,可是依然沒有說明區別所在,估計不少人看了依然是懵逼狀態。爲解決HTML5在低端Android機上的性能缺陷,mui引入了原生加速,在普通瀏覽器端5+的一些方法再也不適用,因此作多端發佈的時候必須先明白哪一些方法可使用,哪一些不能使用。所以若是不是APP端,須要將5+的方法所有替換成h5的方法。

mui中最關鍵的5+模塊是webview控件,所以mui若要發揮其所有能力,凡是涉及到webview窗體的內容在非5+環境不能使用,涉及功能點包括:

  • webview模式窗體動畫

  • 建立子窗口(除了爲解決區域滾動的常見雙webview場景,還涉及webview模式的選項卡等多webview場景)

  • webview模式的側滑菜單(也有div方式側滑菜單)

  • webview模式的tab選項卡(也有div方式選項卡)

  • nativeUI,如原生的警告框、確認框、popover、actionsheet、toast。這些也有HTML5的實現。

  • 預加載

  • 頁面傳值(拓展參數及自定義事件)

對於這部分的內容,解決方法也有不少,若是mui提供了iframe模式的父子頁面(主要兼容上拉加載下拉刷新),div模式的、側滑菜單、選項卡、彈出框,頁面傳值也可使用url傳參或localStorage等本地存儲的方法。在mui初級入門教程(二)— html5+ webview 底部欄用法詳解一文中我也給出了iframe兼容webview模式tabbar的解決方法。

對於第三方插件,html5+中的方法能夠優雅降級處理,採用h5的相關標準去實現,好比dcloud官方給出了一個定位的例子,查看這裏plusto,plusto是爲實現多端發佈的一個開源JS庫,該庫能夠根據平臺實現API的自動轉換,好比在5+ App環境下,將瀏覽器默認定位升級爲5+原生定位,實現一套代碼平滑遷移至多個平臺。在微信中有jssdk一樣能夠調用系統的一些功能,你們能夠自行判斷。

或許有些人喜歡使用一些構建工具,對於多端發佈使用構建工具確實會很方便,可是對於小白用戶來講,可能會遇到更多問題,DCloud的mui及Hello mui示例是使用grunt構建的,grunt相關配置也都開源,感興趣的朋友能夠自行構建,後面有時間再整理一篇相關的文章加以說明。

參考文章

hello mui中的無等待窗體切換是如何實現的
mui適用場景說明,能不能在普通瀏覽器裏使用,可否用於wap網站
多端發佈開發指南

後記

這篇文章基本都是copy相關的文檔,加以增刪,乃成此文。很久不寫文,大神勿噴!

最後放上demo地址:

mui-demo:https://github.com/zhaomenghu...

寫文章不容易,也許寫這些代碼就幾分鐘的事,寫一篇你們好接受的文章或許須要幾天的醞釀,而後加上幾天的碼字,累並快樂着。若是文章對您有幫助請我喝杯咖啡吧!

clipboard.png


近期在segmentfault講堂開設了一場關於html5+ App開發工程化實踐之路的講座,會講到5+ 開發中高性能的優化方案以及使用如何結合Vue.js進行開發,歡迎前來圍觀:https://segmentfault.com/l/15...

相關文章
相關標籤/搜索