HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

去设置里打开相机权限

function openCamera(){  
    var msg = "请在应用权限里设置允许使用相机权限";  
    mui.alert(msg,"开启相机权限","去开启",function(){          
        if (mui.os.ios) {  
            plus.runtime.openURL("app-settings:CAMERA");  
        } else {  
            var main = plus.android.runtimeMainActivity();  
            var Intent = plus.android.importClass("android.content.Intent");  
            var Build = plus.android.importClass("android.os.Build");  
            var Uri = plus.android.importClass("android.net.Uri");  
            var intent = new Intent();  
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
            if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的  
                intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");  
                intent.setData(Uri.fromParts("package", main.getPackageName(), null));  
            } else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的  
                intent.setAction(Intent.ACTION_VIEW);  
                intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");  
                intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());  
            }  
            main.startActivity(intent);  
            //  
        }  
    })  
};
继续阅读 »
function openCamera(){  
    var msg = "请在应用权限里设置允许使用相机权限";  
    mui.alert(msg,"开启相机权限","去开启",function(){          
        if (mui.os.ios) {  
            plus.runtime.openURL("app-settings:CAMERA");  
        } else {  
            var main = plus.android.runtimeMainActivity();  
            var Intent = plus.android.importClass("android.content.Intent");  
            var Build = plus.android.importClass("android.os.Build");  
            var Uri = plus.android.importClass("android.net.Uri");  
            var intent = new Intent();  
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
            if (Build.VERSION.SDK_INT >= 9) {//系统8.0以上的  
                intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");  
                intent.setData(Uri.fromParts("package", main.getPackageName(), null));  
            } else if (Build.VERSION.SDK_INT <= 8) {//系统8.0以下的  
                intent.setAction(Intent.ACTION_VIEW);  
                intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");  
                intent.putExtra("com.android.settings.ApplicationPkgName", main.getPackageName());  
            }  
            main.startActivity(intent);  
            //  
        }  
    })  
};
收起阅读 »

个推平台消息推送踩坑经验分享

以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。

(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同

1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。

2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。

3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。

(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。

1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。

2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。

  • 踩坑总结如下:
  • 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
  • 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
  • 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
  • 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
  • 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
  • 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
    */

一、以下是watcher.js实现逻辑

if(window.plus) {  
    newsClick();  
} else {  
    document.addEventListener('plusready', newsClick, false);     
}  

function newsClick() {  
    //获取个推 CID  
    //mui.toast(plus.push.getClientInfo().clientid);  
    // 监听plusready事件    
    //仅支持竖屏显示  
    plus.screen.lockOrientation("portrait-primary");  
    plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name=='iOS') {//ios当前应用离线时  
            if(msg.aps){  
                pushGetRun(msg.payload);  
            }  
        }else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件  
            if(msg.payload){  
                var payload = eval('(' + msg.payload + ')');  
                pushGetRun(payload);  
            }  
        }  
    }, false);  
    plus.push.addEventListener("receive", function(msg) {  
        //获取透传数据,统一将回调对象msg处理成json对象  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调  
            if(msg.payload){  
                if(typeof(msg.payload) == "string"){  
//                  mui.alert("payload(String): " + msg.payload);  
                    //字符串处理  
                    var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`  
                    if(payloadJson.payload){  
                        newsConfirm(payloadJson.payload);//弹出新消息层  
                    }  
                }else if(typeof(msg.payload) == "object"){  
                    if(msg.payload.payload){  
                        var payloadObj = null;  
                        if(typeof(msg.payload.payload) == 'string'){  
                            payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object  
                        }else if(typeof(msg.payload.payload) == "object"){  
                            payloadObj = msg.payload.payload;  
                        }  
                        if(payloadObj){  
                            newsConfirm(payloadObj);//弹出新消息层  
                        }else{//异常处理  
//                          clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
                        }  
                    }  
                }     
            }  
        }else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调  
            if(msg.payload){  
                newsConfirm(msg.payload);//弹出新消息层  
            }else{//异常处理  
            }     
            //创建本地消息  
//          plus.push.createMessage(msg.content, msg.payload, {  
//              title: msg.title,  
//              cover: false  
//          });  
       }  
    }, false);  

    function pushGetRun(payload) {//用参数打开指定页面  
        //eval()函数将字符串转换时需要区分是否是ios  
        var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');  
        if(data.url&&data.hasOwnProperty("params")){  
            clicked(data.url, data.params);  
        }else{//异常处理  
            mui.toast("参数缺失或错误");  
            clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
        }  
    }  

    //程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件  
    document.addEventListener("newintent", openWebviewFromOthers, false);  
    //获取通知栏(app未启动)点击、第三方程序启动本app  
    function openWebviewFromOthers() {  
        var args = plus.runtime.arguments;  
        if(args.indexOf('wechat') < 0 && args) {  
//          mui.toast("----args----" +JSON.stringify(args));  
            pushGetRun(args);  
        }  
    }  

    function newsConfirm(payload){  
        plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {  
            if(e.index == 0) {  
                pushGetRun(payload);  
            }  
        }, "新消息通知", ["查看", "忽略"]);  
    }  
};  

/*  
 * 针对ios不能执行eval("(" + str ")")来强制转化成json对象,  
 * 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;  
 * 以下为调用例子:  
 * var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;  
 * toJSON(toJSONStr2(toJSONStr1(a)));//测试  
 */  

function toJSONStr1(str){  
//全局将字符串  '{ 和  }' 替换成   {  和   }   ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)  
  return str.replace(/'{/g,"{").replace(/}'/g, "}");  
}  
function toJSONStr2(str) { //全局将属性名添加上双引号  ""  
  return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});  
}  
function toJSON(str) { //处理标准格式的字符串成json对象  
  return JSON.parse(str);  
}

二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:


                //消息事件监听  
                var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");  
                if(!watcherObj){//不存在才创建  
                    var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");  
                    //创建完隐藏  
                    watcher.hide();  
                }

四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:

{  
    title: "通知标题",  
    content: "通知内容",  
    payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'  
}

IOS参数设置----payload的自定义值参考如下:

{  
    "url": "_www/view/discovery/discoverydetail.html",  
    "params": {  
        "article_id": 51  
    }  
}

五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)

六、以下附件是个推平台上要注意的事项截图;

以上全部,欢迎大家一起讨论!

继续阅读 »

以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。

(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同

1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。

2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。

3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。

(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。

1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。

2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。

  • 踩坑总结如下:
  • 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
  • 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
  • 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
  • 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
  • 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
  • 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
    */

一、以下是watcher.js实现逻辑

if(window.plus) {  
    newsClick();  
} else {  
    document.addEventListener('plusready', newsClick, false);     
}  

function newsClick() {  
    //获取个推 CID  
    //mui.toast(plus.push.getClientInfo().clientid);  
    // 监听plusready事件    
    //仅支持竖屏显示  
    plus.screen.lockOrientation("portrait-primary");  
    plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name=='iOS') {//ios当前应用离线时  
            if(msg.aps){  
                pushGetRun(msg.payload);  
            }  
        }else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件  
            if(msg.payload){  
                var payload = eval('(' + msg.payload + ')');  
                pushGetRun(payload);  
            }  
        }  
    }, false);  
    plus.push.addEventListener("receive", function(msg) {  
        //获取透传数据,统一将回调对象msg处理成json对象  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调  
            if(msg.payload){  
                if(typeof(msg.payload) == "string"){  
//                  mui.alert("payload(String): " + msg.payload);  
                    //字符串处理  
                    var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`  
                    if(payloadJson.payload){  
                        newsConfirm(payloadJson.payload);//弹出新消息层  
                    }  
                }else if(typeof(msg.payload) == "object"){  
                    if(msg.payload.payload){  
                        var payloadObj = null;  
                        if(typeof(msg.payload.payload) == 'string'){  
                            payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object  
                        }else if(typeof(msg.payload.payload) == "object"){  
                            payloadObj = msg.payload.payload;  
                        }  
                        if(payloadObj){  
                            newsConfirm(payloadObj);//弹出新消息层  
                        }else{//异常处理  
//                          clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
                        }  
                    }  
                }     
            }  
        }else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调  
            if(msg.payload){  
                newsConfirm(msg.payload);//弹出新消息层  
            }else{//异常处理  
            }     
            //创建本地消息  
//          plus.push.createMessage(msg.content, msg.payload, {  
//              title: msg.title,  
//              cover: false  
//          });  
       }  
    }, false);  

    function pushGetRun(payload) {//用参数打开指定页面  
        //eval()函数将字符串转换时需要区分是否是ios  
        var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');  
        if(data.url&&data.hasOwnProperty("params")){  
            clicked(data.url, data.params);  
        }else{//异常处理  
            mui.toast("参数缺失或错误");  
            clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
        }  
    }  

    //程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件  
    document.addEventListener("newintent", openWebviewFromOthers, false);  
    //获取通知栏(app未启动)点击、第三方程序启动本app  
    function openWebviewFromOthers() {  
        var args = plus.runtime.arguments;  
        if(args.indexOf('wechat') < 0 && args) {  
//          mui.toast("----args----" +JSON.stringify(args));  
            pushGetRun(args);  
        }  
    }  

    function newsConfirm(payload){  
        plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {  
            if(e.index == 0) {  
                pushGetRun(payload);  
            }  
        }, "新消息通知", ["查看", "忽略"]);  
    }  
};  

/*  
 * 针对ios不能执行eval("(" + str ")")来强制转化成json对象,  
 * 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;  
 * 以下为调用例子:  
 * var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;  
 * toJSON(toJSONStr2(toJSONStr1(a)));//测试  
 */  

function toJSONStr1(str){  
//全局将字符串  '{ 和  }' 替换成   {  和   }   ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)  
  return str.replace(/'{/g,"{").replace(/}'/g, "}");  
}  
function toJSONStr2(str) { //全局将属性名添加上双引号  ""  
  return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});  
}  
function toJSON(str) { //处理标准格式的字符串成json对象  
  return JSON.parse(str);  
}

二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:


                //消息事件监听  
                var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");  
                if(!watcherObj){//不存在才创建  
                    var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");  
                    //创建完隐藏  
                    watcher.hide();  
                }

四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:

{  
    title: "通知标题",  
    content: "通知内容",  
    payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'  
}

IOS参数设置----payload的自定义值参考如下:

{  
    "url": "_www/view/discovery/discoverydetail.html",  
    "params": {  
        "article_id": 51  
    }  
}

五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)

六、以下附件是个推平台上要注意的事项截图;

以上全部,欢迎大家一起讨论!

收起阅读 »

希望uni-app打包成app的时候能够把webview内核打包进去

在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。

在一些手机上经常会遇到,因为手机自带webview内核过低,导致页面上的一些问题,希望uni-app能自己打包上,调用自己的。

uni-app中在同一个页面使用多个picker组件出现的一些问题以及解决方法

picker

作为一个刚刚了解一点微信小程序就被迫改用uni-app的人来说,这个框架给我的感觉就是哪里都是坑。倒不是说框架本身问题很多,而是自己没有太多的参考对象。当初学微信的时候,遇到一点问题上百度搜真的是一搜一大把,而现在就是屈指可数。而且也没有什么教学视频,至少我当初入坑时,能搜到的视频还是要收费的。总之这一路走得不平坦,但也感觉收获了不少。现在依然有很多问题,但是学会了用微信小程序来转化成uni-app,很多时候思路都是一样的,至少具体写法有些不同。这也会让我很抓狂,毕竟,我真的是个新手,很多基础知识都不熟,文档也是看得头痛还不能理解。
这不,刚刚就把一个困扰了许久的问题解决了,思路正是来自微信小程序的。这是思路来源,感谢!https://segmentfault.com/a/1190000009797083


<block v-for="(student,index) in studentlist2" :key="index">  
                        <view class="student-list-item padding-sm">  
                            <image class="avatar" :src="student.avatar">  

                            </image>  
                            <view class="student-info padding-sm">  
                                <view class="name font-md">{{student.name}}<span class="iconfont icon-yezi">&#xe601;</span></view>  
                                <view class="student-id font-sm grey main-font-color">{{student.id}}</view>  

                            </view>  
                            <picker @change="bindPickerChange" :value="student.newindex" :range="array" :data-current="index">  
                                <view class="uni-input">{{array[student.newindex]}}</view>  
                            </picker>  
                        </view>  
                        <view class="border"></view>  
                    </block>  

这是视图层,用到是for循环实现一个学生列表。对没有及时签到的学生可以进行选择,故需要用到picker。可是问题就来了,有多个picker,里面的{{array[index]}}显示的内容都是由data中的同一个index控制的,这样,每一次改变其中一个picker的值时,所有的picker都会改变值。这个问题困扰了我许久。当时我就想如果可以得到当前改变的picker的index就好了,这样就可以指定改变的picker了。但是当时的我不知道如何获取。
我的疑点有以下几点:
1.如何获取当前的index?本来也是可以的,用一个函数,参数为student,然后在函数里写index=e.index不就好了?可是这里绑定的函数是@change="bindPickerChange",和普通的绑定不一样,我不知道如何传参。

  1. 然后就是我不知到为何在method中的bindPickerChange又是有一个参数e的。我知道是自己基础不好,对e的认识很浅。我试图用console.log来获取e,看看其内部究竟有哪些值,但结果并不好。
  2. 能不能用data-XXX呢?其实如果是在微信小程序里面,我肯定首选这个,但是在uni-app里,我一直以为不能用data-XXX,因为官方文档似乎没有,网上也没有找到(我的搜索水平太差了),或者说这是默认就可以的。总之,我直到看了搭档这样用以后才知道原来uni-app是可以用的。当时我还很惊讶地问他是怎么知道的,他说还是当初学小程序的时候我教他的。卧槽,这么interesting的吗?

今天终于在一篇解决微信小程序的文章里找到了思路,也解决了之前的疑点。
其实以上三点都是一样的。因为data-xxx是可以用的,而在e里面就是可以看到data-xxx的,这就是答案。


studentlist2: [  
                    {  
                        newindex:0,  
                        avatar: '/static/lishi.jpg',  
                        name: '楚秋然',  
                        id: '2017082314'  
                    },  
                    {  
                        newindex:1,  
                        avatar: '/static/xinli.jpg',  
                        name: '愧泽',  
                        id: '2017082315'  
                    }  
                ]  

bindPickerChange: function(e) {  
                 const curindex = e.target.dataset.current  
                console.log('picker发送选择改变,携带值为', e.target.value)  
                console.log('picker发送选择改变,携带值为', curindex)  
                this.studentlist2[curindex].newindex = e.target.value  
                console.log("index="+this.studentlist.index)  
            }  

感觉自己是基础太差了。又没有人带,不然,这么easy的问题真的不该被卡住这么久。一个小白之所以会不自量力地写一篇文章也是想积累一些经验,和大家交流一下。而且,这个问题似乎都没有人写过,想着可能是太简单了没有必要写。但是如果有像我一样的小白,希望能对你有帮助。毕竟,当初的我是多么渴望有这么一篇文章来帮助我。

继续阅读 »

作为一个刚刚了解一点微信小程序就被迫改用uni-app的人来说,这个框架给我的感觉就是哪里都是坑。倒不是说框架本身问题很多,而是自己没有太多的参考对象。当初学微信的时候,遇到一点问题上百度搜真的是一搜一大把,而现在就是屈指可数。而且也没有什么教学视频,至少我当初入坑时,能搜到的视频还是要收费的。总之这一路走得不平坦,但也感觉收获了不少。现在依然有很多问题,但是学会了用微信小程序来转化成uni-app,很多时候思路都是一样的,至少具体写法有些不同。这也会让我很抓狂,毕竟,我真的是个新手,很多基础知识都不熟,文档也是看得头痛还不能理解。
这不,刚刚就把一个困扰了许久的问题解决了,思路正是来自微信小程序的。这是思路来源,感谢!https://segmentfault.com/a/1190000009797083


<block v-for="(student,index) in studentlist2" :key="index">  
                        <view class="student-list-item padding-sm">  
                            <image class="avatar" :src="student.avatar">  

                            </image>  
                            <view class="student-info padding-sm">  
                                <view class="name font-md">{{student.name}}<span class="iconfont icon-yezi">&#xe601;</span></view>  
                                <view class="student-id font-sm grey main-font-color">{{student.id}}</view>  

                            </view>  
                            <picker @change="bindPickerChange" :value="student.newindex" :range="array" :data-current="index">  
                                <view class="uni-input">{{array[student.newindex]}}</view>  
                            </picker>  
                        </view>  
                        <view class="border"></view>  
                    </block>  

这是视图层,用到是for循环实现一个学生列表。对没有及时签到的学生可以进行选择,故需要用到picker。可是问题就来了,有多个picker,里面的{{array[index]}}显示的内容都是由data中的同一个index控制的,这样,每一次改变其中一个picker的值时,所有的picker都会改变值。这个问题困扰了我许久。当时我就想如果可以得到当前改变的picker的index就好了,这样就可以指定改变的picker了。但是当时的我不知道如何获取。
我的疑点有以下几点:
1.如何获取当前的index?本来也是可以的,用一个函数,参数为student,然后在函数里写index=e.index不就好了?可是这里绑定的函数是@change="bindPickerChange",和普通的绑定不一样,我不知道如何传参。

  1. 然后就是我不知到为何在method中的bindPickerChange又是有一个参数e的。我知道是自己基础不好,对e的认识很浅。我试图用console.log来获取e,看看其内部究竟有哪些值,但结果并不好。
  2. 能不能用data-XXX呢?其实如果是在微信小程序里面,我肯定首选这个,但是在uni-app里,我一直以为不能用data-XXX,因为官方文档似乎没有,网上也没有找到(我的搜索水平太差了),或者说这是默认就可以的。总之,我直到看了搭档这样用以后才知道原来uni-app是可以用的。当时我还很惊讶地问他是怎么知道的,他说还是当初学小程序的时候我教他的。卧槽,这么interesting的吗?

今天终于在一篇解决微信小程序的文章里找到了思路,也解决了之前的疑点。
其实以上三点都是一样的。因为data-xxx是可以用的,而在e里面就是可以看到data-xxx的,这就是答案。


studentlist2: [  
                    {  
                        newindex:0,  
                        avatar: '/static/lishi.jpg',  
                        name: '楚秋然',  
                        id: '2017082314'  
                    },  
                    {  
                        newindex:1,  
                        avatar: '/static/xinli.jpg',  
                        name: '愧泽',  
                        id: '2017082315'  
                    }  
                ]  

bindPickerChange: function(e) {  
                 const curindex = e.target.dataset.current  
                console.log('picker发送选择改变,携带值为', e.target.value)  
                console.log('picker发送选择改变,携带值为', curindex)  
                this.studentlist2[curindex].newindex = e.target.value  
                console.log("index="+this.studentlist.index)  
            }  

感觉自己是基础太差了。又没有人带,不然,这么easy的问题真的不该被卡住这么久。一个小白之所以会不自量力地写一篇文章也是想积累一些经验,和大家交流一下。而且,这个问题似乎都没有人写过,想着可能是太简单了没有必要写。但是如果有像我一样的小白,希望能对你有帮助。毕竟,当初的我是多么渴望有这么一篇文章来帮助我。

收起阅读 »

开了一个WordPress使用uni-app开发app和小程序的教程,来捧个场吧。

uniapp 教程 WordPress

如题,开了一个WordPress使用uni-app开发app和小程序的教程,各位大神都来捧个场吧,主要巩固一下技术,顺便回馈一下小白,超级超级大神绕道,不喜勿喷啊!

看完此教程,你将学到什么:

  1. WordPress深度二开
  2. WordPress主题制作基础
  3. PHP基础
  4. 接口设计基础
  5. 用uni-app做一个属于你自己的app

教程目录(长期更新)

1、WordPress安装
2、开发一个简单的WordPress主题
3、使用uni-app框架创建一个app项目
4、用uni-app制作首页幻灯片
5、用WordPress编写app幻灯片接口
6、uni-app请求接口以及生命周期函数
7、uni-app渲染幻灯片数据
8、用uni-app制作首页文章列表
9、WordPress开发首页文章列表接口
10、uni-app:渲染app的首页文章数据
11、uni-app制作app底部导航栏
12、uni-app新建发现页面并加入底部tab
13、uni-app开发发现界面(九宫格布局)
14、WordPress开发发现界面接口
15、uni-app渲染发现界面
16、uni-app新建用户页面并加入tab
17、开始登录与注册
18、uni-app制作登录页面
19、WordPress开发登录接口
20、uni-app登录
21、uni-app开发注册页面【包含视频】
22、用WordPress开发注册接口【包含视频】(2020年02月19日,更新注册接口)
23、 实现注册功能
24、用户中心:为什么要使用Token?
25、实现Token第一步
27、实现Token第二步
28、封装Token类
29、uni-app实现用户是否登录的判断
30、uni-app实现登录保存Token

下转链接

番外

  1. uni-app+WordPress:美化APP主界面

官方交流群:824144151

问题解决
1、关于接口跨域问题

教程地址:
WordPress开发app(小程序)接口开发教程

技术援助

教程看不懂?需要一对一技术援助服务?点击这里

继续阅读 »

如题,开了一个WordPress使用uni-app开发app和小程序的教程,各位大神都来捧个场吧,主要巩固一下技术,顺便回馈一下小白,超级超级大神绕道,不喜勿喷啊!

看完此教程,你将学到什么:

  1. WordPress深度二开
  2. WordPress主题制作基础
  3. PHP基础
  4. 接口设计基础
  5. 用uni-app做一个属于你自己的app

教程目录(长期更新)

1、WordPress安装
2、开发一个简单的WordPress主题
3、使用uni-app框架创建一个app项目
4、用uni-app制作首页幻灯片
5、用WordPress编写app幻灯片接口
6、uni-app请求接口以及生命周期函数
7、uni-app渲染幻灯片数据
8、用uni-app制作首页文章列表
9、WordPress开发首页文章列表接口
10、uni-app:渲染app的首页文章数据
11、uni-app制作app底部导航栏
12、uni-app新建发现页面并加入底部tab
13、uni-app开发发现界面(九宫格布局)
14、WordPress开发发现界面接口
15、uni-app渲染发现界面
16、uni-app新建用户页面并加入tab
17、开始登录与注册
18、uni-app制作登录页面
19、WordPress开发登录接口
20、uni-app登录
21、uni-app开发注册页面【包含视频】
22、用WordPress开发注册接口【包含视频】(2020年02月19日,更新注册接口)
23、 实现注册功能
24、用户中心:为什么要使用Token?
25、实现Token第一步
27、实现Token第二步
28、封装Token类
29、uni-app实现用户是否登录的判断
30、uni-app实现登录保存Token

下转链接

番外

  1. uni-app+WordPress:美化APP主界面

官方交流群:824144151

问题解决
1、关于接口跨域问题

教程地址:
WordPress开发app(小程序)接口开发教程

技术援助

教程看不懂?需要一对一技术援助服务?点击这里

收起阅读 »

针对plus.runtime.install在安卓9.0+上无法执行的解决方案

install 安卓9.0

先确保你的IDE使用的是HBuilderX, 老HBuilder用户请升级HBuilderX

云打包配置

云打包时配置manifest.json将targetSdkVersion改为26或更高 最高建议28。
5+应用:
http://ask.dcloud.net.cn/article/94


uniapp:
https://uniapp.dcloud.io/collocation/manifest

如果提交云端打包后调用plus.runtime.install无法安装apk文件,请添加以下权限

<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>

如何添加权限?可参考

TIPS

云打包配置修改完毕后。请重新提交云端打包。生成你的APK,该APK才有调用plus.runtime.install安装APK的能力。

离线打包配置

  1. 将build.gradle中的targetSdkVersion调到26或者更高。

  2. 在Androidmanifest.xml添加provider节点,将里面的io.dcloud.HBuilder改成自己应用的包名。

        <provider  
            android:name="io.dcloud.common.util.DCloud_FileProvider"  
            android:authorities="XXXX.XXX.XX(当前的应用包名).dc.fileprovider"  
            android:exported="false"  
            android:grantUriPermissions="true">  
            <meta-data  
                android:name="android.support.FILE_PROVIDER_PATHS"  
                android:resource="@xml/dcloud_file_provider" />  
        </provider>  
  3. 在Androidmanifest.xml中添加权限。
    注:最新版SDK已经将权限加入基础库里面使用时请下载最新版SDK

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>  

配置完权限请重新编译生成APK。该APK才有调用plus.runtime.install安装APK的能力。

继续阅读 »

先确保你的IDE使用的是HBuilderX, 老HBuilder用户请升级HBuilderX

云打包配置

云打包时配置manifest.json将targetSdkVersion改为26或更高 最高建议28。
5+应用:
http://ask.dcloud.net.cn/article/94


uniapp:
https://uniapp.dcloud.io/collocation/manifest

如果提交云端打包后调用plus.runtime.install无法安装apk文件,请添加以下权限

<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>

如何添加权限?可参考

TIPS

云打包配置修改完毕后。请重新提交云端打包。生成你的APK,该APK才有调用plus.runtime.install安装APK的能力。

离线打包配置

  1. 将build.gradle中的targetSdkVersion调到26或者更高。

  2. 在Androidmanifest.xml添加provider节点,将里面的io.dcloud.HBuilder改成自己应用的包名。

        <provider  
            android:name="io.dcloud.common.util.DCloud_FileProvider"  
            android:authorities="XXXX.XXX.XX(当前的应用包名).dc.fileprovider"  
            android:exported="false"  
            android:grantUriPermissions="true">  
            <meta-data  
                android:name="android.support.FILE_PROVIDER_PATHS"  
                android:resource="@xml/dcloud_file_provider" />  
        </provider>  
  3. 在Androidmanifest.xml中添加权限。
    注:最新版SDK已经将权限加入基础库里面使用时请下载最新版SDK

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>  

配置完权限请重新编译生成APK。该APK才有调用plus.runtime.install安装APK的能力。

收起阅读 »

uniapp视频教程

视频教程

uniapp视频教程
http://fainbory.com/E7v

uniapp视频教程
http://fainbory.com/E7v

uni-app/mpvue 插件开发大赛启动,iPhone Xs Max等奖品等你来拿!

插件市场 uni_app

更新:大赛评奖结果揭晓,详见:https://ask.dcloud.net.cn/article/35939

基于vue,开发H5、小程序及App等多端应用,已经成为前端技术界的热门话题。

但vue周边生态很多组件都因为操作dom、window而无法跨多端。

为进一步活跃vue多端开发生态,为开发者提供更多方便的轮子,作为vue开发多端框架的2大主力,uni-app与mpvue团队,联合举办插件开发大赛。

这些插件中涉及小程序的均可用于uni-app和mpvue的开发者。涉及H5和App多端使用的,仅限于uni-app(mpvue不支持h5和App)

大赛活动时间及评奖方式

  • 即日起至2019年4月30日,参赛插件提交发布。超过4月30日的插件可以提交但不再评奖。
  • 2019年5月15日起,评委开始根据插件的下载量、插件市场评分、github star(如有)、评委主观评价等综合权重打分,评选获奖者。
  • 2019年5月20日,公布获奖名单并发放奖品

奖品设置

一等奖:
iphone Xs Max 3名

二等奖:
Samsung 32寸4k显示器 8名

三等奖:
Kindle Paperwhite 16名

贡献奖:
未获得以上奖项,仍有机会评选贡献奖,奖品为uni-app纪念T恤,50名。

其他:
获奖作者将进入DCloud的vip开发者群,享受优先的技术支持和bug受理。
获奖作者将得到宣传报道,有助于为简历或接外包资质添彩。

参赛方式

  1. 登陆插件市场,https://ext.dcloud.net.cn/
  2. 点击发布插件,插件开发指南参考:https://ask.dcloud.net.cn/article/35408
  3. 填写插件描述信息并提交发布
  4. 插件有多种类型,包括组件、js sdk、项目/页面模板、原生插件,均可参赛。但不接受只能用于h5端的插件。

其他注意事项

  1. 越早提交插件,下载量越大,有利于被评选获奖
  2. 插件市场可以同时提交npm地址,但必须有zip包。由于npm下载量可以刷,无法作为评选依据,请理解
  3. 插件市场的下载和评分都有反作弊系统,欢迎向朋友正常推广你的插件,但不要刷数据,违规者取消参赛资格
  4. 插件市场提供了赞赏,并即将上线付费插件购买,插件作者可以有更多收益
  5. 一位作者提交多个插件,每个插件都独立参与评奖。允许一位作者领取多个奖品

如果你想了解广大开发者都需要什么插件,可以点击插件市场右上角的已发布需求

本活动解释权归DCloud uni-app团队mpvue团队

更新:感谢尤雨溪对大赛的宣传支持

继续阅读 »

更新:大赛评奖结果揭晓,详见:https://ask.dcloud.net.cn/article/35939

基于vue,开发H5、小程序及App等多端应用,已经成为前端技术界的热门话题。

但vue周边生态很多组件都因为操作dom、window而无法跨多端。

为进一步活跃vue多端开发生态,为开发者提供更多方便的轮子,作为vue开发多端框架的2大主力,uni-app与mpvue团队,联合举办插件开发大赛。

这些插件中涉及小程序的均可用于uni-app和mpvue的开发者。涉及H5和App多端使用的,仅限于uni-app(mpvue不支持h5和App)

大赛活动时间及评奖方式

  • 即日起至2019年4月30日,参赛插件提交发布。超过4月30日的插件可以提交但不再评奖。
  • 2019年5月15日起,评委开始根据插件的下载量、插件市场评分、github star(如有)、评委主观评价等综合权重打分,评选获奖者。
  • 2019年5月20日,公布获奖名单并发放奖品

奖品设置

一等奖:
iphone Xs Max 3名

二等奖:
Samsung 32寸4k显示器 8名

三等奖:
Kindle Paperwhite 16名

贡献奖:
未获得以上奖项,仍有机会评选贡献奖,奖品为uni-app纪念T恤,50名。

其他:
获奖作者将进入DCloud的vip开发者群,享受优先的技术支持和bug受理。
获奖作者将得到宣传报道,有助于为简历或接外包资质添彩。

参赛方式

  1. 登陆插件市场,https://ext.dcloud.net.cn/
  2. 点击发布插件,插件开发指南参考:https://ask.dcloud.net.cn/article/35408
  3. 填写插件描述信息并提交发布
  4. 插件有多种类型,包括组件、js sdk、项目/页面模板、原生插件,均可参赛。但不接受只能用于h5端的插件。

其他注意事项

  1. 越早提交插件,下载量越大,有利于被评选获奖
  2. 插件市场可以同时提交npm地址,但必须有zip包。由于npm下载量可以刷,无法作为评选依据,请理解
  3. 插件市场的下载和评分都有反作弊系统,欢迎向朋友正常推广你的插件,但不要刷数据,违规者取消参赛资格
  4. 插件市场提供了赞赏,并即将上线付费插件购买,插件作者可以有更多收益
  5. 一位作者提交多个插件,每个插件都独立参与评奖。允许一位作者领取多个奖品

如果你想了解广大开发者都需要什么插件,可以点击插件市场右上角的已发布需求

本活动解释权归DCloud uni-app团队mpvue团队

更新:感谢尤雨溪对大赛的宣传支持

收起阅读 »

uni-app 1.8发布,微信端性能翻倍,并增加若干 Vue 语法支持

微信小程序 性能 filter

背景

uni-app在初期借鉴了mpvue,实现了微信小程序端的快速兼容,感谢美团点评团队对于开源社区的贡献!

但不少开发者抱怨mpvue支持的vue语法少,某些场景性能有问题。

为了让uni-app的开发者更满意,uni-app团队经过数月研发,全新重写框架,大幅提升了微信端运行性能、支持了更多vue语法

新版特性1:性能翻倍

基于mpvue的老框架和新框架是两种编译模式,主要区别在于组件化开发的实现机制不同;

  • mpvue将用户编写的Vue组件,编译为WXML中的模板(template),变相实现组件化开发;我们称这种编译模式为template模板模式
  • uni-app新框架则将用户编写的Vue组件,编译为微信小程序自定义组件,实现了更高的性能;我们称这种编译模式为自定义组件模式

基于自定义组件的新框架完成后,我们构造了如下测试模型:

  • 构造一个列表界面,每个列表项为一个自定义组件
  • 上拉加载触发数据更新,每次从本地读取静态数据,屏蔽网络差异

然后分别使用template模板模式自定义组件模式,在同一台手机(vivo nex)上进行多次测试,然后求其平均值,获取如下结果:

组件数量 老框架(mpvue) 新框架
200 204ms 129ms
400 280ms 139ms
800 341ms 180ms
1000 653ms 196ms

上表时间毫秒是指,从给变量赋值,到界面更新渲染完毕之间的耗时。

从测试数据来看,自定义组件模式(新框架)在复杂页面下,性能有翻倍提升!特别是数据越多、组件越复杂的页面,性能提升越大!

新版特性2:更多Vue语法支持

新版支持了更多 Vue 语法,详细如下:

  • 支持过滤器 filter
  • 支持比较复杂的 JavaScript 渲染表达式
  • 支持在 template 内使用 methods 中的函数
  • 支持 v-html (同 rich-text 的解析)
  • 支持 v-slot 新语法
  • 支持解构插槽 Prop 设置默认值
  • 支持 slot 后备内容
  • 组件支持原生事件绑定,如:@tap.native

新版不支持的 vue 语法

  • class不支持绑定Obejct变量(使用字符串的形式绑定)
  • 不支持事件修饰符:prevent、passive(在App与小程序平台,使用stop修饰符,既可以阻止冒泡也能阻止默认行为)
  • 不支持render、inline-template、X-Templates、keep-alive、transition
  • 不支持使用 Vue.use 的方式注册全局组件(在main.js使用Vue.component的方式引入)

新旧版本兼容策略

为兼容历史项目,uni-app 现阶段同时支持老的template模板模式、和新的自定义组件模式两种模式,默认策略如下:

  • HBuilderX 1.8.0+ 新创建的项目,在微信端默认会启用新的框架;
  • 历史项目默认使用老框架。如需启动新框架请按下面配置开启。
  • 但注意1.7.3群测版默认使用了新框架,升级到1.8后,也需要手动配置开启新框架

开发者可在manifest.json的源码视图里配置, manifest.json -> mp-weixin -> usingComponents切换编译模式,如下:

// manifest.json  
{  
    // ...  
    /* 小程序特有相关 */  
    "mp-weixin": {  
        "usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式`,否则启用老的`template模板模式`  
    }  
}  

Tips:

  • 为保证自定义组件兼容性,运行到微信开发者工具时,建议将微信基础库设置为最新版本。
  • 如果你使用了新增的vue语法,请注意只有h5和微信支持这些新语法,编译到其他平台时,要用条件编译处理。

新版开发注意事项

新框架基于微信小程序自定义组件实现,在进行自定义组件开发(页面开发不影响)时,需注意部分约束,详见:https://ask.dcloud.net.cn/article/35851

性能优化建议

  1. 模板中不建议直接使用 object
<!-- 低性能写法 -->  
<uni-title title="标题文字" note="描述信息" show-extra-icon="true" :extra-icon="{color: '#4cd964',size: '22',type: 'spinner'}"></uni-title>  
<!-- 高性能写法 -->  
<template>  
    <view>  
        <uni-title title="标题文字" note="描述信息" show-extra-icon="true" :extra-icon="extraIcon"></uni-title>  
    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            extraIcon:{color: '#4cd964',size: '22',type: 'spinner'}  
        }  
    }  
}  
</script>  
  1. 在模板中未使用的数据不建议定义在data 中,未使用的数据一律移除到 vm 外边定义
<!-- 低性能写法 -->  
<template>  
    <view>  
        {{name}}  
    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            name:'',  
            types:true  
        }  
    },  
    onLoad(){  
        if(this.types){  
            this.name = '张三';  
        } else {  
            this.name = '李四';  
        }  
    }  
}  
</script>
<!-- 高性能写法 -->  
<template>  
    <view>  
        {{name}}  
    </view>  
</template>  
<script>  
let types = true ;  
export default {  
    data() {  
        return {  
            name:''  
        }  
    },  
    onLoad(){  
        if(types){  
            this.name = '张三';  
        } else {  
            this.name = '李四';  
        }  
    }  
}  
</script>
  1. 为提升开发体验,新版本增加了部分 Vue 语法,其实这些语法在微信小程序中本身是不支持的;为支持这些语法,uni-app 会在编译、运行时分别做一些额外的工作,若开发者希望追求性能极致,则建议尽量少用或者不用新增语法。

后续

新框架会陆续把新编译器迁移到其他小程序端上。

升级注意

如果你的项目是cli创建的,记得编译器在你的项目下,不会随着HBuilderX升级而升级,你需要npm update手动升级编译器。

继续阅读 »

背景

uni-app在初期借鉴了mpvue,实现了微信小程序端的快速兼容,感谢美团点评团队对于开源社区的贡献!

但不少开发者抱怨mpvue支持的vue语法少,某些场景性能有问题。

为了让uni-app的开发者更满意,uni-app团队经过数月研发,全新重写框架,大幅提升了微信端运行性能、支持了更多vue语法

新版特性1:性能翻倍

基于mpvue的老框架和新框架是两种编译模式,主要区别在于组件化开发的实现机制不同;

  • mpvue将用户编写的Vue组件,编译为WXML中的模板(template),变相实现组件化开发;我们称这种编译模式为template模板模式
  • uni-app新框架则将用户编写的Vue组件,编译为微信小程序自定义组件,实现了更高的性能;我们称这种编译模式为自定义组件模式

基于自定义组件的新框架完成后,我们构造了如下测试模型:

  • 构造一个列表界面,每个列表项为一个自定义组件
  • 上拉加载触发数据更新,每次从本地读取静态数据,屏蔽网络差异

然后分别使用template模板模式自定义组件模式,在同一台手机(vivo nex)上进行多次测试,然后求其平均值,获取如下结果:

组件数量 老框架(mpvue) 新框架
200 204ms 129ms
400 280ms 139ms
800 341ms 180ms
1000 653ms 196ms

上表时间毫秒是指,从给变量赋值,到界面更新渲染完毕之间的耗时。

从测试数据来看,自定义组件模式(新框架)在复杂页面下,性能有翻倍提升!特别是数据越多、组件越复杂的页面,性能提升越大!

新版特性2:更多Vue语法支持

新版支持了更多 Vue 语法,详细如下:

  • 支持过滤器 filter
  • 支持比较复杂的 JavaScript 渲染表达式
  • 支持在 template 内使用 methods 中的函数
  • 支持 v-html (同 rich-text 的解析)
  • 支持 v-slot 新语法
  • 支持解构插槽 Prop 设置默认值
  • 支持 slot 后备内容
  • 组件支持原生事件绑定,如:@tap.native

新版不支持的 vue 语法

  • class不支持绑定Obejct变量(使用字符串的形式绑定)
  • 不支持事件修饰符:prevent、passive(在App与小程序平台,使用stop修饰符,既可以阻止冒泡也能阻止默认行为)
  • 不支持render、inline-template、X-Templates、keep-alive、transition
  • 不支持使用 Vue.use 的方式注册全局组件(在main.js使用Vue.component的方式引入)

新旧版本兼容策略

为兼容历史项目,uni-app 现阶段同时支持老的template模板模式、和新的自定义组件模式两种模式,默认策略如下:

  • HBuilderX 1.8.0+ 新创建的项目,在微信端默认会启用新的框架;
  • 历史项目默认使用老框架。如需启动新框架请按下面配置开启。
  • 但注意1.7.3群测版默认使用了新框架,升级到1.8后,也需要手动配置开启新框架

开发者可在manifest.json的源码视图里配置, manifest.json -> mp-weixin -> usingComponents切换编译模式,如下:

// manifest.json  
{  
    // ...  
    /* 小程序特有相关 */  
    "mp-weixin": {  
        "usingComponents":true //是否启用`自定义组件模式`,为true表示新的`自定义组件模式`,否则启用老的`template模板模式`  
    }  
}  

Tips:

  • 为保证自定义组件兼容性,运行到微信开发者工具时,建议将微信基础库设置为最新版本。
  • 如果你使用了新增的vue语法,请注意只有h5和微信支持这些新语法,编译到其他平台时,要用条件编译处理。

新版开发注意事项

新框架基于微信小程序自定义组件实现,在进行自定义组件开发(页面开发不影响)时,需注意部分约束,详见:https://ask.dcloud.net.cn/article/35851

性能优化建议

  1. 模板中不建议直接使用 object
<!-- 低性能写法 -->  
<uni-title title="标题文字" note="描述信息" show-extra-icon="true" :extra-icon="{color: '#4cd964',size: '22',type: 'spinner'}"></uni-title>  
<!-- 高性能写法 -->  
<template>  
    <view>  
        <uni-title title="标题文字" note="描述信息" show-extra-icon="true" :extra-icon="extraIcon"></uni-title>  
    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            extraIcon:{color: '#4cd964',size: '22',type: 'spinner'}  
        }  
    }  
}  
</script>  
  1. 在模板中未使用的数据不建议定义在data 中,未使用的数据一律移除到 vm 外边定义
<!-- 低性能写法 -->  
<template>  
    <view>  
        {{name}}  
    </view>  
</template>  
<script>  
export default {  
    data() {  
        return {  
            name:'',  
            types:true  
        }  
    },  
    onLoad(){  
        if(this.types){  
            this.name = '张三';  
        } else {  
            this.name = '李四';  
        }  
    }  
}  
</script>
<!-- 高性能写法 -->  
<template>  
    <view>  
        {{name}}  
    </view>  
</template>  
<script>  
let types = true ;  
export default {  
    data() {  
        return {  
            name:''  
        }  
    },  
    onLoad(){  
        if(types){  
            this.name = '张三';  
        } else {  
            this.name = '李四';  
        }  
    }  
}  
</script>
  1. 为提升开发体验,新版本增加了部分 Vue 语法,其实这些语法在微信小程序中本身是不支持的;为支持这些语法,uni-app 会在编译、运行时分别做一些额外的工作,若开发者希望追求性能极致,则建议尽量少用或者不用新增语法。

后续

新框架会陆续把新编译器迁移到其他小程序端上。

升级注意

如果你的项目是cli创建的,记得编译器在你的项目下,不会随着HBuilderX升级而升级,你需要npm update手动升级编译器。

收起阅读 »

uni-app 解决 app中调用微信支付一直返回 -1 的错误

官方文档和示例并没有写清楚。导致app中调用微信支付一直返回 -1 的错误,最终通过百度找到一位大佬成功接通iOS版微信支付、支付宝的案例,结合文档iOS和安卓版orderInfo字段数据格式不一致的情况,稍加修改后调用微信支付成功。以下为安卓版微信支付的调用代码。苹果版请参考点击此处查看iOS版完整案例

                // 安卓调用微信支付  
                uni.requestPayment({  
                    provider: "wxpay",  
                    timeStamp: JSON.stringify(result2.timestamp),  
                    nonceStr: result2.noncestr,  
                    package: result2.package,  
                    signType:"MD5",  
                    paySign: result2.sign,  
                    orderInfo: JSON.stringify({  
                        appid: result2.appid,  
                        noncestr: result2.noncestr,  
                        package: result2.package,  
                        partnerid: result2.partnerid,  
                        prepayid: result2.prepayid,  
                        timestamp: result2.timestamp,  
                        sign: result2.sign,  
                    }),  
                    success:function(res){  
                        uni.showToast({  
                            title:"支付成功",  
                            icon:"success",  
                            duration:2000,  
                            complete:function(){  

                            }  
                        });  
                    },  
                    fail:function(res){  
                        // console.log(JSON.stringify(res));  
                        uni.showModal({  
                             content: "支付失败,原因为: "   res.errMsg,  
                             showCancel: false  
                         })  
                        console.log('fail:'   JSON.stringify(res));  
                    }  
                });
继续阅读 »

官方文档和示例并没有写清楚。导致app中调用微信支付一直返回 -1 的错误,最终通过百度找到一位大佬成功接通iOS版微信支付、支付宝的案例,结合文档iOS和安卓版orderInfo字段数据格式不一致的情况,稍加修改后调用微信支付成功。以下为安卓版微信支付的调用代码。苹果版请参考点击此处查看iOS版完整案例

                // 安卓调用微信支付  
                uni.requestPayment({  
                    provider: "wxpay",  
                    timeStamp: JSON.stringify(result2.timestamp),  
                    nonceStr: result2.noncestr,  
                    package: result2.package,  
                    signType:"MD5",  
                    paySign: result2.sign,  
                    orderInfo: JSON.stringify({  
                        appid: result2.appid,  
                        noncestr: result2.noncestr,  
                        package: result2.package,  
                        partnerid: result2.partnerid,  
                        prepayid: result2.prepayid,  
                        timestamp: result2.timestamp,  
                        sign: result2.sign,  
                    }),  
                    success:function(res){  
                        uni.showToast({  
                            title:"支付成功",  
                            icon:"success",  
                            duration:2000,  
                            complete:function(){  

                            }  
                        });  
                    },  
                    fail:function(res){  
                        // console.log(JSON.stringify(res));  
                        uni.showModal({  
                             content: "支付失败,原因为: "   res.errMsg,  
                             showCancel: false  
                         })  
                        console.log('fail:'   JSON.stringify(res));  
                    }  
                });
收起阅读 »

【经验分享】pickers 省市区多级联动设置默认值

picker

【介绍】
当我们使用 mui.PopPicker 创建省、市、区三级联动,并且想要选中默认值的时候,
会出现只能选中第一级,无法选择第二级、第三级。

【原因】
这是因为 pickers 在设置默认值的时候是异步执行,并且有动画效果,我们就不能直接通过以下代码设置:

picker.pickers[0].setSelectedValue(100);  
picker.pickers[1].setSelectedValue(120);  
picker.pickers[2].setSelectedValue(123);

【解决】
如何解决?使用递归的方式调用即可
// 初始化选择器默认值
function initAddressSelector(index) {
if (index < picker.pickers.length && defaultData[index]) {
picker.pickers[index].setSelectedValue(defaultData[index], 0, initAddressSelector(index+1));
}
}

说明:调用的时候默认 index 传 0 ,这样代码会从第一个 picker 开始选择,setSelectedValue 的 第二参数为动画时长,这里设置 0 (单位:毫秒)即可,
setSelectedValue 的第三个参数为设置默认值成功之后回调,这里我们回调自己,并且下标 +1,这样就可以以此把 1、2、3 级全部设置上。
要设置的默认值可以放入一个数组里面,这样在递归的时候可以通过 index 下标获取到每一级的默认值。

继续阅读 »

【介绍】
当我们使用 mui.PopPicker 创建省、市、区三级联动,并且想要选中默认值的时候,
会出现只能选中第一级,无法选择第二级、第三级。

【原因】
这是因为 pickers 在设置默认值的时候是异步执行,并且有动画效果,我们就不能直接通过以下代码设置:

picker.pickers[0].setSelectedValue(100);  
picker.pickers[1].setSelectedValue(120);  
picker.pickers[2].setSelectedValue(123);

【解决】
如何解决?使用递归的方式调用即可
// 初始化选择器默认值
function initAddressSelector(index) {
if (index < picker.pickers.length && defaultData[index]) {
picker.pickers[index].setSelectedValue(defaultData[index], 0, initAddressSelector(index+1));
}
}

说明:调用的时候默认 index 传 0 ,这样代码会从第一个 picker 开始选择,setSelectedValue 的 第二参数为动画时长,这里设置 0 (单位:毫秒)即可,
setSelectedValue 的第三个参数为设置默认值成功之后回调,这里我们回调自己,并且下标 +1,这样就可以以此把 1、2、3 级全部设置上。
要设置的默认值可以放入一个数组里面,这样在递归的时候可以通过 index 下标获取到每一级的默认值。

收起阅读 »