文章來源:小青年原創
發佈時間:2016-07-26
關鍵詞:mui,webview,template,os,多端適配
轉載需標註本文原始地址: http://zhaomenghuan.github.io...css
自歷來公司實習,天天都淹沒在問題中,一直沒有抽出空寫寫文章,今天輪到我完善文檔和總結,就想着抽空把文檔中的內容寫寫,可是文檔限於篇幅,並且不能話嘮,天然博客是最好的方式去分享。哈哈,廢話很少說,將整理的內容貼出來,稍做解釋,方便你們查閱。html
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.userAgent
API進行判斷系統和版本號:
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-wechat
,mui-ios-version
,mui-android-version
,mui-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...
寫文章不容易,也許寫這些代碼就幾分鐘的事,寫一篇你們好接受的文章或許須要幾天的醞釀,而後加上幾天的碼字,累並快樂着。若是文章對您有幫助請我喝杯咖啡吧!
近期在segmentfault講堂開設了一場關於html5+ App開發工程化實踐之路的講座,會講到5+ 開發中高性能的優化方案以及使用如何結合Vue.js進行開發,歡迎前來圍觀:https://segmentfault.com/l/15...。