HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

我觉得这个启动时间优化空间很大!

性能优化

我觉得这个启动时间优化空间很大!

比我的Dreamweaver cs5 打开都慢很多!

我觉得这个启动时间优化空间很大!

比我的Dreamweaver cs5 打开都慢很多!

【示例】 Mui v3.3.0使用dialog实现密码的输入及验证

弹出框 技术分享 mui

需求描述

使用dialog弹出密码输入框,用户输入密码并且密码验证通过后方可关闭dialog。

需求分析

首先,dialog中提供密码输入框。
其次,用户输入密码后对密码进行验证。
最后,通过验证则关闭dialog,否则不关闭dialog并提示错误信息。

实现思路

dialog

mui提供了许多dialog,只有mui.prompt()提供了输入框,但它并不是密码框。
mui.confirm()的message参数,可以传html代码段来展示密码框,就选它了。

回调函数

由于当前版本mui,点击dialog中的按钮均会关闭dialog,所以需要对dialog按钮的默认行为进行修改。
注:下个版本会更新此修改,目前需要的话请下载附件中的mui.js文件。

验证密码

对用户输入的密码进行验证后,如果验证失败,则需要做出相应的提示。
和密码框的思路一样,使用一个文本内容默认为空的元素来展示错误信息。

功能实现

密码输入框

使用mui.confirm()弹出密码输入框。

mui.confirm('<input type="password" id="test" />', 'Hello MUI', null, function(e) {},'div');  

注:这里需要声明使用H5模式的dialog,参考文档dialog

阻止关闭dialog

用户输入完成后,点击”确认“按钮,验证密码。

mui.confirm('<input type="password" id="test" />', 'Hello MUI', null, function(event) {  
    var index = event.index;  
    if(index === 1) {  
        var pwd = document.getElementById('test').value;  
        // 验证失败返回false  
        return false;  
    }  
},'div');  

修改按钮的默认行为后,在回调函数中返回false,则不会关闭dialog。

错误信息

在拼接密码输入框的同时,见错误信息提示的元素一起拼接。

mui.confirm('<input type="password" id="test" /><span id="error">&nbsp</span>', 'Hello MUI', null, function(event) {},'div');  

源码

附上源码,直接浏览即可。

继续阅读 »

需求描述

使用dialog弹出密码输入框,用户输入密码并且密码验证通过后方可关闭dialog。

需求分析

首先,dialog中提供密码输入框。
其次,用户输入密码后对密码进行验证。
最后,通过验证则关闭dialog,否则不关闭dialog并提示错误信息。

实现思路

dialog

mui提供了许多dialog,只有mui.prompt()提供了输入框,但它并不是密码框。
mui.confirm()的message参数,可以传html代码段来展示密码框,就选它了。

回调函数

由于当前版本mui,点击dialog中的按钮均会关闭dialog,所以需要对dialog按钮的默认行为进行修改。
注:下个版本会更新此修改,目前需要的话请下载附件中的mui.js文件。

验证密码

对用户输入的密码进行验证后,如果验证失败,则需要做出相应的提示。
和密码框的思路一样,使用一个文本内容默认为空的元素来展示错误信息。

功能实现

密码输入框

使用mui.confirm()弹出密码输入框。

mui.confirm('<input type="password" id="test" />', 'Hello MUI', null, function(e) {},'div');  

注:这里需要声明使用H5模式的dialog,参考文档dialog

阻止关闭dialog

用户输入完成后,点击”确认“按钮,验证密码。

mui.confirm('<input type="password" id="test" />', 'Hello MUI', null, function(event) {  
    var index = event.index;  
    if(index === 1) {  
        var pwd = document.getElementById('test').value;  
        // 验证失败返回false  
        return false;  
    }  
},'div');  

修改按钮的默认行为后,在回调函数中返回false,则不会关闭dialog。

错误信息

在拼接密码输入框的同时,见错误信息提示的元素一起拼接。

mui.confirm('<input type="password" id="test" /><span id="error">&nbsp</span>', 'Hello MUI', null, function(event) {},'div');  

源码

附上源码,直接浏览即可。

收起阅读 »

流应用体验视频及入口说明

流应用

流应用有多种入口来源,并非单一的应用市场搜索。

1. 使用DCloud流应用管理器

手机访问http://m3w.cn,可下载DCloud流应用管理器,获取和管理本机流应用。

2. 360手机助手搜索秒开流应用

2015年10月起的360手机助手起,支持搜索流应用名字,显示秒开按钮。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_i0171dyo7cf.html

3. 金立手机软件商店秒开流应用

2017年6月起的金立软件商店版本,可以在搜索页面下方推荐位及软件分类-即点即用里使用流应用。https://bbs.amigo.cn/forum.php?mod=viewthread&tid=217285
手机原厂支持的流应用,体验更优秀。

4. 360手机浏览器秒开流应用

2016年11月起,360手机浏览器8.0安卓版,开始内嵌流应用引擎。
在地址栏里敲vip.com,可以直接进入流应用。
使用时有3点注意:1.360浏览器会在WiFi下静默下载流应用插件,如果插件没下载完或不是在WiFi下,启动时仍然是普通H5。2. 普通H5和流应用的区别是,流应用顶部有一个黑色的导航条,没有地址栏。
https://v.qq.com/x/page/n0336208o73.html

5. 青柠桌面云文件夹

青柠桌面是国内较大的第三方laucher,其预置了流应用云文件夹,里面的应用即点即用又可以达到原生体验。实现了更高效率的分发变现。
可以点击这里下载体验

6. 快码,扫描立即秒装app

快码是一种集成了流应用、原生App下载、微信公众号关注、微博关注于一体的统一码。
快码是连接线上线下最便捷的方式。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_w0171ems73j.html

快码还具备扫码直通功能,扫码如下的码,能直接进入到大众点评外卖里的必胜客餐厅。

打通App孤岛,直达内容,这是HTML5及流应用的重要优势。

7. 分享,通过社交网络快速传播app

分享一个App,就像分享一个消息。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_r0171bswy6f.html

分享同样支持分享直通车,可以分享App里的具体内容, 比如:
一个资讯App的某条文章;
一个视频App的某个电影;
一个电商App的某个商品...

8. 推送流应用

推送是推广的大杀器,只要精准筛选目标用户,在合适的时间、给合适的人以合适的信息,点击推送后App立即安装激活。推广效率可以用“恐怖”来形容。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_k0171y6vfyu_x01833hx4q3.html

9. 手机网页打开流应用

这里有文章专门讲解如何通过wap浏览器打开流应用,把wap用户变成app用户。http://ask.dcloud.net.cn/article/579
视频如下:http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_k0171y6vfyu_t0190xh3198.html

10. 从一个App里打开流应用

app互推荐或应用内广告,也是流应用的流量来源。因为原生app的下载安装麻烦,所以一直以来积分墙等app互推业务并没有起量。但app向流应用导流的效果要好于向原生app数倍,重新打开了这个流量市场。
文档:http://ask.dcloud.net.cn/article/670

11. 清理卸载入口

360手机助手从2016年7月起的版本,在清理应用卸载时,会提示用户是否在桌面放一个微应用快捷方式图标在桌面。


每天有数千万人在清理卸载原生App。
非Top30的App,如果体积大、有后台耗电,很容易被用户清理掉。
原生Apk辛苦发展来的激活用户就此流失。
但有30%的用户在卸载后会点击保留微应用版本,实现低频应用的驻留。

继续阅读 »

流应用有多种入口来源,并非单一的应用市场搜索。

1. 使用DCloud流应用管理器

手机访问http://m3w.cn,可下载DCloud流应用管理器,获取和管理本机流应用。

2. 360手机助手搜索秒开流应用

2015年10月起的360手机助手起,支持搜索流应用名字,显示秒开按钮。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_i0171dyo7cf.html

3. 金立手机软件商店秒开流应用

2017年6月起的金立软件商店版本,可以在搜索页面下方推荐位及软件分类-即点即用里使用流应用。https://bbs.amigo.cn/forum.php?mod=viewthread&tid=217285
手机原厂支持的流应用,体验更优秀。

4. 360手机浏览器秒开流应用

2016年11月起,360手机浏览器8.0安卓版,开始内嵌流应用引擎。
在地址栏里敲vip.com,可以直接进入流应用。
使用时有3点注意:1.360浏览器会在WiFi下静默下载流应用插件,如果插件没下载完或不是在WiFi下,启动时仍然是普通H5。2. 普通H5和流应用的区别是,流应用顶部有一个黑色的导航条,没有地址栏。
https://v.qq.com/x/page/n0336208o73.html

5. 青柠桌面云文件夹

青柠桌面是国内较大的第三方laucher,其预置了流应用云文件夹,里面的应用即点即用又可以达到原生体验。实现了更高效率的分发变现。
可以点击这里下载体验

6. 快码,扫描立即秒装app

快码是一种集成了流应用、原生App下载、微信公众号关注、微博关注于一体的统一码。
快码是连接线上线下最便捷的方式。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_w0171ems73j.html

快码还具备扫码直通功能,扫码如下的码,能直接进入到大众点评外卖里的必胜客餐厅。

打通App孤岛,直达内容,这是HTML5及流应用的重要优势。

7. 分享,通过社交网络快速传播app

分享一个App,就像分享一个消息。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_r0171bswy6f.html

分享同样支持分享直通车,可以分享App里的具体内容, 比如:
一个资讯App的某条文章;
一个视频App的某个电影;
一个电商App的某个商品...

8. 推送流应用

推送是推广的大杀器,只要精准筛选目标用户,在合适的时间、给合适的人以合适的信息,点击推送后App立即安装激活。推广效率可以用“恐怖”来形容。
http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_k0171y6vfyu_x01833hx4q3.html

9. 手机网页打开流应用

这里有文章专门讲解如何通过wap浏览器打开流应用,把wap用户变成app用户。http://ask.dcloud.net.cn/article/579
视频如下:http://v.qq.com/boke/gplay/c17d8789e7dd8a208cd6e6189ae90664_nst000001qufah3_k0171y6vfyu_t0190xh3198.html

10. 从一个App里打开流应用

app互推荐或应用内广告,也是流应用的流量来源。因为原生app的下载安装麻烦,所以一直以来积分墙等app互推业务并没有起量。但app向流应用导流的效果要好于向原生app数倍,重新打开了这个流量市场。
文档:http://ask.dcloud.net.cn/article/670

11. 清理卸载入口

360手机助手从2016年7月起的版本,在清理应用卸载时,会提示用户是否在桌面放一个微应用快捷方式图标在桌面。


每天有数千万人在清理卸载原生App。
非Top30的App,如果体积大、有后台耗电,很容易被用户清理掉。
原生Apk辛苦发展来的激活用户就此流失。
但有30%的用户在卸载后会点击保留微应用版本,实现低频应用的驻留。

收起阅读 »

Deferred long-running timer task(s)...

Deferred long-running timer task(s) to improve scrolling smoothness. See crbug.com/574343

Deferred long-running timer task(s) to improve scrolling smoothness. See crbug.com/574343

Mui前端架子(编程规范分享)

mui

原文标题:PHP Lumen - 入门教程 - web前端架子
转来自我的博客:http://blog.csdn.net/wowkk/article/details/52254696

用了Lumen一段时间了,感觉还不错。也适合全栈开发。因为我一丢丢PHP基础都没看就直接用起了框架,挺多地方还是闹笑话了。比如,字符串追加,PHP它喵的居然是用 “.” 来追加,而通过“->”进行属性调用也是不爽~

这个web前端架子,不是Lumen专用的,额外分享。

首先我写了一个公共类(common.js),主要用来进行封装请求的。

/*!  
 * =====================================================  
 * 全局通用变量  
 * =====================================================  
 */  
var Common = {};  
//Common.ServerUrl = "http://120.24.xx.xx:8080/";       //线上测试版本  
Common.ServerUrl = "http://192.168.0.110:8080/";    //公司测试版本  
//Common.ServerUrl = "http://192.168.99.139:8080/";     //宿舍测试版本  

Common.Post = function(url,data,successcallback,errcallback){  
    console.log(Common.jsonToUrl(url,data));  
    if(errcallback==null){  
        errcallback = function(xhr,type,errorThrown){  
            console.log(JSON.stringify(xhr))  
            plus.nativeUI.closeWaiting();//关闭旋转菊花  
            alert("网络异常:" + url);  
        }  
    }  
    //这里的mui是HBuilder跨平台开发工具自己的js,根据自己项目调改。  
    mui.ajax(Common.ServerUrl + url,{  
        data:data,  
        dataType:'json',  
        type:'post',  
        timeout:5000,  
        success:successcallback,  
        error:errcallback  
    });  
}  

Common.jsonToUrl=function(url,jsonData){  
    var full_url = Common.ServerUrl + url + "?";  
    for(var index in jsonData){  
        full_url = full_url + index + "=" + jsonData[index] + "&";  
    }  
    return full_url;  
};

可以把这段代码塞到js插件里面去(比如jQuery)减少请求。
这一丢丢代码有几个好处:
1.统一请求的url,不需要每个页面都去设置请求地址。页面发送ajax时,只需要把相对路径传进来就行了。
2.统一错误返回的处理,可以即时知道哪个请求出错。也可以根据需要特殊回调处理。
3.把post的data转换为url地址,方便直接复制到浏览器进行get调试。
4.方便拓展与维护,比如可以统一处理“未登录则自动跳转到登录页”。

再看下html页的代码

<script>  
        /*  
         * 页面配置  
         */  
        var PAGE = {  
                View: {},  
                page: 0,  
                Model: {  
                    Article: function(article) {  
                        return '<article id="' + article.information_id + '">' +  
                            '<div class="article-time">' +  
                            '<span>' + article.time_title + '</span>' +  
                            '</div>' +  
                            '<div class="article-bg" style="background-image: url(' + article.information_imgurl + ');">' +  
                            '<div class="article-bg-cover">' +  
                            '<span class="information_title"># ' + article.information_title + '</span>' +  
                            '</div>' +  
                            '</div>' +  
                            '<div class="mui-pull-right article_collect">' +  
                            '<img style="width: 100%;" src="../../img/news_shoucang.png" />' +  
                            '<div class="article_collect_fone">' + article.favour_num + '</div>' +  
                            '</div>' +  
                            '</article>';  
                    },  
                    Articles:function(articles){  
                        var html = "";  
                        for(var i = 0; i < articles.length; i++) {  
                            html += PAGE.Model.Article(articles[i]);  
                        }  
                        return html;  
                    }  
                }  
            };  
        mui.init();//(mui框架需要)初始化框架  
        mui.plusReady(function() {  
            PAGE.Init();//初始化本页面  
        });  
        /*  
         * 页面初始化  
         */  
        PAGE.Init = function() {  
                PAGE.preloadView();  
                PAGE.addEventListener();  
            }  
            /*  
             * 页面预加载  
             */  
        PAGE.preloadView = function() {}  
            /*  
             * 事件监听  
             */  
        PAGE.addEventListener = function() {  
            PAGE.addEventListener_Article();//确定监听点击文章列表的元素  
        }  
            /*  
             * 页面预加载-实现  
             */  
        PAGE.preloadView_Name = function() {}  
            /*  
             * 事件监听-实现  
             */  
        PAGE.addEventListener_Article = function() {  
                mui("#div_newList").on("tap", "article", function() {  
                    mui.openWindow({  
                        id: "/View/News/details.html",  
                        url: "/View/News/details.html",  
                        extras: {  
                            information_id: this.id,  
                            information_title: this.getElementsByClassName("information_title")[0].innerText,  
                            information_imgurl: this.getElementsByClassName("article-bg")[0].style.backgroundImage  
                        }  
                    })  
                })  
            }  
            /*  
             * 事件实现  
             */  
        PAGE.Event_Name = function() {}  
    </script>

编出来的这段,个人用起来还是比较舒服的。
1.所有js代码都是在PAGE这个域里面,尽量避免污染。
2.将所有监听事件独个封装起来,然后由PAGE.addEventListener统一调用。这样在简单事件较多的情况下,代码也足够清晰易阅读和定位。
3.所有动态生成的代码放在PAGE.Model对象里面(传人json数据,返回对应的html代码)。同样也是清晰易阅读和定位。
4.普通函数比如,更新页面数据就用PAGE.Event_XXX格式命名函数。这个主要就是统一规范吧。
5.一些配置变量,比如当前页PageNum,也可以防止PAGE里面去维护。

接下来继续实战,看能不能怎么优化。现在为了性能,大多数都是用原生js,看看有没有机会封装个js架子。

继续阅读 »

原文标题:PHP Lumen - 入门教程 - web前端架子
转来自我的博客:http://blog.csdn.net/wowkk/article/details/52254696

用了Lumen一段时间了,感觉还不错。也适合全栈开发。因为我一丢丢PHP基础都没看就直接用起了框架,挺多地方还是闹笑话了。比如,字符串追加,PHP它喵的居然是用 “.” 来追加,而通过“->”进行属性调用也是不爽~

这个web前端架子,不是Lumen专用的,额外分享。

首先我写了一个公共类(common.js),主要用来进行封装请求的。

/*!  
 * =====================================================  
 * 全局通用变量  
 * =====================================================  
 */  
var Common = {};  
//Common.ServerUrl = "http://120.24.xx.xx:8080/";       //线上测试版本  
Common.ServerUrl = "http://192.168.0.110:8080/";    //公司测试版本  
//Common.ServerUrl = "http://192.168.99.139:8080/";     //宿舍测试版本  

Common.Post = function(url,data,successcallback,errcallback){  
    console.log(Common.jsonToUrl(url,data));  
    if(errcallback==null){  
        errcallback = function(xhr,type,errorThrown){  
            console.log(JSON.stringify(xhr))  
            plus.nativeUI.closeWaiting();//关闭旋转菊花  
            alert("网络异常:" + url);  
        }  
    }  
    //这里的mui是HBuilder跨平台开发工具自己的js,根据自己项目调改。  
    mui.ajax(Common.ServerUrl + url,{  
        data:data,  
        dataType:'json',  
        type:'post',  
        timeout:5000,  
        success:successcallback,  
        error:errcallback  
    });  
}  

Common.jsonToUrl=function(url,jsonData){  
    var full_url = Common.ServerUrl + url + "?";  
    for(var index in jsonData){  
        full_url = full_url + index + "=" + jsonData[index] + "&";  
    }  
    return full_url;  
};

可以把这段代码塞到js插件里面去(比如jQuery)减少请求。
这一丢丢代码有几个好处:
1.统一请求的url,不需要每个页面都去设置请求地址。页面发送ajax时,只需要把相对路径传进来就行了。
2.统一错误返回的处理,可以即时知道哪个请求出错。也可以根据需要特殊回调处理。
3.把post的data转换为url地址,方便直接复制到浏览器进行get调试。
4.方便拓展与维护,比如可以统一处理“未登录则自动跳转到登录页”。

再看下html页的代码

<script>  
        /*  
         * 页面配置  
         */  
        var PAGE = {  
                View: {},  
                page: 0,  
                Model: {  
                    Article: function(article) {  
                        return '<article id="' + article.information_id + '">' +  
                            '<div class="article-time">' +  
                            '<span>' + article.time_title + '</span>' +  
                            '</div>' +  
                            '<div class="article-bg" style="background-image: url(' + article.information_imgurl + ');">' +  
                            '<div class="article-bg-cover">' +  
                            '<span class="information_title"># ' + article.information_title + '</span>' +  
                            '</div>' +  
                            '</div>' +  
                            '<div class="mui-pull-right article_collect">' +  
                            '<img style="width: 100%;" src="../../img/news_shoucang.png" />' +  
                            '<div class="article_collect_fone">' + article.favour_num + '</div>' +  
                            '</div>' +  
                            '</article>';  
                    },  
                    Articles:function(articles){  
                        var html = "";  
                        for(var i = 0; i < articles.length; i++) {  
                            html += PAGE.Model.Article(articles[i]);  
                        }  
                        return html;  
                    }  
                }  
            };  
        mui.init();//(mui框架需要)初始化框架  
        mui.plusReady(function() {  
            PAGE.Init();//初始化本页面  
        });  
        /*  
         * 页面初始化  
         */  
        PAGE.Init = function() {  
                PAGE.preloadView();  
                PAGE.addEventListener();  
            }  
            /*  
             * 页面预加载  
             */  
        PAGE.preloadView = function() {}  
            /*  
             * 事件监听  
             */  
        PAGE.addEventListener = function() {  
            PAGE.addEventListener_Article();//确定监听点击文章列表的元素  
        }  
            /*  
             * 页面预加载-实现  
             */  
        PAGE.preloadView_Name = function() {}  
            /*  
             * 事件监听-实现  
             */  
        PAGE.addEventListener_Article = function() {  
                mui("#div_newList").on("tap", "article", function() {  
                    mui.openWindow({  
                        id: "/View/News/details.html",  
                        url: "/View/News/details.html",  
                        extras: {  
                            information_id: this.id,  
                            information_title: this.getElementsByClassName("information_title")[0].innerText,  
                            information_imgurl: this.getElementsByClassName("article-bg")[0].style.backgroundImage  
                        }  
                    })  
                })  
            }  
            /*  
             * 事件实现  
             */  
        PAGE.Event_Name = function() {}  
    </script>

编出来的这段,个人用起来还是比较舒服的。
1.所有js代码都是在PAGE这个域里面,尽量避免污染。
2.将所有监听事件独个封装起来,然后由PAGE.addEventListener统一调用。这样在简单事件较多的情况下,代码也足够清晰易阅读和定位。
3.所有动态生成的代码放在PAGE.Model对象里面(传人json数据,返回对应的html代码)。同样也是清晰易阅读和定位。
4.普通函数比如,更新页面数据就用PAGE.Event_XXX格式命名函数。这个主要就是统一规范吧。
5.一些配置变量,比如当前页PageNum,也可以防止PAGE里面去维护。

接下来继续实战,看能不能怎么优化。现在为了性能,大多数都是用原生js,看看有没有机会封装个js架子。

收起阅读 »

底部选项卡被输入法撑起问题解决

输入法 选项卡

1.如果是单页面出现的问题,可以使用
mui.plusReady(function() {
//设置bottom绝对位置
document.getElementById('bottomx').style.top = (plus.display.resolutionHeight - 50) + "px";
});
这段代码 转自:解决弹出输入法时页面高度变小导致底部上浮的问题

2.如果选项卡在父页面中,并且在页面中的样式中设置了bottom属性,可以使用
mui.plusReady(function(){
var self=plus.webview.currentWebview();
/**

  • 防止 在write页面输入文字的时候 , 输入法把选项卡撑起来
    */
    var parentVebView =self.opener();
    //防止 父页面选项卡被输入法撑起
    window.addEventListener('resize', function() {
    var a=plus.android.invoke(plus.android.currentWebview(),"getHeight") ;
    var b=plus.navigator.getStatusbarHeight();
    var c=plus.screen.resolutionHeight ;
    var d=(c-a-b);
    console.info('webview高度:'+a+" 状态栏高度:"+b+" 屏幕高度:"+c+" 输入法高度:"+d)
    d >0 ? self.setStyle({top: '45px',bottom: '0px'}) : self.setStyle({top: '45px',bottom: '50px'});
    //d > 0 ? parentVebView.evalJS("mui('#nav_id').css('position','absolute');") : parentVebView.evalJS("mui('#nav_id').css('position','fixed');");
    }, false);
    });
    当输入法打开时 重新设置当前webview的 style属性
继续阅读 »

1.如果是单页面出现的问题,可以使用
mui.plusReady(function() {
//设置bottom绝对位置
document.getElementById('bottomx').style.top = (plus.display.resolutionHeight - 50) + "px";
});
这段代码 转自:解决弹出输入法时页面高度变小导致底部上浮的问题

2.如果选项卡在父页面中,并且在页面中的样式中设置了bottom属性,可以使用
mui.plusReady(function(){
var self=plus.webview.currentWebview();
/**

  • 防止 在write页面输入文字的时候 , 输入法把选项卡撑起来
    */
    var parentVebView =self.opener();
    //防止 父页面选项卡被输入法撑起
    window.addEventListener('resize', function() {
    var a=plus.android.invoke(plus.android.currentWebview(),"getHeight") ;
    var b=plus.navigator.getStatusbarHeight();
    var c=plus.screen.resolutionHeight ;
    var d=(c-a-b);
    console.info('webview高度:'+a+" 状态栏高度:"+b+" 屏幕高度:"+c+" 输入法高度:"+d)
    d >0 ? self.setStyle({top: '45px',bottom: '0px'}) : self.setStyle({top: '45px',bottom: '50px'});
    //d > 0 ? parentVebView.evalJS("mui('#nav_id').css('position','absolute');") : parentVebView.evalJS("mui('#nav_id').css('position','fixed');");
    }, false);
    });
    当输入法打开时 重新设置当前webview的 style属性
收起阅读 »

mui主动触发上拉下拉加载

mui.init({
pullRefresh : {
container:refreshContainer,//待刷新区域标识,querySelector能定位的css选择器均可,比如:id、.class等
up : {
contentrefresh : "正在加载...",//可选,正在加载状态时,上拉加载控件上显示的标题内容
contentnomore:'没有更多数据了',//可选,请求完毕若没有更多数据时显示的提醒内容;
callback :pullfresh-function ,
auto:true//页面加载完就加载一次
}
}
});

主动下拉加载
mui('#pullrefresh').pullRefresh().pulldownLoading();
主动上拉加载
mui('#pullrefresh').pullRefresh().pullupLoading();

继续阅读 »

mui.init({
pullRefresh : {
container:refreshContainer,//待刷新区域标识,querySelector能定位的css选择器均可,比如:id、.class等
up : {
contentrefresh : "正在加载...",//可选,正在加载状态时,上拉加载控件上显示的标题内容
contentnomore:'没有更多数据了',//可选,请求完毕若没有更多数据时显示的提醒内容;
callback :pullfresh-function ,
auto:true//页面加载完就加载一次
}
}
});

主动下拉加载
mui('#pullrefresh').pullRefresh().pulldownLoading();
主动上拉加载
mui('#pullrefresh').pullRefresh().pullupLoading();

收起阅读 »

怎么从零开始学习Dcloud的技术,开发手机APP?

5+App开发 mui HBuilder 视频教程 学习

推荐国内首推的跨平台移动APP开发专业培训机构-东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!咨询报名QQ:410355878 网址:http://www.dongyixueyuan.com/ 欢迎有意向学习的朋友加好友咨询!谢谢Dcloud提供这么好的平台!

立即学习

继续阅读 »

推荐国内首推的跨平台移动APP开发专业培训机构-东翌学院是Dcloud的合作培训机构,跨平台APP开发整体课程在线直播+课程源码+全套视频,最新最全的APP开发,HB和MUI的全套视频,零基础都可以学习,更有高级进修课程,30天最快速的开发跨平台APP!咨询报名QQ:410355878 网址:http://www.dongyixueyuan.com/ 欢迎有意向学习的朋友加好友咨询!谢谢Dcloud提供这么好的平台!

立即学习

收起阅读 »

HTML5新增标签总结、简单说明

从使用的特点上来看,HTML5相对以前版本来看给人的感觉就是更加人性化。按照以往的页面布局习惯是<div id="article"> 代表内容模块,<div id="aside">代表边栏模块,通过这种方式来区分每个div的区块部分。HTML5就不一样了,一改以往布局习惯换成<article>、<aside> 这些更加语义化的标签。所以说H5增加了这些标签最大的作用就是语义化,便于读取和识辨。因此也更加适合做SEO,容易快速准确的被爬虫读取,就像head和 titile 这样的标签元素一样。同时一些移动设备在解析到这些标签的时候做出特殊提示或者更加人性化的展示 等等。
HTML5新增了哪些标签(来源网络)

标签 标记意义及用法分析/示例 属性/属性值/描述
<article> 定义独立的内容,如论坛帖子、报纸文章、博客条目、用户评论等内容。 支持HTML5的全局属性和事件属性。
<aside> 定义两栏或多栏页面的侧边栏内容,如联系我们、客服、网站公告等内容。 支持HTML5的全局属性和事件属性。
<audio> 定义音频内容,如音乐或其他音频流。
autoplay autoplay 自动播放。
controls controls 显示控件。
loop loop 自动重播。
preload preload 预备播放。如果使用 “autoplay”,则忽略该属性。
src url 音频的URL。
支持HTML5的全局属性和事件属性。
<audio src=”audio.wav”>
您的浏览器不支持 audio 标签。(注:可以在开始标签和结束标签之间加上此文本内容,这样若浏览器不支持此元素,就可以显示出这个信息。)
</audio>

<canvas> 定义图形,如图表和其他图像。(注:<canvas> 只是图形容器,我们必须使用脚本来绘制图形。)
height pixels 设置 canvas 的高度。
width pixels 设置 canvas 的宽度。
支持HTML5的全局属性和事件属性。
<canvas id=”myCanvas”></canvas>
<script type=”text/javascript”>
var canvas=document.getElementById(‘myCanvas’);
var ctx=canvas.getContext(‘2d’);
ctx.fillStyle=’#FFFF00′;
ctx.fillRect(0,0,20,30);
</script>

<command> 标记定义一个命令按钮,比如单选按钮、复选框或按钮。只有当 command 元素位于 menu 元素内时,该元素才是可见的。否则不会显示这个元素,但是可以用它规定键盘快捷键。
checked checked 定义是否被选中。仅用于 radio 或 checkbox 类型
disabled disabled 定义 command 是否可用
icon url 定义作为 command 来显示的图像的url
label text 为 command 定义可见的 label
radiogroup groupname 定义 command 所属的组名。仅在类型为 radio 时使用
type checkbox
command
radio
定义该 command 的类型。默认是 “command”
支持HTML5的全局属性和事件属性。
<menu>
<command onclick=”alert(‘Hello!’)”>Click here.</command>
</menu>

<datalist> 定义选项列表,需与 input 元素配合使用,通过input 元素的 list 属性来绑定,用来定义 input 可能的值。datalist 及其选项不会被显示出来,它仅仅是合法的输入值列表。 支持HTML5的全局属性和事件属性。
<input id=”fruits” list=”fruits” />
<datalist id=”fruits”>
<option value=”Apple”>
<option value=”Banana”>
</datalist>

<details> 用于描述文档或文档某个部分的细节。
open open 定义 details 是否可见
支持HTML5的全局属性和事件属性。
<details>
<summary>Some title.</summary>
<p>Some details about the title.</p>
</details>

<embed> 定义外部的可交互的内容或插件。
height pixels 设置嵌入内容的高度
src url 嵌入内容的 URL
type type 定义嵌入内容的类型
width pixels 设置嵌入内容的宽度
支持HTML5的全局属性和事件属性。
<embed src=”someone.swf” />

<figure> 定义一组媒体内容(图像、图表、照片、代码等)以及它们的标题。如果被删除,则不应对文档流产生影响。 支持HTML5的全局属性和事件属性。
<figure>
<p>The title of the image.</p>
<img src=”someimage.jpg” width=”100″ height=”50″ />
</figure>

<footer> 定义一个页面或一个区域的页脚。可包含文档的作者姓名、创作日期或者联系信息。 支持HTML5的全局属性和事件属性。
<header> 定义一个页面或一个区域的头部。 支持HTML5的全局属性和事件属性。
<hgroup> 定义文件中一个区块的相关信息,使用 <hgroup> 标签对网页或区段(section)的标题进行组合。 支持HTML5的全局属性和事件属性。
<hgroup>
<h1>Welcome my world!</h1>
<h2>This is a title.</h2>
</hgroup>

<keygen> 定义表单里一个生成的键值。规定用于表单的密钥对生成器字段。当提交表单时,私钥存储在本地,公钥发送到服务器。
autofocus autofocus 使 keygen 字段在页面加载时获得焦点
challenge challenge 如果使用,则将 keygen 的值设置为在提交时询问
disabled disabled 禁用 keytag 字段
form formname 定义该 keygen 字段所属的一个或多个表单
keytype rsa 定义 keytype。rsa 生成 RSA 密钥
name fieldname 定义 keygen 元素的唯一名称,用于在提交表单时搜集字段的值。
支持HTML5的全局属性和事件属性。
<form action=”demo_keygen.asp” method=”get”>
Username: <input type=”text” name=”usr_name” />
Encryption: <keygen name=”security” />
<input type=”submit” />
</form>

<mark> 定义有标记的文本。请在需要突出显示文本时使用此标签。 支持HTML5的全局属性和事件属性。
<p>I like <mark>apple</mark> most.</p>

<meter> 定义度量衡。仅用于已知最大和最小值的度量。(注:必须定义度量的范围,既可以在元素的文本中,也可以在 min/max 属性中定义。)
high number 定义度量的值位于哪个点,被界定为高的值
low number 定义度量的值位于哪个点,被界定为低的值
max number 定义最大值。默认值是 1
min number 定义最小值。默认值是 0
optimum number 定义什么样的度量值是最佳的值。如果该值高于 “high” 属性,则意味着值越高越好。如果该值低于 “low” 属性的值,则意味着值越低越好。
value number 定义度量的值
支持HTML5的全局属性和事件属性。
<meter min=”0″ max=”10″>2</meter>
<meter>2 out of 5</meter>
<meter>10%</meter>

<nav> 定义导航链接。(注:如果文档中有“前后”按钮,则应该把它放到 <nav> 元素中。) 支持HTML5的全局属性和事件属性。
<nav>
<a href=”index.asp”>Home</a>
<a href=”Previous.asp”>Previous</a>
<a href=”Next.asp”>Next</a>
</nav>

<output> 定义不同类型的输出,比如脚本的输出。
for id of another element 定义输出域相关的一个或多个元素
form formname 定义输入字段所属的一个或多个表单
name unique name 定义对象的唯一名称。(表单提交时使用)
支持HTML5的全局属性和事件属性。
<progress> 定义任务(如下载)的过程,可以使用此标签来显示 JavaScript 中耗费时间的函数的进度。
max number 定义完成的值
value number 定义进程的当前值
支持HTML5的全局属性和事件属性。
<progress>
<span id=”progress”>15</span>%
</progress>

<ruby> 定义 ruby 注释(中文注音或字符)。在东亚使用,显示的是东亚字符的发音。ruby 元素由一个或多个字符(需要一个解释/发音)和一个提供该信息的 rt 元素组成,还包括可选的 rp 元素,定义当浏览器不支持 “ruby” 元素时显示的内容。 支持HTML5的全局属性和事件属性。
<section> 定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
cite URL 当 section 摘自 web 的时候使用
支持HTML5的全局属性和事件属性。
<source> 为媒介元素(比如 <video> 和 <audio>)定义媒介资源。
media media query 定义媒介资源的类型,供浏览器决定是否下载
src url 媒介的 URL
type numeric value 定义播放器在音频流中播放起始位置。默认是从开头播放。
支持HTML5的全局属性和事件属性。
<time> 定义一个日期/时间,该元素能够以机器可读的方式对日期和时间进行编码,举例说,用户代理能够把生日提醒或排定的事件添加到用户日程表中,搜索引擎也能够生成更智能的搜索结果。
datetime datetime 规定日期或时间。否则,由元素的内容给定日期或时间
pubdate pubdate 指示 <time> 元素中的日期或时间是文档的发布日期
支持HTML5的全局属性和事件属性。
<p>大家都是早上 <time>9:00</time> 上班。</p>
<p><time datetime=”2012-01-01″>元旦</time>晚会。</p>

<video> 定义视频,比如电影片段或其他视频流。
autoplay autoplay 自动播放。
controls controls 显示控件。
height pixels 设置视频播放器的高度
loop loop 自动重播。
preload preload 预备播放。如果使用 “autoplay”,则忽略该属性。
src url 视频的URL。
width pixels 设置视频播放器的宽度
支持HTML5的全局属性和事件属性。
<video src=”movie.ogg” controls=”controls”>
您的浏览器不支持 video 标签。(注:可以在开始标签和结束标签之间加上此文本内容,这样若浏览器不支持此元素,就可以显示出这个信息。)
</video>

继续阅读 »

从使用的特点上来看,HTML5相对以前版本来看给人的感觉就是更加人性化。按照以往的页面布局习惯是<div id="article"> 代表内容模块,<div id="aside">代表边栏模块,通过这种方式来区分每个div的区块部分。HTML5就不一样了,一改以往布局习惯换成<article>、<aside> 这些更加语义化的标签。所以说H5增加了这些标签最大的作用就是语义化,便于读取和识辨。因此也更加适合做SEO,容易快速准确的被爬虫读取,就像head和 titile 这样的标签元素一样。同时一些移动设备在解析到这些标签的时候做出特殊提示或者更加人性化的展示 等等。
HTML5新增了哪些标签(来源网络)

标签 标记意义及用法分析/示例 属性/属性值/描述
<article> 定义独立的内容,如论坛帖子、报纸文章、博客条目、用户评论等内容。 支持HTML5的全局属性和事件属性。
<aside> 定义两栏或多栏页面的侧边栏内容,如联系我们、客服、网站公告等内容。 支持HTML5的全局属性和事件属性。
<audio> 定义音频内容,如音乐或其他音频流。
autoplay autoplay 自动播放。
controls controls 显示控件。
loop loop 自动重播。
preload preload 预备播放。如果使用 “autoplay”,则忽略该属性。
src url 音频的URL。
支持HTML5的全局属性和事件属性。
<audio src=”audio.wav”>
您的浏览器不支持 audio 标签。(注:可以在开始标签和结束标签之间加上此文本内容,这样若浏览器不支持此元素,就可以显示出这个信息。)
</audio>

<canvas> 定义图形,如图表和其他图像。(注:<canvas> 只是图形容器,我们必须使用脚本来绘制图形。)
height pixels 设置 canvas 的高度。
width pixels 设置 canvas 的宽度。
支持HTML5的全局属性和事件属性。
<canvas id=”myCanvas”></canvas>
<script type=”text/javascript”>
var canvas=document.getElementById(‘myCanvas’);
var ctx=canvas.getContext(‘2d’);
ctx.fillStyle=’#FFFF00′;
ctx.fillRect(0,0,20,30);
</script>

<command> 标记定义一个命令按钮,比如单选按钮、复选框或按钮。只有当 command 元素位于 menu 元素内时,该元素才是可见的。否则不会显示这个元素,但是可以用它规定键盘快捷键。
checked checked 定义是否被选中。仅用于 radio 或 checkbox 类型
disabled disabled 定义 command 是否可用
icon url 定义作为 command 来显示的图像的url
label text 为 command 定义可见的 label
radiogroup groupname 定义 command 所属的组名。仅在类型为 radio 时使用
type checkbox
command
radio
定义该 command 的类型。默认是 “command”
支持HTML5的全局属性和事件属性。
<menu>
<command onclick=”alert(‘Hello!’)”>Click here.</command>
</menu>

<datalist> 定义选项列表,需与 input 元素配合使用,通过input 元素的 list 属性来绑定,用来定义 input 可能的值。datalist 及其选项不会被显示出来,它仅仅是合法的输入值列表。 支持HTML5的全局属性和事件属性。
<input id=”fruits” list=”fruits” />
<datalist id=”fruits”>
<option value=”Apple”>
<option value=”Banana”>
</datalist>

<details> 用于描述文档或文档某个部分的细节。
open open 定义 details 是否可见
支持HTML5的全局属性和事件属性。
<details>
<summary>Some title.</summary>
<p>Some details about the title.</p>
</details>

<embed> 定义外部的可交互的内容或插件。
height pixels 设置嵌入内容的高度
src url 嵌入内容的 URL
type type 定义嵌入内容的类型
width pixels 设置嵌入内容的宽度
支持HTML5的全局属性和事件属性。
<embed src=”someone.swf” />

<figure> 定义一组媒体内容(图像、图表、照片、代码等)以及它们的标题。如果被删除,则不应对文档流产生影响。 支持HTML5的全局属性和事件属性。
<figure>
<p>The title of the image.</p>
<img src=”someimage.jpg” width=”100″ height=”50″ />
</figure>

<footer> 定义一个页面或一个区域的页脚。可包含文档的作者姓名、创作日期或者联系信息。 支持HTML5的全局属性和事件属性。
<header> 定义一个页面或一个区域的头部。 支持HTML5的全局属性和事件属性。
<hgroup> 定义文件中一个区块的相关信息,使用 <hgroup> 标签对网页或区段(section)的标题进行组合。 支持HTML5的全局属性和事件属性。
<hgroup>
<h1>Welcome my world!</h1>
<h2>This is a title.</h2>
</hgroup>

<keygen> 定义表单里一个生成的键值。规定用于表单的密钥对生成器字段。当提交表单时,私钥存储在本地,公钥发送到服务器。
autofocus autofocus 使 keygen 字段在页面加载时获得焦点
challenge challenge 如果使用,则将 keygen 的值设置为在提交时询问
disabled disabled 禁用 keytag 字段
form formname 定义该 keygen 字段所属的一个或多个表单
keytype rsa 定义 keytype。rsa 生成 RSA 密钥
name fieldname 定义 keygen 元素的唯一名称,用于在提交表单时搜集字段的值。
支持HTML5的全局属性和事件属性。
<form action=”demo_keygen.asp” method=”get”>
Username: <input type=”text” name=”usr_name” />
Encryption: <keygen name=”security” />
<input type=”submit” />
</form>

<mark> 定义有标记的文本。请在需要突出显示文本时使用此标签。 支持HTML5的全局属性和事件属性。
<p>I like <mark>apple</mark> most.</p>

<meter> 定义度量衡。仅用于已知最大和最小值的度量。(注:必须定义度量的范围,既可以在元素的文本中,也可以在 min/max 属性中定义。)
high number 定义度量的值位于哪个点,被界定为高的值
low number 定义度量的值位于哪个点,被界定为低的值
max number 定义最大值。默认值是 1
min number 定义最小值。默认值是 0
optimum number 定义什么样的度量值是最佳的值。如果该值高于 “high” 属性,则意味着值越高越好。如果该值低于 “low” 属性的值,则意味着值越低越好。
value number 定义度量的值
支持HTML5的全局属性和事件属性。
<meter min=”0″ max=”10″>2</meter>
<meter>2 out of 5</meter>
<meter>10%</meter>

<nav> 定义导航链接。(注:如果文档中有“前后”按钮,则应该把它放到 <nav> 元素中。) 支持HTML5的全局属性和事件属性。
<nav>
<a href=”index.asp”>Home</a>
<a href=”Previous.asp”>Previous</a>
<a href=”Next.asp”>Next</a>
</nav>

<output> 定义不同类型的输出,比如脚本的输出。
for id of another element 定义输出域相关的一个或多个元素
form formname 定义输入字段所属的一个或多个表单
name unique name 定义对象的唯一名称。(表单提交时使用)
支持HTML5的全局属性和事件属性。
<progress> 定义任务(如下载)的过程,可以使用此标签来显示 JavaScript 中耗费时间的函数的进度。
max number 定义完成的值
value number 定义进程的当前值
支持HTML5的全局属性和事件属性。
<progress>
<span id=”progress”>15</span>%
</progress>

<ruby> 定义 ruby 注释(中文注音或字符)。在东亚使用,显示的是东亚字符的发音。ruby 元素由一个或多个字符(需要一个解释/发音)和一个提供该信息的 rt 元素组成,还包括可选的 rp 元素,定义当浏览器不支持 “ruby” 元素时显示的内容。 支持HTML5的全局属性和事件属性。
<section> 定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。
cite URL 当 section 摘自 web 的时候使用
支持HTML5的全局属性和事件属性。
<source> 为媒介元素(比如 <video> 和 <audio>)定义媒介资源。
media media query 定义媒介资源的类型,供浏览器决定是否下载
src url 媒介的 URL
type numeric value 定义播放器在音频流中播放起始位置。默认是从开头播放。
支持HTML5的全局属性和事件属性。
<time> 定义一个日期/时间,该元素能够以机器可读的方式对日期和时间进行编码,举例说,用户代理能够把生日提醒或排定的事件添加到用户日程表中,搜索引擎也能够生成更智能的搜索结果。
datetime datetime 规定日期或时间。否则,由元素的内容给定日期或时间
pubdate pubdate 指示 <time> 元素中的日期或时间是文档的发布日期
支持HTML5的全局属性和事件属性。
<p>大家都是早上 <time>9:00</time> 上班。</p>
<p><time datetime=”2012-01-01″>元旦</time>晚会。</p>

<video> 定义视频,比如电影片段或其他视频流。
autoplay autoplay 自动播放。
controls controls 显示控件。
height pixels 设置视频播放器的高度
loop loop 自动重播。
preload preload 预备播放。如果使用 “autoplay”,则忽略该属性。
src url 视频的URL。
width pixels 设置视频播放器的宽度
支持HTML5的全局属性和事件属性。
<video src=”movie.ogg” controls=”controls”>
您的浏览器不支持 video 标签。(注:可以在开始标签和结束标签之间加上此文本内容,这样若浏览器不支持此元素,就可以显示出这个信息。)
</video>

收起阅读 »

安卓上用推送通知后续操作打开url+url scheme实现透传消息效果,相比直接使用透传的优点是:传递的数据量大,到达率高

推送

安卓上用推送通知后续操作打开url url scheme实现透传消息效果,相比直接使用透传的优点是:传递的数据量大,到达率高

安卓上用推送通知后续操作打开url url scheme实现透传消息效果,相比直接使用透传的优点是:传递的数据量大,到达率高

给各位新人分享一个APP开发经验附带源码[上啦加载下拉刷新后通过ajax获取网络数据,页面传值,列表点击]

5 App开发

这是我昨天用hbuider开发的一款练手的APP,数据是调用百度API市场提供的一个微信精选API 主要涉及的操作有页面之间的传值,
上啦加载下拉刷新后执行ajax获取新的数据 ,列表点击事件

PS:其实我也是一个小白,在开发 过程中请教过很多高手指点,怀疑人生很久后才独立开发出这款APP的 界面偷了论坛某位大神写的,

内置浏览器也是偷的论坛某位大神发的 嘻嘻 看图

继续阅读 »

这是我昨天用hbuider开发的一款练手的APP,数据是调用百度API市场提供的一个微信精选API 主要涉及的操作有页面之间的传值,
上啦加载下拉刷新后执行ajax获取新的数据 ,列表点击事件

PS:其实我也是一个小白,在开发 过程中请教过很多高手指点,怀疑人生很久后才独立开发出这款APP的 界面偷了论坛某位大神写的,

内置浏览器也是偷的论坛某位大神发的 嘻嘻 看图

收起阅读 »

录音文件与Base64编码相互转换的方法

技术分享

前言

最近有几个朋友一直在问语音文件怎么转base64字符串进行发送上传,base64字符串又如何转成文件,论坛中已经有多篇问题的帖子有介绍,这里只是稍微整理,方便大家可以更加方便的使用,首先看效果:

录音文件转成base64字符串

hello mui 演示app中im-chat.html有演示案例,通过hold和release控制录音的长度,即长按按钮开始录音,释放就停止录音,上拉取消发送录音。

html部分

<button id="recorder" type="button" class="mui-btn mui-btn-blue mui-btn-block">录制语音文件转base64字符串</button>

js部分

mui.init中首先需要配置手势事件

mui.init({  
    gestureConfig: {  
        tap: true, //默认为true  
        doubletap: true, //默认为false  
        longtap: true, //默认为false  
        swipe: true, //默认为true  
        drag: true, //默认为true  
        hold: true, //默认为false,不监听  
        release: true //默认为false,不监听  
    }  
});

录音逻辑控制,按住按钮弹出录音提示框,并且对录音时长进行控制,录音时间太短取消操作,手指上划,取消发送。

var MIN_SOUND_TIME = 800;  
var recorder = null;  
var startTimestamp = null;  
var stopTimestamp = null;  
var stopTimer = null;  
var recordCancel = false;  

var soundAlert = document.getElementById("sound-alert");  
var audioTips = document.getElementById("audio-tips");  

// 控制录音弹出框是否播放  
var setSoundAlertVisable=function(show){  
    if(show){  
        soundAlert.style.display = 'block';  
        soundAlert.style.opacity = 1;  
    }else{  
        soundAlert.style.opacity = 0;  
        //  完成再真正隐藏  
        setTimeout(function(){  
            soundAlert.style.display = 'none';  
        },200);  
    }  
};  

mui.plusReady(function () {  
    /**  
     * 录制语音文件转base64字符串  
     */  
    // 按住录音(长按开始录音)  
    document.querySelector('#recorder').addEventListener('hold',function () {  
        recordCancel = false;  
    if(stopTimer)clearTimeout(stopTimer);  

    audioTips.innerHTML = "手指上划,取消发送";  
    soundAlert.classList.remove('rprogress-sigh');  
    setSoundAlertVisable(true);  

    // 获取当前设备的录音对象  
        recorder = plus.audio.getRecorder();  
        startTimestamp = (new Date()).getTime();  
        recorder.record({  
            filename:"_doc/audio/",  
            format:"amr" //iOS平台支持"wav"、"aac"、"amr"格式,默认为"wav"  
        }, function (path) {  
            if (recordCancel) return;  
            console.log("path:"+path);  
            Audio2dataURL(path);  
        }, function ( e ) {  
            mui.toast("录音出现异常: " + e.message );  
        });  
    })  

    // 释放保存(松手保存)  
    document.querySelector('#recorder').addEventListener('release',function () {  
        if (audioTips.classList.contains("cancel")) {  
            audioTips.classList.remove("cancel");  
            audioTips.innerHTML = "手指上划,取消发送";  
        }  
        // 判断录音时间  
        stopTimestamp = (new Date()).getTime();  
        if (stopTimestamp - startTimestamp < 800) {  
            audioTips.innerHTML = "录音时间太短";  
            soundAlert.classList.add('rprogress-sigh');  
            recordCancel = true;  
            stopTimer=setTimeout(function(){  
                setSoundAlertVisable(false);  
            },800);  
        }else{  
            setSoundAlertVisable(false);  
        }  
        recorder.stop();  
    })  

    // 拖动屏幕(手指上划,取消发送)  
    document.body.addEventListener('drag', function(event) {  
        if (Math.abs(event.detail.deltaY) > 50) {  
            if (!recordCancel) {  
                recordCancel = true;  
                if (!audioTips.classList.contains("cancel")) {  
                    audioTips.classList.add("cancel");  
                }  
                audioTips.innerHTML = "松开手指,取消发送";  
            }  
        } else {  
            if (recordCancel) {  
                recordCancel = false;  
                if (audioTips.classList.contains("cancel")) {  
                    audioTips.classList.remove("cancel");  
                }  
                audioTips.innerHTML = "手指上划,取消发送";  
            }  
        }  
      }, false);  
})

当录音成功后,我们可以将录音文件转成base64字符串,用于网络传输。

/**  
 * 录音语音文件转base64字符串  
 * @param {Object} path  
 */  
function Audio2dataURL (path) {  
    plus.io.resolveLocalFileSystemURL(path, function(entry){  
        entry.file(function(file){  
            var reader = new plus.io.FileReader();  
            reader.onloadend = function (e) {  
                console.log(e.target.result);  
            };  
            reader.readAsDataURL(file);  
        },function(e){  
            mui.toast("读写出现异常: " + e.message );  
        })  
    })  
}

至此我们完成了录音语音文件转base64字符串,反过来我们需要将base64字符串转成语音文件。

base64字符串转成语音文件

我们可以封装如下方法:

/**  
 * base64字符串转成语音文件(参考http://ask.dcloud.net.cn/question/16935)  
 * @param {Object} base64Str  
 * @param {Object} callback  
 */  
function dataURL2Audio (base64Str, callback) {  
    var base64Str = base64Str.replace('data:audio/amr;base64,','');  
    var audioName = (new Date()).valueOf() + '.amr';  

    plus.io.requestFileSystem(plus.io.PRIVATE_DOC,function(fs){  
        fs.root.getFile(audioName,{create:true},function(entry){  
            // 获得平台绝对路径  
            var fullPath = entry.fullPath;  
            if(mui.os.android){    
                // 读取音频  
                var Base64 = plus.android.importClass("android.util.Base64");  
                var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");  
                try{  
                    var out = new FileOutputStream(fullPath);  
                    var bytes = Base64.decode(base64Str, Base64.DEFAULT);  
                    out.write(bytes);   
                    out.close();  
                    // 回调  
                    callback && callback(entry);  
                }catch(e){  
                    console.log(e.message);  
                }  
            }else if(mui.os.ios){  
                var NSData = plus.ios.importClass('NSData');  
                var nsData = new NSData();  
                nsData = nsData.initWithBase64EncodedStringoptions(base64Str,0);  
                if (nsData) {  
                    nsData.plusCallMethod({writeToFile: fullPath,atomically:true});  
                    plus.ios.deleteObject(nsData);  
                }  
                // 回调  
                callback && callback(entry);  
            }  
        })  
    })  
}

调用方法如下:

html部分:

<button id="player" type="button" class="mui-btn mui-btn-blue mui-btn-block">base64字符串转成语音文件播放</button>

js部分:

/**  
 * base64字符串转成语音文件播放  
 */  
document.querySelector('#player').addEventListener('tap',function () {  
        // 语音文件Base64编码(由于编码过长影响阅读体验,请查看工程验证)  
     var base64Str = ' '   

        // 转成.amr文件播放  
    dataURL2Audio(base64Str, function(entry){  
        var toURL = entry.toURL();  
        // 播放音频  
        playAudio(toURL);  
    })  
})  

/**  
 * 播放音频  
 * @param {Object} path  
 */  
function playAudio (path) {  
    var player = plus.audio.createPlayer(path);  
    player.play(function(){  
        mui.toast("播放成功");  
    }, function(e) {  
        mui.toast("播放失败");  
    });   
}

写在后面

本文以语音文件为例说明5+中语音文件与Base64编码的相互转换,对于图片与Base64编码的转换方法请参考nativeObj Bitmap: 原生图片对象,可以通过loadBase64Data方法加载Base64编码格式图片到Bitmap对象,通过toBase64Data方法获取图片的Base64编码数据。对于一般性文件,建议使用h5 File API,详细可以参考我这篇文章:
JavaScript进阶学习(三)—— 基于html5 File API的文件操作

本文详细代码请查看附件工程。

继续阅读 »

前言

最近有几个朋友一直在问语音文件怎么转base64字符串进行发送上传,base64字符串又如何转成文件,论坛中已经有多篇问题的帖子有介绍,这里只是稍微整理,方便大家可以更加方便的使用,首先看效果:

录音文件转成base64字符串

hello mui 演示app中im-chat.html有演示案例,通过hold和release控制录音的长度,即长按按钮开始录音,释放就停止录音,上拉取消发送录音。

html部分

<button id="recorder" type="button" class="mui-btn mui-btn-blue mui-btn-block">录制语音文件转base64字符串</button>

js部分

mui.init中首先需要配置手势事件

mui.init({  
    gestureConfig: {  
        tap: true, //默认为true  
        doubletap: true, //默认为false  
        longtap: true, //默认为false  
        swipe: true, //默认为true  
        drag: true, //默认为true  
        hold: true, //默认为false,不监听  
        release: true //默认为false,不监听  
    }  
});

录音逻辑控制,按住按钮弹出录音提示框,并且对录音时长进行控制,录音时间太短取消操作,手指上划,取消发送。

var MIN_SOUND_TIME = 800;  
var recorder = null;  
var startTimestamp = null;  
var stopTimestamp = null;  
var stopTimer = null;  
var recordCancel = false;  

var soundAlert = document.getElementById("sound-alert");  
var audioTips = document.getElementById("audio-tips");  

// 控制录音弹出框是否播放  
var setSoundAlertVisable=function(show){  
    if(show){  
        soundAlert.style.display = 'block';  
        soundAlert.style.opacity = 1;  
    }else{  
        soundAlert.style.opacity = 0;  
        //  完成再真正隐藏  
        setTimeout(function(){  
            soundAlert.style.display = 'none';  
        },200);  
    }  
};  

mui.plusReady(function () {  
    /**  
     * 录制语音文件转base64字符串  
     */  
    // 按住录音(长按开始录音)  
    document.querySelector('#recorder').addEventListener('hold',function () {  
        recordCancel = false;  
    if(stopTimer)clearTimeout(stopTimer);  

    audioTips.innerHTML = "手指上划,取消发送";  
    soundAlert.classList.remove('rprogress-sigh');  
    setSoundAlertVisable(true);  

    // 获取当前设备的录音对象  
        recorder = plus.audio.getRecorder();  
        startTimestamp = (new Date()).getTime();  
        recorder.record({  
            filename:"_doc/audio/",  
            format:"amr" //iOS平台支持"wav"、"aac"、"amr"格式,默认为"wav"  
        }, function (path) {  
            if (recordCancel) return;  
            console.log("path:"+path);  
            Audio2dataURL(path);  
        }, function ( e ) {  
            mui.toast("录音出现异常: " + e.message );  
        });  
    })  

    // 释放保存(松手保存)  
    document.querySelector('#recorder').addEventListener('release',function () {  
        if (audioTips.classList.contains("cancel")) {  
            audioTips.classList.remove("cancel");  
            audioTips.innerHTML = "手指上划,取消发送";  
        }  
        // 判断录音时间  
        stopTimestamp = (new Date()).getTime();  
        if (stopTimestamp - startTimestamp < 800) {  
            audioTips.innerHTML = "录音时间太短";  
            soundAlert.classList.add('rprogress-sigh');  
            recordCancel = true;  
            stopTimer=setTimeout(function(){  
                setSoundAlertVisable(false);  
            },800);  
        }else{  
            setSoundAlertVisable(false);  
        }  
        recorder.stop();  
    })  

    // 拖动屏幕(手指上划,取消发送)  
    document.body.addEventListener('drag', function(event) {  
        if (Math.abs(event.detail.deltaY) > 50) {  
            if (!recordCancel) {  
                recordCancel = true;  
                if (!audioTips.classList.contains("cancel")) {  
                    audioTips.classList.add("cancel");  
                }  
                audioTips.innerHTML = "松开手指,取消发送";  
            }  
        } else {  
            if (recordCancel) {  
                recordCancel = false;  
                if (audioTips.classList.contains("cancel")) {  
                    audioTips.classList.remove("cancel");  
                }  
                audioTips.innerHTML = "手指上划,取消发送";  
            }  
        }  
      }, false);  
})

当录音成功后,我们可以将录音文件转成base64字符串,用于网络传输。

/**  
 * 录音语音文件转base64字符串  
 * @param {Object} path  
 */  
function Audio2dataURL (path) {  
    plus.io.resolveLocalFileSystemURL(path, function(entry){  
        entry.file(function(file){  
            var reader = new plus.io.FileReader();  
            reader.onloadend = function (e) {  
                console.log(e.target.result);  
            };  
            reader.readAsDataURL(file);  
        },function(e){  
            mui.toast("读写出现异常: " + e.message );  
        })  
    })  
}

至此我们完成了录音语音文件转base64字符串,反过来我们需要将base64字符串转成语音文件。

base64字符串转成语音文件

我们可以封装如下方法:

/**  
 * base64字符串转成语音文件(参考http://ask.dcloud.net.cn/question/16935)  
 * @param {Object} base64Str  
 * @param {Object} callback  
 */  
function dataURL2Audio (base64Str, callback) {  
    var base64Str = base64Str.replace('data:audio/amr;base64,','');  
    var audioName = (new Date()).valueOf() + '.amr';  

    plus.io.requestFileSystem(plus.io.PRIVATE_DOC,function(fs){  
        fs.root.getFile(audioName,{create:true},function(entry){  
            // 获得平台绝对路径  
            var fullPath = entry.fullPath;  
            if(mui.os.android){    
                // 读取音频  
                var Base64 = plus.android.importClass("android.util.Base64");  
                var FileOutputStream = plus.android.importClass("java.io.FileOutputStream");  
                try{  
                    var out = new FileOutputStream(fullPath);  
                    var bytes = Base64.decode(base64Str, Base64.DEFAULT);  
                    out.write(bytes);   
                    out.close();  
                    // 回调  
                    callback && callback(entry);  
                }catch(e){  
                    console.log(e.message);  
                }  
            }else if(mui.os.ios){  
                var NSData = plus.ios.importClass('NSData');  
                var nsData = new NSData();  
                nsData = nsData.initWithBase64EncodedStringoptions(base64Str,0);  
                if (nsData) {  
                    nsData.plusCallMethod({writeToFile: fullPath,atomically:true});  
                    plus.ios.deleteObject(nsData);  
                }  
                // 回调  
                callback && callback(entry);  
            }  
        })  
    })  
}

调用方法如下:

html部分:

<button id="player" type="button" class="mui-btn mui-btn-blue mui-btn-block">base64字符串转成语音文件播放</button>

js部分:

/**  
 * base64字符串转成语音文件播放  
 */  
document.querySelector('#player').addEventListener('tap',function () {  
        // 语音文件Base64编码(由于编码过长影响阅读体验,请查看工程验证)  
     var base64Str = ' '   

        // 转成.amr文件播放  
    dataURL2Audio(base64Str, function(entry){  
        var toURL = entry.toURL();  
        // 播放音频  
        playAudio(toURL);  
    })  
})  

/**  
 * 播放音频  
 * @param {Object} path  
 */  
function playAudio (path) {  
    var player = plus.audio.createPlayer(path);  
    player.play(function(){  
        mui.toast("播放成功");  
    }, function(e) {  
        mui.toast("播放失败");  
    });   
}

写在后面

本文以语音文件为例说明5+中语音文件与Base64编码的相互转换,对于图片与Base64编码的转换方法请参考nativeObj Bitmap: 原生图片对象,可以通过loadBase64Data方法加载Base64编码格式图片到Bitmap对象,通过toBase64Data方法获取图片的Base64编码数据。对于一般性文件,建议使用h5 File API,详细可以参考我这篇文章:
JavaScript进阶学习(三)—— 基于html5 File API的文件操作

本文详细代码请查看附件工程。

收起阅读 »