123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702 |
- /**
- * mui.init 5+
- * @param {type} $
- * @returns {undefined}
- */
- (function($) {
- var defaultOptions = {
- swipeBack: false,
- preloadPages: [], //5+ lazyLoad webview
- preloadLimit: 10, //预加载窗口的数量限制(一旦超出,先进先出)
- keyEventBind: {
- backbutton: true,
- menubutton: true
- },
- titleConfig: {
- height: "44px",
- backgroundColor: "#f7f7f7", //导航栏背景色
- bottomBorderColor: "#cccccc", //底部边线颜色
- title: { //标题配置
- text: "", //标题文字
- position: {
- top: 0,
- left: 0,
- width: "100%",
- height: "100%"
- },
- styles: {
- color: "#000000",
- align: "center",
- family: "'Helvetica Neue',Helvetica,sans-serif",
- size: "17px",
- style: "normal",
- weight: "normal",
- fontSrc: ""
- }
- },
- back: {
- image: {
- base64Data: '',
- imgSrc: '',
- sprite: {
- top: '0px',
- left: '0px',
- width: '100%',
- height: '100%'
- },
- position: {
- top: "10px",
- left: "10px",
- width: "24px",
- height: "24px"
- }
- }
- }
- }
- };
- //默认页面动画
- var defaultShow = {
- event:"titleUpdate",
- autoShow: true,
- duration: 300,
- aniShow: 'slide-in-right',
- extras:{}
- };
- //若执行了显示动画初始化操作,则要覆盖默认配置
- if($.options.show) {
- defaultShow = $.extend(true, defaultShow, $.options.show);
- }
- $.currentWebview = null;
- $.extend(true, $.global, defaultOptions);
- $.extend(true, $.options, defaultOptions);
- /**
- * 等待动画配置
- * @param {type} options
- * @returns {Object}
- */
- $.waitingOptions = function(options) {
- return $.extend(true, {}, {
- autoShow: true,
- title: '',
- modal: false
- }, options);
- };
- /**
- * 窗口显示配置
- * @param {type} options
- * @returns {Object}
- */
- $.showOptions = function(options) {
- return $.extend(true, {}, defaultShow, options);
- };
- /**
- * 窗口默认配置
- * @param {type} options
- * @returns {Object}
- */
- $.windowOptions = function(options) {
- return $.extend({
- scalable: false,
- bounce: "" //vertical
- }, options);
- };
- /**
- * plusReady
- * @param {type} callback
- * @returns {_L6.$}
- */
- $.plusReady = function(callback) {
- if(window.plus) {
- setTimeout(function() { //解决callback与plusready事件的执行时机问题(典型案例:showWaiting,closeWaiting)
- callback();
- }, 0);
- } else {
- document.addEventListener("plusready", function() {
- callback();
- }, false);
- }
- return this;
- };
- /**
- * 5+ event(5+没提供之前我自己实现)
- * @param {type} webview
- * @param {type} eventType
- * @param {type} data
- * @returns {undefined}
- */
- $.fire = function(webview, eventType, data) {
- if(webview) {
- if(typeof data === 'undefined') {
- data = '';
- } else if(typeof data === 'boolean' || typeof data === 'number') {
- webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "'," + data + ")");
- return;
- } else if($.isPlainObject(data) || $.isArray(data)) {
- data = JSON.stringify(data || {}).replace(/\'/g, "\\u0027").replace(/\\/g, "\\u005c");
- }
- webview.evalJS("typeof mui!=='undefined'&&mui.receive('" + eventType + "','" + data + "')");
- }
- };
- /**
- * 5+ event(5+没提供之前我自己实现)
- * @param {type} eventType
- * @param {type} data
- * @returns {undefined}
- */
- $.receive = function(eventType, data) {
- if(eventType) {
- try {
- if(data && typeof data === 'string') {
- data = JSON.parse(data);
- }
- } catch(e) {}
- $.trigger(document, eventType, data);
- }
- };
- var triggerPreload = function(webview) {
- if(!webview.preloaded) { //保证仅触发一次
- $.fire(webview, 'preload');
- var list = webview.children();
- for(var i = 0; i < list.length; i++) {
- $.fire(list[i], 'preload');
- }
- webview.preloaded = true;
- }
- };
- var trigger = function(webview, eventType, timeChecked) {
- if(timeChecked) {
- if(!webview[eventType + 'ed']) {
- $.fire(webview, eventType);
- var list = webview.children();
- for(var i = 0; i < list.length; i++) {
- $.fire(list[i], eventType);
- }
- webview[eventType + 'ed'] = true;
- }
- } else {
- $.fire(webview, eventType);
- var list = webview.children();
- for(var i = 0; i < list.length; i++) {
- $.fire(list[i], eventType);
- }
- }
- };
- /**
- * 打开新窗口
- * @param {string} url 要打开的页面地址
- * @param {string} id 指定页面ID
- * @param {object} options 可选:参数,等待,窗口,显示配置{params:{},waiting:{},styles:{},show:{}}
- */
- $.openWindow = function(url, id, options) {
- if(typeof url === 'object') {
- options = url;
- url = options.url;
- id = options.id || url;
- } else {
- if(typeof id === 'object') {
- options = id;
- id = options.id || url;
- } else {
- id = id || url;
- }
- }
- if(!$.os.plus) {
- //TODO 先临时这么处理:手机上顶层跳,PC上parent跳
- if($.os.ios || $.os.android) {
- window.top.location.href = url;
- } else {
- window.parent.location.href = url;
- }
- return;
- }
- if(!window.plus) {
- return;
- }
- options = options || {};
- var params = options.params || {};
- var webview = null,
- webviewCache = null,
- nShow, nWaiting;
- if($.webviews[id]) {
- webviewCache = $.webviews[id];
- //webview真实存在,才能获取
- if(plus.webview.getWebviewById(id)) {
- webview = webviewCache.webview;
- }
- } else if(options.createNew !== true) {
- webview = plus.webview.getWebviewById(id);
- }
- if(webview) { //已缓存
- //每次show都需要传递动画参数;
- //预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
- nShow = webviewCache ? webviewCache.show : defaultShow;
- nShow = options.show ? $.extend(nShow, options.show) : nShow;
- nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
- triggerPreload(webview);
- trigger(webview, 'pagebeforeshow', false);
- });
- if(webviewCache) {
- webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
- }
- return webview;
- } else { //新窗口
- if(!url) {
- throw new Error('webview[' + id + '] does not exist');
- }
- //显示waiting
- var waitingConfig = $.waitingOptions(options.waiting);
- if(waitingConfig.autoShow) {
- nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
- }
- //创建页面
- options = $.extend(options, {
- id: id,
- url: url
- });
- webview = $.createWindow(options);
- //显示
- nShow = $.showOptions(options.show);
- if(nShow.autoShow) {
- var showWebview = function() {
- //关闭等待框
- if(nWaiting) {
- nWaiting.close();
- }
- //显示页面
- webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
- options.afterShowMethodName && webview.evalJS(options.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
- };
- //titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
- webview.addEventListener(nShow.event, showWebview, false);
- //loaded事件发生后,触发预加载和pagebeforeshow事件
- webview.addEventListener("loaded", function() {
- triggerPreload(webview);
- trigger(webview, 'pagebeforeshow', false);
- }, false);
- }
- }
- return webview;
- };
- $.openWindowWithTitle = function(options, titleConfig) {
- options = options || {};
- var url = options.url;
- var id = options.id || url;
- if(!$.os.plus) {
- //TODO 先临时这么处理:手机上顶层跳,PC上parent跳
- if($.os.ios || $.os.android) {
- window.top.location.href = url;
- } else {
- window.parent.location.href = url;
- }
- return;
- }
- if(!window.plus) {
- return;
- }
- var params = options.params || {};
- var webview = null,
- webviewCache = null,
- nShow, nWaiting;
- if($.webviews[id]) {
- webviewCache = $.webviews[id];
- //webview真实存在,才能获取
- if(plus.webview.getWebviewById(id)) {
- webview = webviewCache.webview;
- }
- } else if(options.createNew !== true) {
- webview = plus.webview.getWebviewById(id);
- }
- if(webview) { //已缓存
- //每次show都需要传递动画参数;
- //预加载的动画参数优先级:openWindow配置>preloadPages配置>mui默认配置;
- nShow = webviewCache ? webviewCache.show : defaultShow;
- nShow = options.show ? $.extend(nShow, options.show) : nShow;
- nShow.autoShow && webview.show(nShow.aniShow, nShow.duration, function() {
- triggerPreload(webview);
- trigger(webview, 'pagebeforeshow', false);
- });
- if(webviewCache) {
- webviewCache.afterShowMethodName && webview.evalJS(webviewCache.afterShowMethodName + '(\'' + JSON.stringify(params) + '\')');
- }
- return webview;
- } else { //新窗口
- if(!url) {
- throw new Error('webview[' + id + '] does not exist');
- }
- //显示waiting
- var waitingConfig = $.waitingOptions(options.waiting);
- if(waitingConfig.autoShow) {
- nWaiting = plus.nativeUI.showWaiting(waitingConfig.title, waitingConfig.options);
- }
- //创建页面
- options = $.extend(options, {
- id: id,
- url: url
- });
- webview = $.createWindow(options);
- if(titleConfig) { //处理原生头
- $.extend(true, $.options.titleConfig, titleConfig);
- var tid = $.options.titleConfig.id ? $.options.titleConfig.id : id + "_title";
- var view = new plus.nativeObj.View(tid, {
- top: 0,
- height: $.options.titleConfig.height,
- width: "100%",
- dock: "top",
- position: "dock"
- });
- view.drawRect($.options.titleConfig.backgroundColor); //绘制背景色
- var _b = parseInt($.options.titleConfig.height) - 1;
- view.drawRect($.options.titleConfig.bottomBorderColor, {
- top: _b + "px",
- left: "0px"
- }); //绘制底部边线
- //绘制文字
- if($.options.titleConfig.title.text){
- var _title = $.options.titleConfig.title;
- view.drawText(_title.text,_title.position , _title.styles);
- }
-
- //返回图标绘制
- var _back = $.options.titleConfig.back;
- var backClick = null;
- //优先字体
- //其次是图片
- var _backImage = _back.image;
- if(_backImage.base64Data || _backImage.imgSrc) {
- //TODO 此处需要处理百分比的情况
- backClick = {
- left:parseInt(_backImage.position.left),
- right:parseInt(_backImage.position.left) + parseInt(_backImage.position.width)
- };
- var bitmap = new plus.nativeObj.Bitmap(id + "_back");
- if(_backImage.base64Data) { //优先base64编码字符串
- bitmap.loadBase64Data(_backImage.base64Data);
- } else { //其次加载图片文件
- bitmap.load(_backImage.imgSrc);
- }
- view.drawBitmap(bitmap,_backImage.sprite , _backImage.position);
- }
- //处理点击事件
- view.setTouchEventRect({
- top: "0px",
- left: "0px",
- width: "100%",
- height: "100%"
- });
- view.interceptTouchEvent(true);
- view.addEventListener("click", function(e) {
- var x = e.clientX;
-
- //返回按钮点击
- if(backClick&& x > backClick.left && x < backClick.right){
- if( _back.click && $.isFunction(_back.click)){
- _back.click();
- }else{
- webview.evalJS("window.mui&&mui.back();");
- }
- }
- }, false);
- webview.append(view);
- }
- //显示
- nShow = $.showOptions(options.show);
- if(nShow.autoShow) {
- //titleUpdate触发时机早于loaded,更换为titleUpdate后,可以更早的显示webview
- webview.addEventListener(nShow.event, function () {
- //关闭等待框
- if(nWaiting) {
- nWaiting.close();
- }
- //显示页面
- webview.show(nShow.aniShow, nShow.duration, function() {},nShow.extras);
- }, false);
- }
- }
- return webview;
- };
- /**
- * 根据配置信息创建一个webview
- * @param {type} options
- * @param {type} isCreate
- * @returns {webview}
- */
- $.createWindow = function(options, isCreate) {
- if(!window.plus) {
- return;
- }
- var id = options.id || options.url;
- var webview;
- if(options.preload) {
- if($.webviews[id] && $.webviews[id].webview.getURL()) { //已经cache
- webview = $.webviews[id].webview;
- } else { //新增预加载窗口
- //判断是否携带createNew参数,默认为false
- if(options.createNew !== true) {
- webview = plus.webview.getWebviewById(id);
- }
- //之前没有,那就新创建
- if(!webview) {
- webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), $.extend({
- preload: true
- }, options.extras));
- if(options.subpages) {
- $.each(options.subpages, function(index, subpage) {
- var subpageId = subpage.id || subpage.url;
- if(subpageId) { //过滤空对象
- var subWebview = plus.webview.getWebviewById(subpageId);
- if(!subWebview) { //如果该webview不存在,则创建
- subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), $.extend({
- preload: true
- }, subpage.extras));
- }
- webview.append(subWebview);
- }
- });
- }
- }
- }
- //TODO 理论上,子webview也应该计算到预加载队列中,但这样就麻烦了,要退必须退整体,否则可能出现问题;
- $.webviews[id] = {
- webview: webview, //目前仅preload的缓存webview
- preload: true,
- show: $.showOptions(options.show),
- afterShowMethodName: options.afterShowMethodName //就不应该用evalJS。应该是通过事件消息通讯
- };
- //索引该预加载窗口
- var preloads = $.data.preloads;
- var index = preloads.indexOf(id);
- if(~index) { //删除已存在的(变相调整插入位置)
- preloads.splice(index, 1);
- }
- preloads.push(id);
- if(preloads.length > $.options.preloadLimit) {
- //先进先出
- var first = $.data.preloads.shift();
- var webviewCache = $.webviews[first];
- if(webviewCache && webviewCache.webview) {
- //需要将自己打开的所有页面,全部close;
- //关闭该预加载webview
- $.closeAll(webviewCache.webview);
- }
- //删除缓存
- delete $.webviews[first];
- }
- } else {
- if(isCreate !== false) { //直接创建非预加载窗口
- webview = plus.webview.create(options.url, id, $.windowOptions(options.styles), options.extras);
- if(options.subpages) {
- $.each(options.subpages, function(index, subpage) {
- var subpageId = subpage.id || subpage.url;
- var subWebview = plus.webview.getWebviewById(subpageId);
- if(!subWebview) {
- subWebview = plus.webview.create(subpage.url, subpageId, $.windowOptions(subpage.styles), subpage.extras);
- }
- webview.append(subWebview);
- });
- }
- }
- }
- return webview;
- };
- /**
- * 预加载
- */
- $.preload = function(options) {
- //调用预加载函数,不管是否传递preload参数,强制变为true
- if(!options.preload) {
- options.preload = true;
- }
- return $.createWindow(options);
- };
- /**
- *关闭当前webview打开的所有webview;
- */
- $.closeOpened = function(webview) {
- var opened = webview.opened();
- if(opened) {
- for(var i = 0, len = opened.length; i < len; i++) {
- var openedWebview = opened[i];
- var open_open = openedWebview.opened();
- if(open_open && open_open.length > 0) {
- //关闭打开的webview
- $.closeOpened(openedWebview);
- //关闭自己
- openedWebview.close("none");
- } else {
- //如果直接孩子节点,就不用关闭了,因为父关闭的时候,会自动关闭子;
- if(openedWebview.parent() !== webview) {
- openedWebview.close('none');
- }
- }
- }
- }
- };
- $.closeAll = function(webview, aniShow) {
- $.closeOpened(webview);
- if(aniShow) {
- webview.close(aniShow);
- } else {
- webview.close();
- }
- };
- /**
- * 批量创建webview
- * @param {type} options
- * @returns {undefined}
- */
- $.createWindows = function(options) {
- $.each(options, function(index, option) {
- //初始化预加载窗口(创建)和非预加载窗口(仅配置,不创建)
- $.createWindow(option, false);
- });
- };
- /**
- * 创建当前页面的子webview
- * @param {type} options
- * @returns {webview}
- */
- $.appendWebview = function(options) {
- if(!window.plus) {
- return;
- }
- var id = options.id || options.url;
- var webview;
- if(!$.webviews[id]) { //保证执行一遍
- //TODO 这里也有隐患,比如某个webview不是作为subpage创建的,而是作为target webview的话;
- if(!plus.webview.getWebviewById(id)) {
- webview = plus.webview.create(options.url, id, options.styles, options.extras);
- }
- //之前的实现方案:子窗口loaded之后再append到父窗口中;
- //问题:部分子窗口loaded事件发生较晚,此时执行父窗口的children方法会返回空,导致父子通讯失败;
- // 比如父页面执行完preload事件后,需触发子页面的preload事件,此时未append的话,就无法触发;
- //修改方式:不再监控loaded事件,直接append
- //by chb@20150521
- // webview.addEventListener('loaded', function() {
- plus.webview.currentWebview().append(webview);
- // });
- $.webviews[id] = options;
- }
- return webview;
- };
- //全局webviews
- $.webviews = {};
- //预加载窗口索引
- $.data.preloads = [];
- //$.currentWebview
- $.plusReady(function() {
- $.currentWebview = plus.webview.currentWebview();
- });
- $.addInit({
- name: '5+',
- index: 100,
- handle: function() {
- var options = $.options;
- var subpages = options.subpages || [];
- if($.os.plus) {
- $.plusReady(function() {
- //TODO 这里需要判断一下,最好等子窗口加载完毕后,再调用主窗口的show方法;
- //或者:在openwindow方法中,监听实现;
- $.each(subpages, function(index, subpage) {
- $.appendWebview(subpage);
- });
- //判断是否首页
- if(plus.webview.currentWebview() === plus.webview.getWebviewById(plus.runtime.appid)) {
- //首页需要自己激活预加载;
- //timeout因为子页面loaded之后才append的,防止子页面尚未append、从而导致其preload未触发的问题;
- setTimeout(function() {
- triggerPreload(plus.webview.currentWebview());
- }, 300);
- }
- //设置ios顶部状态栏颜色;
- if($.os.ios && $.options.statusBarBackground) {
- plus.navigator.setStatusBarBackground($.options.statusBarBackground);
- }
- if($.os.android && parseFloat($.os.version) < 4.4) {
- //解决Android平台4.4版本以下,resume后,父窗体标题延迟渲染的问题;
- if(plus.webview.currentWebview().parent() == null) {
- document.addEventListener("resume", function() {
- var body = document.body;
- body.style.display = 'none';
- setTimeout(function() {
- body.style.display = '';
- }, 10);
- });
- }
- }
- });
- } else {
- //已支持iframe嵌入
- // if (subpages.length > 0) {
- // var err = document.createElement('div');
- // err.className = 'mui-error';
- // //文字描述
- // var span = document.createElement('span');
- // span.innerHTML = '在该浏览器下,不支持创建子页面,具体参考';
- // err.appendChild(span);
- // var a = document.createElement('a');
- // a.innerHTML = '"mui框架适用场景"';
- // a.href = 'http://ask.dcloud.net.cn/article/113';
- // err.appendChild(a);
- // document.body.appendChild(err);
- // console.log('在该浏览器下,不支持创建子页面');
- // }
- }
- }
- });
- window.addEventListener('preload', function() {
- //处理预加载部分
- var webviews = $.options.preloadPages || [];
- $.plusReady(function() {
- $.each(webviews, function(index, webview) {
- $.createWindow($.extend(webview, {
- preload: true
- }));
- });
- });
- });
- $.supportStatusbarOffset = function() {
- return $.os.plus && $.os.ios && parseFloat($.os.version) >= 7;
- };
- $.ready(function() {
- //标识当前环境支持statusbar
- if($.supportStatusbarOffset()) {
- document.body.classList.add($.className('statusbar'));
- }
- });
- })(mui);
|