mui跨平台开发记录

断点调试问题

跨平台开发,所以我们需要在不同平台进行断点调试,分成两大类,网页端app端

  1. 网页端调试

    • Chrome 浏览器

      最爽的调试工具,刷新一下立马见效,直接实时修改样式,变量查看方便,关键是可以使用链接调试某个页面,免去了真机,模拟器需要一层层跳转比较麻烦,这个,地球人都会的东西了  
      
  2. app端,真机or模拟器调试

    • iOS真机

      1). 打开设置程序,进入Safari->高级页面开启Web检查器

      2). 用usb连接电脑,运行程序  
      
      3). 运行`Safari`,点击`Safari`菜单下面的`偏好设置(Preferences...)`,切换到`高级选项(Advanced)`,勾选`在菜单栏显示开发菜单(Show Develop menu in menu bar)`  
      
      4). 如图,选择相应的`html`页面即可打开调试界面  
      
        ![2016-12-23-01](http://7xrlno.com1.z0.glb.clouddn.com/2016-12-24-2016-12-23-01.png)  
      
      • iOS模拟器

        1). 下载xcode,安装模拟器

        2). 运行程序

        3). 如图,选择html页面即可打开调试界面

        2016-12-23-02

  • Android真机(系统4.4以上)

    1). 打开`开发者选项`,开启`usb调试`,连接usb
    
    2). 运行程序
    
    3). 在`Chrome`地址栏,输入`chrome://inspect`或通过`菜单`->`工具`->`检查设备`打开设备检查页面
    
    4). `DevTools`工具会自动检测已连接设备运行的可调试页面列表,点击对应页面的`inspect`链接打开调试页面  
    

    2016-12-23-03

  • Android模拟器

    1). 安装Android studio,启动模拟器
    
    2). 参考`Android真机(系统4.4以上)`对应的步骤
    

底部tabbar的问题

在原生app中,我们使用系统提供的切换选项卡来坐切换,但是,在h5中,mui的教程(mui初级入门教程(二)— html5+ webview 底部栏用法详解)使用了iframe切换,使用后发现如下问题:

h5中,执行了回退操作,假若页面中含有AJAX代码,页面就会被强制刷新,所以,当使用iframe之后,切换到了第二个选项卡,进入二级页面,再进行回退操作时,iframe会强制刷新,由此导致选项卡切换为默认的第一个,但是当前界面还是停留在第二选项卡的界面,如图:

2016-12-23-04

最终解决办法是在四个首页(首页、话题、文章、评茶),使用html+css模拟下方的切换卡,高亮显示当前对应的切换卡

正则表达式

为了截取MarkDown中的图片,需要使用正则来获取,如下:

var reg = new RegExp("/!\[[^\]]+\]\([^\)]+\)/g")

参考文章:深入浅出的javascript的正则表达式学习教程

##页面跳转传参
页面间传参,由于是跨平台开发,需要兼容两端,app端可使用mui的框架进行页面传参,网页端使用url传参

打开新界面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 打开新界面传递参数
* @param {String} param 字符串参数,若为对象请先转成字符串
* @param {String} baseUrl 新界面的url
* @param {String} id 新界面的标识
*/
open: function(param, baseUrl, id) {
var url = mui.os.plus ? baseUrl : baseUrl + '?param=' + param;
mui.openWindow({
url: url,
id: id,
extras: {
param: param
}
})
},

目标界面获取参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
getParam: function(callback) {
if(mui.os.plus) {
mui.plusReady(function() {
var self = plus.webview.currentWebview();
if(callback) {
callback(param);
}
})
} else {
var reg = new RegExp("(^|&)" + "param" + "=([^&]*)(&|$)");
var url = decodeURI(window.location.search);
var r = url.substr(1).match(reg);
if(r != null) {
if(callback) {
callback(unescape(r[2]));
}
} else {
if(callback) {
callback(null);
}
}
}
}

事件冒泡与捕获

事件传递有事件捕获and事件冒泡

  1. 事件捕获,从外到内,父元素到子元素传递

  2. 事件冒泡,从内到外,子元素到父元素传递

  3. 阻止冒泡w3c中使用stopPropagation(),ie使用cancelBubble = true

参考文章:js之事件冒泡和事件捕获详细介绍

mui样式覆盖

样式覆盖涉及到优先级的问题,直接定位class很难修改到样式,建议在Chrome浏览器中先修改,再复制到代码中

##滑动条长度修改
mui提供的滑动条控件,使用了栅格系统,将屏幕分成了12份,如下代码设置滑动条长度:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="sliderProgressBar" class="mui-slider-progress-bar mui-col-xs-4"></div>
```
`mui-col-xs-4`表示将屏幕分成三份,每份四个栅格,如果我们想要线再短一点,就不好控制了,如下,初始效果:
![2016-12-23-05](http://7xrlno.com1.z0.glb.clouddn.com/2016-12-24-2016-12-23-05.png)
目标效果:
![2016-12-23-06](http://7xrlno.com1.z0.glb.clouddn.com/2016-12-24-2016-12-23-06.png)
解决方案:
win.onload = function() {
    $('#sliderProgressBar').css({
        'width': '11.1111%',
        'margin-left': '11.111%'
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
## 垂直居中(不同浏览器适配性)
文章参考:
1. [css实现固定高度及未知高度文字垂直居中的完美解决方案](http://www.cnblogs.com/tugenhua0707/p/3454942.html)
2. [CSS 元素垂直居中的 6种方法](http://blog.zhourunsheng.com/2012/03/css-%E5%85%83%E7%B4%A0%E5%9E%82%E7%9B%B4%E5%B1%85%E4%B8%AD%E7%9A%84-6%E7%A7%8D%E6%96%B9%E6%B3%95/)
## BFC
了解到这个的是因为看到`mui`的一些demo的效果,进而找到了`overflow`这个属性,引出了`BFC`这个专用名词
参考文章:[前端精选文摘:BFC 神奇背后的原理](http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html)
##图片变形问题
1. 设置宽高其中一个,另一个设置 max-xx:100%
2. 使用`background-image`,设置`background-size`
文章参考:[理解CSS3中的background-size(对响应性图片等比例缩放)](http://www.cnblogs.com/tugenhua0707/p/5260411.html#_labe10)
## css
- [用纯CSS实现的箭头](http://ourjs.com/detail/532bc9f36922aa7e1d000001)
- 圆头像,`border-radius:50%`
- 限制行数,[css实现多行文本溢出显示省略号(…)全攻略](http://www.111cn.net/cssdiv/css/67208.htm)
- `rem`做屏幕适配,代码如下:
(function(doc, win) {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function() {
            var clientWidth = docEl.clientWidth;
            if(!clientWidth) return;
            docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
        };
    if(!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);
1
2
3
4
5
6
7
8
9
10
11
12
再启用`px`转`rem`提示助手([px转rem提示功能指南(HBuilder7.5.2以后含此功能)](http://ask.dcloud.net.cn/article/982)),直接输入`px`就可以转成`rem`适配
参考文章:
1. [(淘宝无限适配)手机端rem布局详解](http://www.cnblogs.com/well-nice/p/5509589.html)
2. [使用Flexible实现手淘H5页面的终端适配](https://github.com/amfe/article/issues/17)
## js
- 获取`select`(下拉框)的选中项
var options_relation = $("#relation_family option:selected");
var relationTx = options_relation.text();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- `swiper`左右滑动切换,[控件](http://www.swiper.com.cn/)
## 下拉刷新
下拉刷新分为单个下拉刷新,类似网易新闻之类的多个下拉刷新:
1. 单个的可以使用[官方文档示例](http://dev.dcloud.net.cn/mui/pulldown/)
2. 类似网易新闻的,`mui`也提供了一个[demo](http://www.dcloud.io/hellomui/examples/pullrefresh_with_tab.html)
3. 针对第二点,网易新闻的多个下拉刷新,`mui`的demo的下拉刷新在`Android`真机上面下拉刷新是一个圈圈,仿`Android`原生的刷新动画,抱着不混淆用户视觉信念(好吧,其实是强迫症),需要将样式统一,参考文章[Android真机环境下下拉刷新失效](http://ask.dcloud.net.cn/question/21313) ,此处需要修改`mui.js`源码!!!
## 下拉刷新部分封装
pullToRefresh.js

(function(win, $) {

var PULL_DOWN = 'pull_down', //下拉刷新
    PULL_UP = 'pull_up'; //上拉加载更多

var refreshs = new Array();

var pullToRefresh = function(options) {
    this.STATIC = $.extend({
        PULL_DOWN: 'pull_down',
        PULL_UP: 'pull_up',
        tableIds: [],
        requestData: null,
        renderWithData: null,
        refreshEnd: null,
        isMulti: true,
        needPullDown: true,
        needPullUp: true,
        contentrefresh: '正在刷新...',
        contentnomore: '- 没有更多了 -'
    }, options);

    PULL_DOWN = this.STATIC.PULL_DOWN;
    PULL_UP = this.STATIC.PULL_UP;

    this.initRefresh();
}

pullToRefresh.prototype.getData = function(type, callBack, index) {

    if(this.STATIC.requestData) {
        this.STATIC.requestData(type, function(arr, isLast) {
            if(type == PULL_DOWN) {
                if(callBack) {
                    callBack(arr, isLast);
                }
            } else {
                if(callBack) {
                    callBack(arr, isLast);
                }
            }
        }, index);
    }
}

pullToRefresh.prototype.render = function(type, currentIndex, data) {

    var table = null;

    if(currentIndex < this.STATIC.tableIds.length) {
        table = $(this.STATIC.tableIds[currentIndex]);
    }

    if(table != null && type == PULL_DOWN) {
        table.empty();
    }

    if(this.STATIC.renderWithData) {
        this.STATIC.renderWithData(table, data, currentIndex, type);
    }
}

pullToRefresh.prototype.handleRefresh = function(self, type) {

    var index = 0;

    if(this.STATIC.isMulti) {
        index = parseInt(self.element.getAttribute('index'));
    }

    var _this = this;
    _this.getData(type, function(data, isLast) {

        if(data !== null) {
            _this.render(type, index, data);
        }

        if(_this.STATIC.isMulti) {
            if(type == PULL_DOWN) {

                self.endPulldownToRefresh();

                if(isLast) {
                    self.endPullupToRefresh(isLast);
                } else {
                    self.refresh(true);
                }

            } else {
                self.endPullupToRefresh(isLast);
            }
        } else {
            if(type == PULL_DOWN) {
                self.endPulldownToRefresh();
                if(isLast) {
                    self.endPullupToRefresh(isLast);
                } else {
                    self.refresh(true);
                }
            } else {
                self.endPullupToRefresh(isLast);
            }
        }

        if(_this.STATIC.refreshEnd) {
            _this.STATIC.refreshEnd();
        }

    }, index);
}

/**
 * 
 * @param {Boolean} isPullDown true:下拉刷新;false:加载更多
 */
pullToRefresh.prototype.startRefresh = function(isPullDown) {
    var self = this;
    if(self.STATIC.isMulti) {
        if(mui.os.plus) {
            mui.plusReady(function() {
                refresh(self, isPullDown);
            });
        } else {
            mui.ready(function() {
                refresh(self, isPullDown);
            });
        }
    } else {
        if(mui.os.plus) {
            mui.plusReady(function() {
                setTimeout(function() {
                    refresh(self, isPullDown);
                }, 0);
            });
        } else {
            mui.ready(function() {
                refresh(self, isPullDown);
            });
        }
    }
}

function refresh(self, isPullDown) {
    if(self.STATIC.isMulti) {
        $.each(refreshs, function(index, refresh) {
            if(isPullDown) {
                refresh.pullRefresh().pulldownLoading();
            } else {
                refresh.pullRefresh().pullupLoading();
            }

        });
    } else {
        if(isPullDown) {
            mui('#pullrefresh').pullRefresh().pulldownLoading();
        } else {
            mui('#pullrefresh').pullRefresh().pullupLoading();

        }
    }
}

pullToRefresh.prototype.initRefresh = function() {

    var _self = this;
    if(_self.STATIC.isMulti) {
        mui.init();
        $.each(document.querySelectorAll('.mui-slider-group .mui-scroll-wrapper'), function(index, pullRefreshEl) {
            refreshs.push(mui(pullRefreshEl));
            mui(pullRefreshEl).pullRefresh({
                down: {
                    callback: function() {
                        _self.handleRefresh(this, PULL_DOWN);
                    }
                },
                up: {
                    contentnomore: _self.STATIC.contentnomore,
                    callback: function() {
                        _self.handleRefresh(this, PULL_UP);
                    }
                }
            });
        });
    } else {

        var down = null,
            up = null;

        if(_self.STATIC.needPullDown) {
            down = {
                contentdown: "下拉可以刷新", //可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容
                contentover: "释放立即刷新", //可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容
                contentrefresh: _self.STATIC.contentrefresh, //可选,正在刷新状态时,下拉刷新控件上显示的标题内容
                callback: function() {
                    _self.handleRefresh(this, PULL_DOWN);
                }
            };
        }

        if(_self.STATIC.needPullUp) {
            up = {
                contentnomore: _self.STATIC.contentnomore,
                callback: function() {
                    _self.handleRefresh(this, PULL_UP);
                }
            }
        }

        mui.init({
            gestureConfig: {
                doubletap: true
            },
            pullRefresh: {
                container: '#pullrefresh',
                down: down,
                up: up
            }
        });
    }
}

window.ZqRefresh = pullToRefresh;

})(window, jQuery);

1
2
3
4
单个下拉刷新:
- html







1
- js


zqRefresh = new ZqRefresh({
tableIds: [‘.mui-table-view’],
requestData: requestData,
renderWithData: renderWithData,
isMulti: false
});

zqRefresh.startRefresh(false);

function requestData(type, callBack) {
//do something
//then call callBack
if(callBack){
callBack(data,isLast);
}
}

function renderWithData(table, data, currentIndex, type) {
//render ui
table.append($(‘
  • ‘));
    }
    1
    2
    3
    4
    5
    多个下拉刷新:
    - html













                <div id="item2mobile" class="mui-slider-item mui-control-content">
                    <div id="scroll1" class="mui-scroll-wrapper" index="1">
                        <div class="mui-scroll" index="1">
                            <ul class="mui-table-view" id="topic-table-view">
    
                            </ul>
                        </div>
                    </div>
                </div>
    
                <div id="item3mobile" class="mui-slider-item mui-control-content">
                    <div id="scroll3" class="mui-scroll-wrapper" index="2">
                        <div class="mui-scroll" index="2">
                            <ul class="mui-table-view" id="course-table-view">
    
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    1
    - js
        zqRefresh = new ZqRefresh({
            tableIds: ['#headlines-table-view', '#topic-table-view', '#course-table-view'],
            requestData: requestData,
            renderWithData: renderWithData,
        });
    
        zqRefresh.startRefresh(false);  
    
        function requestData(type, callBack, currentIndex) {
    
            switch(currentIndex) {
                case 0://第一个下拉刷新的tableview
    
                    break;
                case 1:
    
                    break;
                case 2:
    
                    break;
            }
        }
    
        function renderWithData(table, data, currentIndex, type) {
        //render ui
        table.append($('<li></li>'));
    }
    

    ```

    |—参数—|—必需—|—描述—|—|—|:-: |:————————————-:|

    | tableIds | 否 |tableView的id,可为空 |

    | requestData | 是 | 请求数据,刷新,加载更多操作时回调 |

    | renderWithData | 是 | 渲染ui,table可能为null |

    |refreshEnd | 否 | 刷新结束回调 |

    |isMulti | 否 | 是否多个刷新,默认为true |

    |needPullDown | 否 | 是否需要下拉刷新,目前只有单个刷新可控制 |

    |needPullUp | 否 | 是否需要加载更多,目前只有单个刷新可控制 |

    |contentrefresh | 否 | 下拉刷新描述文字,默认为‘正在刷新…’ |

    |contentnomore | 否 | 加载更多描述文字,默认为‘- 没有更多了 -’ |