
如何通过应用A给流应用B导流
传统的应用A导应用B,比如积分墙、换量广告、各种广告sdk....他们的导流效率是非常低的。
因为原生App的下载、安装、启动有很高的门槛,进一步导致广告的效果很差。
但如果应用B是一款流应用,就可以大幅降低折损,提升广告投放效果。
流应用的下载、安装、启动是三合一的,并且全过程完成时间在2-5秒之间,非常快。调了下面的代码,如果手机上已经有了流应用B,则启动之;如果没有,则安装并启动之。
如何在应用A里给流应用B导流?我们分3种情况。
- 应用A是5+ App,即本身是使用5+runtime打包的
- 应用A是流应用,即一个流应用给另一个流应用导流
- 应用A不是上面2种情况的普通App。
以下的示例代码里,同时判断了3种情况,先上代码
// 判断程序是否已安装
function isInstalled(pn){
var main = plus.android.runtimeMainActivity();
var pm = main.getPackageManager();
var PackageManager = plus.android.importClass(pm);
try{
var pi = pm.getPackageInfo(pn,PackageManager.GET_ACTIVITIES);
if(pi){
return true;
}
}catch(e){
}
return false;
}
function openStream(id){
if(navigator.userAgent.indexOf('Html5Plus')<0){//非5+环境
location.href='http://m3w.cn/s/'+id;
}else if(navigator.userAgent.indexOf('StreamApp')>=0){//流应用环境
plus.stream.open({appid:id});
}else{// 非流应用环境
if(isInstalled('io.dcloud.streamapps')){//安装了流应用
plus.runtime.openURL('streamapp://s/'+id,null,'io.dcloud.streamapps');
}else if(isInstalled('com.qihoo.appstore')){//安装了360手机助手
plus.runtime.openURL('streamapp://s/'+id,null,'com.qihoo.appstore');
}else{//未安装流应用环境
plus.runtime.openURL('http://www.dcloud.io/streamapp/');//调用系统浏览器打开流基座下载页面
}
}
}
在5+App里安装启动流应用
userAgent中如果包含Html5Plus字符串,则表示当前运行环境支持5+ API,否则表示当前运行环境不支持5+ API。
if(navigator.userAgent.indexOf('Html5Plus')<0){//非5+环境
满足此条件则表示运行环境不支持5+ API,此时可引导用户下载流应用运行环境。
在一个流应用中安装启动另一个流应用
userAgent中如果包含StreamApp字符串(navigator.userAgent.indexOf('StreamApp')>=0),则表示当前运行环境支持流应用,此时可通过plus.stream.open方法启动流应用。
非流应用环境
在非流应用运行环境中,我们可以通过url scheme来启动流应用,目前在“360手机助手”和“流应用”应用中已内置流应用引擎,可以通过5+ API(plus.runtime.openURL)方法来启动url scheme,其格式为:
streamapp://s/%APPID%
其中%APPID%为要启动的流应用APPID。
注意上面的示例代码是js的,实际在原生App中想调起流应用,需要写原生代码,原理也还是url schemes。
注:isInstalled方法使用native.js来判断当前设备上是否安装指定包名的应用。
启动流应用时如何传递参数
如果要调起同时传递参数,那么在调起url后面直接加问号参数。这个是启动大众点评外卖并进入某饭馆的url
:http://m3w.cn/s/H5BCD03E4?scene=share&arg=page%3Dshop%26id%3D2380186&__streamapp 。
这样的参数在启动后,可以通过plus.runtime这个api接收http://html5plus.org/doc/zh_cn/runtime.html#plus.runtime.arguments
这种机制,可以实现内容直达,尤其适合分享直通车等业务场景。
常见需调起的流应用的appid
手机京东 W2Am.sjjd.com
淘宝 W2Am.taobao.com
美团 W2Ameituan.com
卖座电影 H5A0B1958
e代驾 W2Aedaijia.cn
唯品会 H52588A9C
一号店 W2Am.yhd.com
去哪儿旅行 W2AH5E349CB7
携程酒店 H5B5EEFBB
途牛机票 W2AH56B3FED7
艺龙旅行网 W2Am.elong.com
趣趣游戏 H5E7A7BE6
传奇世界 H55269FFC
决战沙城 H54AA3D1F
如果你的app流量较大,希望变现,可以邮件stream@dcloud.io,我们与列表里的这些开发商都有商务推广分成协议。
比如在你的app中给手机京东流应用导流,产生的订单你就可以拿到提成。
传统的应用A导应用B,比如积分墙、换量广告、各种广告sdk....他们的导流效率是非常低的。
因为原生App的下载、安装、启动有很高的门槛,进一步导致广告的效果很差。
但如果应用B是一款流应用,就可以大幅降低折损,提升广告投放效果。
流应用的下载、安装、启动是三合一的,并且全过程完成时间在2-5秒之间,非常快。调了下面的代码,如果手机上已经有了流应用B,则启动之;如果没有,则安装并启动之。
如何在应用A里给流应用B导流?我们分3种情况。
- 应用A是5+ App,即本身是使用5+runtime打包的
- 应用A是流应用,即一个流应用给另一个流应用导流
- 应用A不是上面2种情况的普通App。
以下的示例代码里,同时判断了3种情况,先上代码
// 判断程序是否已安装
function isInstalled(pn){
var main = plus.android.runtimeMainActivity();
var pm = main.getPackageManager();
var PackageManager = plus.android.importClass(pm);
try{
var pi = pm.getPackageInfo(pn,PackageManager.GET_ACTIVITIES);
if(pi){
return true;
}
}catch(e){
}
return false;
}
function openStream(id){
if(navigator.userAgent.indexOf('Html5Plus')<0){//非5+环境
location.href='http://m3w.cn/s/'+id;
}else if(navigator.userAgent.indexOf('StreamApp')>=0){//流应用环境
plus.stream.open({appid:id});
}else{// 非流应用环境
if(isInstalled('io.dcloud.streamapps')){//安装了流应用
plus.runtime.openURL('streamapp://s/'+id,null,'io.dcloud.streamapps');
}else if(isInstalled('com.qihoo.appstore')){//安装了360手机助手
plus.runtime.openURL('streamapp://s/'+id,null,'com.qihoo.appstore');
}else{//未安装流应用环境
plus.runtime.openURL('http://www.dcloud.io/streamapp/');//调用系统浏览器打开流基座下载页面
}
}
}
在5+App里安装启动流应用
userAgent中如果包含Html5Plus字符串,则表示当前运行环境支持5+ API,否则表示当前运行环境不支持5+ API。
if(navigator.userAgent.indexOf('Html5Plus')<0){//非5+环境
满足此条件则表示运行环境不支持5+ API,此时可引导用户下载流应用运行环境。
在一个流应用中安装启动另一个流应用
userAgent中如果包含StreamApp字符串(navigator.userAgent.indexOf('StreamApp')>=0),则表示当前运行环境支持流应用,此时可通过plus.stream.open方法启动流应用。
非流应用环境
在非流应用运行环境中,我们可以通过url scheme来启动流应用,目前在“360手机助手”和“流应用”应用中已内置流应用引擎,可以通过5+ API(plus.runtime.openURL)方法来启动url scheme,其格式为:
streamapp://s/%APPID%
其中%APPID%为要启动的流应用APPID。
注意上面的示例代码是js的,实际在原生App中想调起流应用,需要写原生代码,原理也还是url schemes。
注:isInstalled方法使用native.js来判断当前设备上是否安装指定包名的应用。
启动流应用时如何传递参数
如果要调起同时传递参数,那么在调起url后面直接加问号参数。这个是启动大众点评外卖并进入某饭馆的url
:http://m3w.cn/s/H5BCD03E4?scene=share&arg=page%3Dshop%26id%3D2380186&__streamapp 。
这样的参数在启动后,可以通过plus.runtime这个api接收http://html5plus.org/doc/zh_cn/runtime.html#plus.runtime.arguments
这种机制,可以实现内容直达,尤其适合分享直通车等业务场景。
常见需调起的流应用的appid
手机京东 W2Am.sjjd.com
淘宝 W2Am.taobao.com
美团 W2Ameituan.com
卖座电影 H5A0B1958
e代驾 W2Aedaijia.cn
唯品会 H52588A9C
一号店 W2Am.yhd.com
去哪儿旅行 W2AH5E349CB7
携程酒店 H5B5EEFBB
途牛机票 W2AH56B3FED7
艺龙旅行网 W2Am.elong.com
趣趣游戏 H5E7A7BE6
传奇世界 H55269FFC
决战沙城 H54AA3D1F
如果你的app流量较大,希望变现,可以邮件stream@dcloud.io,我们与列表里的这些开发商都有商务推广分成协议。
比如在你的app中给手机京东流应用导流,产生的订单你就可以拿到提成。

5+sdk安卓widget集成示例
经过半个月的集成过程,终于集成好了一个示例,
本人看了几个帖子做的集成,分别是:
1、官方发布的集成方案:
http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/81
2、网友给的集成方案(相对比较实用):
http://ask.dcloud.net.cn/article/526?notification_id-76397__item_id-3005
在集成过程中,我遇到了几个问题,在社区里提问了,官方骁骑同学帮忙解答了,这里要感谢骁骑同学。
http://ask.dcloud.net.cn/question/19108
我做集成方案的目标主要有两点:
1、不希望每次打开webapp都重新初始化5 内核,能做到5 内核初始化一次后,每次都可以重用5 内核的实例,
这样既省去了内核初始化的过程,又加快了webapp加载的速度;这样做还有一个好处,就是可以集成多个webapp,同时共用一个5 内核实例。 我的示例代码里面只集成了一个webapp。
2、webapp页面打开方式能以动画形式从右侧推出,同时去掉闪屏。
基于这两个目标,我把官网的集成方案做了改动,同时官网骁骑同学帮忙写了5+ 内核初始化的方案,在此万分感谢骁骑!
示例代码github地址:https://github.com/hehelhx/widgetHtml5Plus
经过半个月的集成过程,终于集成好了一个示例,
本人看了几个帖子做的集成,分别是:
1、官方发布的集成方案:
http://ask.dcloud.net.cn/docs/#http://ask.dcloud.net.cn/article/81
2、网友给的集成方案(相对比较实用):
http://ask.dcloud.net.cn/article/526?notification_id-76397__item_id-3005
在集成过程中,我遇到了几个问题,在社区里提问了,官方骁骑同学帮忙解答了,这里要感谢骁骑同学。
http://ask.dcloud.net.cn/question/19108
我做集成方案的目标主要有两点:
1、不希望每次打开webapp都重新初始化5 内核,能做到5 内核初始化一次后,每次都可以重用5 内核的实例,
这样既省去了内核初始化的过程,又加快了webapp加载的速度;这样做还有一个好处,就是可以集成多个webapp,同时共用一个5 内核实例。 我的示例代码里面只集成了一个webapp。
2、webapp页面打开方式能以动画形式从右侧推出,同时去掉闪屏。
基于这两个目标,我把官网的集成方案做了改动,同时官网骁骑同学帮忙写了5+ 内核初始化的方案,在此万分感谢骁骑!
示例代码github地址:https://github.com/hehelhx/widgetHtml5Plus
收起阅读 »
plus.nativeObj.View解析
HBuilder7.2起,提供了plus.nativeObj.View,简称nview,http://html5plus.org/doc/zh_cn/nativeobj.html,它是一个灵活的底层组件,可以通过js控制样式的原生画布,写字、贴图、做动画,它不属于dom,可盖在webview和各种原生控件上面。
业内有些人认为HTML5渲染不敌原生渲染,确实在非预载的情况下HTML渲染慢于原生,那nview其实就是纯原生渲染了,nview的出现,补齐了HTML5的短板,满足了对体验有苛刻要求的开发者。
合理运用nview的应用,其加载速度已经毫无逊色于原生应用,这里有些视频对比http://ask.dcloud.net.cn/article/12576
nview可灵活运用于多种情况。
举例:
- 更高性能的窗体切换动画
我们知道div动画效果不好,webview的动画效果要好很多,但追求极致的话,nativeobj的动画是效果最好的。
从HBuilder8.8起,提供了subnview。加载一个webview时,可以把webview的界面部分原生化。这样动画期间,其实webview是不渲染不移动的,移动的是原生绘制的subnview。
subnview绘制极快,可以在100毫秒渲染,所以动画期间就能看到内容。而普通HTML文件渲染不预载的话是无法在100毫秒渲染的。 - 始终悬浮在webview上的圆球按钮
- 使用nativeObj.view来做title,不再使用父子双webview,节省更多内存资源,提升加载速度。此需求已经于HBuilder8.8起封装为webview的titleNView,可以在创建webview时配置一个参数,就可以生成一个nview的title,同时这个nview的title也可以继续使用nview的api进行文字图片的绘制。参考http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles
- 自定义原生控件
扫码、地图...很多HTML5+里提供的原生控件,之前是难以自定义界面的,需要使用github上的5+runtime代码自己改源码、本地打包新引擎。有了nview,可以自由的在这些原生控件上贴图、写字、增加按钮,实现界面的自定义。 - 全屏遮罩
子webview里的popover,弹出时无法全屏遮罩,其实我们可以不用popover的遮罩,直接用plus.nativeObj.View在popover四周贴蒙灰半透明图。 - webview选项卡上面多一个弧形
以前,下图样式通过5+的webview选项卡并不好实现,或者改用div选项卡,或者在中间的webview底部fix一个图。
现在你可以创建一个原生的view放到选项卡中间,然后把圆球图贴进去,这个view是可以跨越webview的边界限制的。具体参考这个文章http://ask.dcloud.net.cn/article/12602
plus.nativeObj.View还支持点击事件,还可以在图上继续贴图,应用场景非常多。
plus.nativeObj.View可以盖在webview上面,从HBuilder7.3起,view还支持内嵌于webview,可跟随webview一起动。
plus.nativeObj.View的引入极大的提升了5+app的性能和ui自定义性,对父子双webview的使用产生很大替代作用,但注意mui封装过的父子webview是可以兼容到非5+的普通浏览器里使用的,而native view则必须依赖5+环境。
HBuilder7.2起,提供了plus.nativeObj.View,简称nview,http://html5plus.org/doc/zh_cn/nativeobj.html,它是一个灵活的底层组件,可以通过js控制样式的原生画布,写字、贴图、做动画,它不属于dom,可盖在webview和各种原生控件上面。
业内有些人认为HTML5渲染不敌原生渲染,确实在非预载的情况下HTML渲染慢于原生,那nview其实就是纯原生渲染了,nview的出现,补齐了HTML5的短板,满足了对体验有苛刻要求的开发者。
合理运用nview的应用,其加载速度已经毫无逊色于原生应用,这里有些视频对比http://ask.dcloud.net.cn/article/12576
nview可灵活运用于多种情况。
举例:
- 更高性能的窗体切换动画
我们知道div动画效果不好,webview的动画效果要好很多,但追求极致的话,nativeobj的动画是效果最好的。
从HBuilder8.8起,提供了subnview。加载一个webview时,可以把webview的界面部分原生化。这样动画期间,其实webview是不渲染不移动的,移动的是原生绘制的subnview。
subnview绘制极快,可以在100毫秒渲染,所以动画期间就能看到内容。而普通HTML文件渲染不预载的话是无法在100毫秒渲染的。 - 始终悬浮在webview上的圆球按钮
- 使用nativeObj.view来做title,不再使用父子双webview,节省更多内存资源,提升加载速度。此需求已经于HBuilder8.8起封装为webview的titleNView,可以在创建webview时配置一个参数,就可以生成一个nview的title,同时这个nview的title也可以继续使用nview的api进行文字图片的绘制。参考http://www.html5plus.org/doc/zh_cn/webview.html#plus.webview.WebviewTitleNViewStyles
- 自定义原生控件
扫码、地图...很多HTML5+里提供的原生控件,之前是难以自定义界面的,需要使用github上的5+runtime代码自己改源码、本地打包新引擎。有了nview,可以自由的在这些原生控件上贴图、写字、增加按钮,实现界面的自定义。 - 全屏遮罩
子webview里的popover,弹出时无法全屏遮罩,其实我们可以不用popover的遮罩,直接用plus.nativeObj.View在popover四周贴蒙灰半透明图。 - webview选项卡上面多一个弧形
以前,下图样式通过5+的webview选项卡并不好实现,或者改用div选项卡,或者在中间的webview底部fix一个图。
现在你可以创建一个原生的view放到选项卡中间,然后把圆球图贴进去,这个view是可以跨越webview的边界限制的。具体参考这个文章http://ask.dcloud.net.cn/article/12602
plus.nativeObj.View还支持点击事件,还可以在图上继续贴图,应用场景非常多。
plus.nativeObj.View可以盖在webview上面,从HBuilder7.3起,view还支持内嵌于webview,可跟随webview一起动。
plus.nativeObj.View的引入极大的提升了5+app的性能和ui自定义性,对父子双webview的使用产生很大替代作用,但注意mui封装过的父子webview是可以兼容到非5+的普通浏览器里使用的,而native view则必须依赖5+环境。
收起阅读 »
上市公司子公司招聘高级移动APP研发(HTML5)
我们公司是由两家上市公司合资成立的子公司,项目前景很好,具有核心垄断资源,现需要招聘高级移动APP研发经理(HTML5),请注意,我们需要的是真正的高手,非诚勿扰,诚邀您的加盟!
**联系方式:** QQ 4258336(验证信息请注明:应聘H5)
**薪资:** 20K起
**工作地点:** 北京望京
**岗位职责:**
1、领导技术团队成员开发移动端APP;
2、负责移动端APP的构架设计及核心代码编写;
3、配合产品经理和UI设计师,研究并改善用户体验;
4、维护和优化现有系统。
**任职要求:**
1、最少3年以上移动端APP开发经验,必须有至少2款移动APP开发经验;
2、精通并使用符合W3C标准的Html5、JavaScript和CSS3等相关技术
3、熟悉HTTP协议以及JQuery、JSON、AJAX等前端WEB技术;
4、熟练使用Hbuilder开发工具,熟悉5+Runtime、Mui框架开发,熟悉其他Hybrid流行框架如:Cordova/PhoneGap、AppCan、jQuery Mobile等;
5、熟悉Android和iOS的知识,除了多线程,文件存储等基础知识,Android需要熟练的掌握WebView、WebSettings、WebChromeClient、WebClient四大对象。iOS需要熟练掌握UIWebView对象;
6、对响应式布局、动态交互特效、页面性能优化、浏览器兼容问题有一定经验,有微信相关开发经验者优先。
我们公司是由两家上市公司合资成立的子公司,项目前景很好,具有核心垄断资源,现需要招聘高级移动APP研发经理(HTML5),请注意,我们需要的是真正的高手,非诚勿扰,诚邀您的加盟!
**联系方式:** QQ 4258336(验证信息请注明:应聘H5)
**薪资:** 20K起
**工作地点:** 北京望京
**岗位职责:**
1、领导技术团队成员开发移动端APP;
2、负责移动端APP的构架设计及核心代码编写;
3、配合产品经理和UI设计师,研究并改善用户体验;
4、维护和优化现有系统。
**任职要求:**
1、最少3年以上移动端APP开发经验,必须有至少2款移动APP开发经验;
2、精通并使用符合W3C标准的Html5、JavaScript和CSS3等相关技术
3、熟悉HTTP协议以及JQuery、JSON、AJAX等前端WEB技术;
4、熟练使用Hbuilder开发工具,熟悉5+Runtime、Mui框架开发,熟悉其他Hybrid流行框架如:Cordova/PhoneGap、AppCan、jQuery Mobile等;
5、熟悉Android和iOS的知识,除了多线程,文件存储等基础知识,Android需要熟练的掌握WebView、WebSettings、WebChromeClient、WebClient四大对象。iOS需要熟练掌握UIWebView对象;
6、对响应式布局、动态交互特效、页面性能优化、浏览器兼容问题有一定经验,有微信相关开发经验者优先。
收起阅读 »

web封装,外部页面跳转,href按返回键 返回 后退问题的解决。
在封装一个简单的手机网站时,或者访问外部链接,按返回键失效
因在一个webview 中打开多个外部链接,h5+或本平台 返回键针对的是一个webview的释放回收。
解决办法:
外部页面或网站,引入mui.js 并 mui.init(); 初始化 ,则此页面 按返回键 有反应。也就是让外部页面也在mui平台下运行。
其测试,本部分代码 ,与浏览器请求页面不会报错,都可以正常访问。
有的页面没法引入 mui.js ,目前本人还没有发现好的解决办法。
在封装一个简单的手机网站时,或者访问外部链接,按返回键失效
因在一个webview 中打开多个外部链接,h5+或本平台 返回键针对的是一个webview的释放回收。
解决办法:
外部页面或网站,引入mui.js 并 mui.init(); 初始化 ,则此页面 按返回键 有反应。也就是让外部页面也在mui平台下运行。
其测试,本部分代码 ,与浏览器请求页面不会报错,都可以正常访问。
有的页面没法引入 mui.js ,目前本人还没有发现好的解决办法。
收起阅读 »
双指放大缩小问题(不需要第三方
看到很多去年甚至前年没有回答的双指放大缩小问题,自己折腾了半天实现了,感觉挺简单的,为什么没人回答呢,所以我把自己弄出来的写出来给大家瞅瞅。是原生的mui解决,不需要第三方
<meta name="viewport" content="user-scalable=yes,width=device-width,minimum-scale=1.0">
先写这个,重点是这句user-scalable=yes
引入mui.js之后
var wv =null;
mui.plusReady(function()
{
var wv=plus.webview.currentWebview();
wv.setStyle({'scalable':'true'});
});
在文件底下写js,直接把上面这段copy,有bug的话估计也是括号之类的问题,然后运行吧
基本上这样就能实现了
对大家的有帮助的话请务必给我回复鼓励,靴靴
看到很多去年甚至前年没有回答的双指放大缩小问题,自己折腾了半天实现了,感觉挺简单的,为什么没人回答呢,所以我把自己弄出来的写出来给大家瞅瞅。是原生的mui解决,不需要第三方
<meta name="viewport" content="user-scalable=yes,width=device-width,minimum-scale=1.0">
先写这个,重点是这句user-scalable=yes
引入mui.js之后
var wv =null;
mui.plusReady(function()
{
var wv=plus.webview.currentWebview();
wv.setStyle({'scalable':'true'});
});
在文件底下写js,直接把上面这段copy,有bug的话估计也是括号之类的问题,然后运行吧
基本上这样就能实现了
对大家的有帮助的话请务必给我回复鼓励,靴靴

mui初级入门教程(三)— html5+ XMLHttpRequest 与mui ajax用法详解
为了良好的阅读体验,推荐转到本人博客小青年博客或者segmentfault
文章来源:小青年原创
发布时间:2016-05-29
关键词:mui,html5+,XMLHttpRequest ,ajax,懒加载
转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20160529
写在前面
这是这个系列的的第三篇文章,前面的文章在多个地方(本人github博客、dcloud ask社区、segmentfault)发出来了,很多朋友收藏点赞,只是没有多少人反映内容的深浅,也没有人提出意见,所以实话说不知道符不符合大家胃口,不过我写博客一向以详细为标准,尽可能照顾到各种人群,特别是入门级的同学,力求还原我学习这个东西的一个思路和过程,在文章中也分享一些不错的干货,最近在折腾博客,用webpack和vue-cli打包了一下,目前还有些问题有待解决,自己尝试写一个markdown编辑器因为bug过多的问题,然后开始使用马克飞象写博客,毕竟生成的界面美观多了,这样可以方便大家阅读吧。废话不多说,开始我们今天的内容,今天主要是学习一下html5+的XMLHttpRequest以及mui的基本用法。
基础铺垫
Javascript XMLHttpRequest网络请求
XMLHttpRequest 是一个 JavaScript 对象,它最初由微软设计,随后被 Mozilla、Apple 和 Google采纳. 如今,该对象已经被 W3C组织标准化. 通过它,你可以很容易的取回一个URL上的资源数据. 尽管名字里有XML, 但 XMLHttpRequest 可以取回所有类型的数据资源,并不局限于XML。 而且除了HTTP ,它还支持file 和 ftp 协议. —— MDN XMLHttpRequest
XMLHttpRequest
让发送一个HTTP
请求变得非常容易。你只需要简单的创建一个请求对象实例,打开一个URL
,然后发送这个请求。当传输完毕后,结果的HTTP
状态以及返回的响应内容也可以从请求对象中获取。
XMLHttpRequest网络请求的一般步骤:
第一步:创建一个 XMLHttpRequest 实例
new XMLHttpRequest();
第二步:初始化HTTP请求参数
void open(
DOMString method,
DOMString url,
optional boolean async,
optional DOMString user,
optional DOMString password
);
- method:请求所使用的HTTP方法; 例如 "GET", "POST", "PUT", "DELETE"等. 如果下个参数是非HTTP(S)的URL,则忽略该参数.
- url:该请求所要访问的URL
- async:一个可选的布尔值参数,默认为true,意味着是否执行异步操作,如果值为false,则send()方法不会返回任何东西,直到接受到了服务器的返回数据。如果为值为true,一个对开发者透明的通知会发送到相关的事件监听者。这个值必须是
true
,如果multipart
属性是true,否则将会出现一个意外。 - user:用户名,可选参数,为授权使用;默认参数为空string.
- password:密码,可选参数,为授权使用;默认参数为空string.
第三步:发送请求
send();
发送请求. 如果该请求是异步模式(默认),该方法会立刻返回. 相反,如果请求是同步模式,则直到请求的响应完全接受以后,该方法才会返回.
如下例:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
console.log(this.responseText);
};
xhr.onreadystatechange = function() {
console.log(this.readyState);
};
xhr.open("get", "https://www.baidu.com", true);
xhr.send();
我们在hbuilder里面打开,控制台会报错:
[Web浏览器] "XMLHttpRequest cannot load https://www.baidu.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access."
用浏览器打开,按F12在控制台console下查看也会发现上述错误,这是为啥呢?
这是因为普通网页能够使用XMLHttpRequest对象发送或者接受服务器数据, 但是它们受限于同源策略。只要先获取了跨域请求许可,就可以进行跨域请求。
同源策略:如果两个页面的协议、域名和端口是完全相同的,那么它们就是同源的。同源策略是为了防止从一个地址加载的文档或脚本访问或者设置从另外一个地址加载的文档的属性。如果两个页面的主域名相同,则还可以通过设置
document.domain
属性将它们认为是同源的。
跨域请求的几种常用方法:
第一种:CORS,使用XMLHttpRequest对象
CORS 的全称是 Cross-Origin Resource Sharing,即跨域资源共享。他的原理就是使用自定义的 HTTP 头部,让服务器与浏览器进行沟通,主要是通过设置响应头的 Access-Control-Allow-Origin 来达到目的的。这样,XMLHttpRequest 就能跨域了。
在服务器端添加响应头Access-Control-Allow-Origin,使用XMLHttpRequest对象请求。值得注意的是,正常情况下的 XMLHttpRequest 是只发送一次请求的,但是跨域问题下很可能是会发送两次的请求(预发送)。
PHP:
header('Access-Control-Allow-Origin: *');
java:
response.addHeader( "Access-Control-Allow-Origin", "*" );
第二种:Jsonp,只适用于get请求
Jsonp的跨域不是用XMLHttpRequest实现的,而是一个script标签,script是可以跨域的,回调函数作为get参数传入请求里。
原理很简单,比如你在A域名请求B域名:
- 在A域名的页面中使用script标签src写成B域名中服务器的URL
script标签是可以跨域的,比如你调用Google Map或Google Analytics时引入的js就是google域名下的。 - 后端程序在最后需要把一段js代码的字符串print出来,这样就可以运行A域名js中写好的callback方法,将要返回的数据放入参数就可以了
A域名中的js文件:
<script type="text/javascript" src="http://www.b.com/action?callback=myCallback"></script>
<script type="text/javascript">
function myCallback (data) {
alert(data);
}
</script>
B域名中服务器
String cb = get('callback');
Int b = '我是数据';
print('<script type="text/javascript"> ' + cb + '(' + b + '); </script>');
后端print数据到页面中后就会这样
<script type="text/javascript">
myCallback('我是数据');
</script>
注:引用自segmentfault 的tychio的回答。
总之,不论是XMLHttpRequest的跨域,还是Jsonp,都是需要请求的网站服务器端提供支持,在愿意分享给你数据的情况下你才能得到。在对方没有提供支持的情况下,你是取不到它的数据的。当然跨域的解决方案有很多种,由于本人没有实践过,没有实践就没有发言权,这里给大家贴一个帖子,自己跨域自行验证,浅谈浏览器端JavaScript跨域解决方法。
html5+ XMLHttpRequest网络请求
上面我们花了很大篇幅讲解了JavaScript XMLHttpRequest对象,而且也简单的讲解了同源策略和跨域请求的常用方法,我们注意到无论是JavaScript XMLHttpRequest还是jsonp都需要通过服务器端的支持才能实现跨域,另外还有几种也有一定的局限性,所以总还是让人觉得美中不足。html5+提供了一个XMLHttpRequest模块,在APP端很完美的解决了这种问题,而且提供了和JavaScript XMLHttpRequest对象用法类似的一系列属性方法。由于本文的重在在于讲解html5+ XMLHttpRequest,所以前面的JavaScript XMLHttpRequest相关的属性方法只是初略介绍了一下,下面重点介绍html5+ XMLHttpRequest模块。
适用范围:
由于html5+ XMLHttpRequest是一种拓展方案,所以需要底层支持,基于html5+ XMLHttpRequest的方法不能用于非5+环境,如果对这些概念不清楚的欢迎先阅读我之前写的文章mui初级入门教程(一)— 菜鸟入手mui的学习路线。
我们用hbuilder新建一个app工程,然后运行下面的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title></title>
</head>
<body>
<script type="text/javascript">
document.addEventListener('plusready', function(){
var xhr = new plus.net.XMLHttpRequest();
xhr.onreadystatechange = function () {
switch ( xhr.readyState ) {
case 0:
console.log( "xhr请求已初始化" );
break;
case 1:
console.log( "xhr请求已打开" );
break;
case 2:
console.log( "xhr请求已发送" );
break;
case 3:
console.log( "xhr请求已响应");
break;
case 4:
if ( xhr.status == 200 ) {
alert( "xhr请求成功:"+xhr.responseText );
} else {
console.log( "xhr请求失败:"+xhr.readyState );
}
break;
default :
break;
}
}
xhr.open("GET", "https://www.baidu.com/");
xhr.send();
}, false );
</script>
</body>
</html>
我们会发现最后弹出了弹框,里面写有百度首页的代码。
XMLHttpRequest对象:
创建一个XMLHttpRequest 对象,对象创建时不触发任何时间和网络请求,需和open,send方法配合使用。
var xhr = new plus.net.XMLHttpRequest();
xhr.open(method, url);
xhr.send();
XMLHttpRequest的属性:
- readyState: HTTP 请求的状态
- response: 请求从服务器接收到的响应数据
- responseText: 请求从服务器接收到的响应数据(字符串数据)
- responseType:请求响应数据response的类型
- responseXML: 请求响应的Document对象
- status: 服务器返回的HTTP状态代码
- statusText: 服务器返回的HTTP状态描述
- timeout: 请求服务器的超时时间,单位为毫秒(ms)
- withCredentials: 是否支持跨域请求
XMLHttpRequest的方法:
- abort: 取消当前响应,关闭连接并且结束任何未决的网络活动
- getAllResponseHeaders: 获取HTTP响应头部信息
- getResponseHeader: 获取指定的HTTP响应头部的值
- open: 初始化HTTP请求参数,例如URL和HTTP方法,但是并不发送请求
- send: 发送HTTP请求
- setRequestHeader: 指定一个HTTP请求的Header
XMLHttpRequest的事件:
- onreadystatechange: 网络请求状态发生变化事件
- onloadstart: 网络请求开始事件
- onprogress: 网络请求传输数据事件
- onabort: 网络请求取消事件
- onerror: 网络请求错误事件
- onload: 网络请求成功事件
- ontimeout: 网络请求超时事件
- onloadend: 网络请求结束事件
mui ajax
mui框架基于htm5plus的XMLHttpRequest,封装了常用的Ajax函数,支持GET、POST请求方式,支持返回json、xml、html、text、script数据类型; 本着极简的设计原则,mui提供了mui.ajax方法,并在mui.ajax方法基础上,进一步简化出最常用的mui.get()、mui.getJSON()、mui.post()三个方法。
mui.ajax( url [,settings] )
- url:请求发送的目标地址
- settings:key/value格式的json对象,用来配置ajax请求参数,支持的参数如下:
- data:发送到服务器的业务数据;
- type:请求方式,目前仅支持'GET'和'POST',默认为'GET'方式;
- dataType:预期服务器返回的数据类型;如果不指定,mui将自动根据HTTP包的MIME头信息自动判断;
支持设置的dataType可选值:- "xml": 返回XML文档
- "html": 返回纯文本HTML信息;
- "script": 返回纯文本JavaScript代码
- "json": 返回JSON数据
- "text": 返回纯文本字符串
- success:Type: Functon(Anything data,String textStatus,XMLHttpRequest xhr)
请求成功时触发的回调函数,该函数接收三个参数:- data:服务器返回的响应数据,类型可以是json对象、xml对象、字符串等;
- textStatus:状态描述,默认值为'success'
- xhr:xhr实例对象
- error:Type: Functon(XMLHttpRequest xhr,String type,String errorThrown)请求失败时触发的回调函数;
该函数接收三个参数:- xhr:xhr实例对象
- type:错误描述,可取值:"timeout", "error", "abort", "parsererror"、"null"
- errorThrown:可捕获的异常对象
- timeout:Type: Number,请求超时时间(毫秒),默认值为0,表示永不超时;若超过设置的超时时间(非0的情况),依然未收到服务器响应,则触发error回调;
- headers:Type: Object,格式为:{'Content-Type':'application/json'},
详情参考html5+ setRequestHeader。
基本格式如下:
mui.ajax(url,{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
mui.post( url [,data] [,success] [,dataType] )
mui.post()方法是对mui.ajax()的一个简化方法,直接使用POST请求方式向服务器发送数据、且不处理timeout和异常(若需处理异常及超时,请使用mui.ajax()方法)
mui.post('http://server-name/login.php',{
username:'username',
password:'password'
},function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},'json'
);
mui.get( url [,data] [,success] [,dataType] )
mui.get()方法和mui.post()方法类似,只不过是直接使用GET请求方式向服务器发送数据、且不处理timeout和异常(若需处理异常及超时,请使用mui.ajax()方法)。如下为获得某服务器新闻列表的代码片段,服务器以json格式返回数据列表:
mui.get('http://server-name/list.php',
{category:'news'},
function(data){
//获得服务器响应
...
},'json'
);
mui.get( url [,data] [,success] )
mui.getJSON()方法是在mui.get()方法基础上的更进一步简化,限定返回json格式的数据,其它参数和mui.get()方法一致,如上获得新闻列表的代码换成mui.getJSON()方法后,更为简洁,如下:
mui.getJSON('http://server-name/list.php',
{category:'news'},
function(data){
//获得服务器响应
...
}
);
注:初学者肯对于GET与POST的区别不是很清楚,这里不做详细介绍,若要深入了解请查看:GET,POST — 简述
项目实战
我们接着上一篇文章的项目开始进行本节的内容,上一篇我们讲解了html5+ webview的使用方法,并且实现了一个基于父子webview的tab bar切换的案例,我们这次利用网易音乐API接口请求数据,完成我们后续的音乐播放器功能。
API分析
网易音乐搜索API:
- url:http://s.music.163.com/search/get/
- type:"GET"或“POST" //HTTP请求类型
- 请求参数:
- type: 1
- s: //关键词
- limit: 10 //限制返回结果数为10
- offset: 0 //偏移
- src: lofter //可为空
- filterDj: true | false //可为空
- callback: //为空时返回json,反之返回jsonp callback
由于HTTP请求类型包含get,我们只需要把请求的参数拼接到url里面就可以得到返回的数据,格式为url?key1=value1&key2=value2。
在这个例子中我们打开这个网址http://s.music.163.com/search/get/?type=1&limit=5&s=喜欢你,我们会发现一些数据返回了,如下图:
OK,我们下面讲解怎么通过程序得到这些数据,并且我们并且怎么解析这些数据。
在开始之前我们先对我们要得到的数据进行美化,这里我在网上随便搜了一个
在线JSON校验格式化工具,我们只需要把刚刚那些数据复制粘贴到我给的这个工具里面,然后点击校验就变整齐了。
{
"result": {
"songCount": 3224,
"songs": [
{
"id": 28949444,
"name": "喜欢你",
"artists": [
{
"id": 7763,
"name": "G.E.M.邓紫棋",
"picUrl": null
}
],
"album": {
"id": 2956076,
"name": "喜欢你",
"artist": {
"id": 0,
"name": "",
"picUrl": null
},
"picUrl": "http://p1.music.126.net/u_1EudmF8Swgow6vfgYe1g==/8896148580676276.jpg"
},
"audio": "http://m2.music.126.net/_icR1apQHVl8wa0EP_REkQ==/3269947581061892.mp3",
"djProgramId": 0
}
]
},
"code": 200
}
我们可以看到
"picUrl":"http://p1.music.126.net/u_1EudmF8Swgow6vfgYe1g==/8896148580676276.jpg"
打开这个图片地址我们就可以看到邓紫棋了,哈哈,也就是说我们只需要抓取到这个地址就可以进行下面的工作咯,其他的类似。
mui.ajax请求实例
我们在上次新建的M-BOX下的home.html下写这个例子:
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
var url = "http://s.music.163.com/search/get/";
mui.ajax(url,{
data: {
'type': 1,
's': "喜欢你",
'limit': 10
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
console.log(JSON.stringify(data));
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
</script>
hbuilder
很方便的一个功能就是真机调试,我们直接将电脑与手机连接,通过console.log()
函数可以很方便的将数据在控制台打印出来,例如上述例子如果我们在success
的回调函数中执行console.log(data);
,在控制台会输出[object Object]
,我们只需要利用JSON.stringify()
方法可以将任意的JavaScript
值序列化成 JSON
字符串。
Javascript语法基础
每次看到很多同学在解析json
的时候错误百出,严重暴漏了基本功,这里我就总结几条与解析json
可能相关的知识点。
什么是JSON?
JSON:JavaScript Object Notation
(JavaScript 对象表示法),JSON
是存储和交换文本信息的语法,独立于语言。类似 XML
。JSON
比 XML
更小、更快,更易解析,具有自我描述性,更易理解的特点。
JSON
就是一串字符串,只不过元素会使用特定的符号标注。
- {} 双括号表示对象
- [] 中括号表示数组
- "" 双引号内是属性或值
- :表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
{"name": "Dcloud"}
可以理解为是一个包含name
为Dcloud
的对象;
[{"name": "mui"},{"name": "html5+"}]
就表示包含两个对象的数组。
通过JavaScript
,您可以创建一个对象数组,并像这样进行赋值:
var employees = [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName": "Jones" }
];
可以像这样访问 JavaScript 对象数组中的第一项:
employees[0].lastName;
返回的内容是:
Doe
可以像这样修改数据:
employees[0].firstName = "Jonatan";
运算符[ ] 和 .
[ ]可以用于数组和对象取值,数组中按下边取值。
var array=["one","two","three","four"];
array[0];
对象属性取值时,当我们不知道属性名或属性名本身包含点(.)的键,应当使用[ ]。
for(var key in obj){
console.log(key + ":" + obj[key]);
}
var obj={
id:"obj",
"self.ref":ref
}
console.log(obj["self.ref"]);
.运算符的左边为一个对象,右边为属性名。如:obj.id
可以动态访问属性:
var key="property";
console.log(key);
var obj={
property:"hello word"
}
console.log(obj[key]);
数组的map方法:
var array=[1,2,3,4,5];
array.map(function(item){
return item*2;
});
数组map
方法可以接受一个匿名函数,数组中每个元素都会调用这个匿名函数,并且讲返回结果放在一个数组中。
获取数据更新UI
mui
中的each()
方法既是一个类方法,同时也是一个对象方法,两个方法适用场景不同;换言之,你可以使用mui.each()
去遍历数组或json
对象,也可以使用mui(selector).each()
去遍历DOM
结构。
mui.each( obj , handler )
- obj :
Type: Array||JSONObj
需遍历的对象或数组;若为对象,仅遍历对象根节点下的key - handler :
Type: Function( Integer||String index,Anything element)
为每个元素执行的回调函数;其中,index表示当前元素的下标或key,element表示当前匹配元素
对于前面说到的音乐api
返回的json
数据,首先我们要通过var songs=data.result.songs;
获取"songs"
的值,然后遍历"songs"
对象的子对象。
···
success:function(data){
// console.log(JSON.stringify(data));
var songs=data.result.songs;
mui.each(songs,function(index,item){
var id = item.id,
name = item.album.name,
author = item.artists[0].name,
picUrl = item.album.picUrl,
audio = item.audio;
})
},
···
我们用上述代码可以得到我们想要的数据,下面就是需要将信息展示出来,这里我们只获取 歌曲id
、歌曲所属专辑名name
、歌曲第一作者author
、歌曲所属专辑图片picUrl
、歌曲音频文件audio
。
考虑到要加载很多图片,这里我们使用懒加载实现效果,这里我们直接使用hello mui
里面的模板页面lazyload-image.html
,我们需要引入mui.lazyload.js
和mui.lazyload.img.js
两个文件,还有占位图。下面先贴出修改后的基本的代码,然后再讲解其中的内容。
home.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>M-BOX</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!--标准mui.css-->
<link rel="stylesheet" href="../css/mui.min.css">
<style type="text/css">
.mui-content>.mui-table-view:first-child {
margin-top: 0px;
}
</style>
</head>
<body>
<div class="mui-content">
<ul id="list" class="mui-table-view mui-table-view-chevron"></ul>
</div>
</body>
<script src="../js/mui.min.js "></script>
<script src="../js/mui.lazyload.js"></script>
<script src="../js/mui.lazyload.img.js"></script>
<script>
mui.init();
var url = "http://s.music.163.com/search/get/";
mui.ajax(url,{
data: {
'type': 1,
's': "喜欢你",
'limit': 10
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//console.log(JSON.stringify(data));
var songs=data.result.songs;
var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
var li;
mui.each(songs,function(index,item){
var id = item.id,
name = item.album.name,
author = item.artists[0].name,
picUrl = item.album.picUrl,
audio = item.audio;
li = document.createElement('li');
li.className = 'mui-table-view-cell mui-media';
li.innerHTML = '<a class="mui-navigate-right" id='+ id +' data-audio='+ audio +'>'+
'<img class="mui-media-object mui-pull-left" data-lazyload="'+picUrl+'">'+
'<div class="mui-media-body">'+name+
'<p class="mui-ellipsis">'+author+'</p>'+
'</div>'+
'</a>';
fragment.appendChild(li);
})
list.appendChild(fragment)
mui(document).imageLazyload({
placeholder: '../img/60x60.gif'
});
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
//列表点击事件
mui("#list").on('tap','li a',function(){
var id = this.getAttribute('id');
var audio = this.getAttribute('data-audio');
//打开详情页面
mui.openWindow({
url:'music.html',
id:'music.html',
extras:{
musicId:id,
audioUrl:audio
}
});
});
</script>
</html>
music.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<link href="../css/mui.min.css" rel="stylesheet"/>
</head>
<body>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function(){
var self = plus.webview.currentWebview();
var musicId = self.musicId;
var audioUrl = self.audioUrl;
document.write("musicId:" + musicId + "<br />");
document.write("audioUrl:" + audioUrl);
});
</script>
</body>
</html>
我们这里说几个开发者常见的问题:
拼接html字符串
首先打开hello mui
里面的模板页面lazyload-image.html
,我们打开控制台查看elements
,结构如下:
<ul id="list" class="mui-table-view mui-table-view-chevron">
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right">
<img class="mui-media-object mui-pull-left" data-lazyload-id="0" src="http://www.dcloud.io/hellomui/images/1.jpg?version=447.4190210457891">
<div class="mui-media-body">
主标题
<p class="mui-ellipsis">列表二级标题</p>
</div>
</a>
</li>
</ul>
我们需要将获取的内容动态的填充到这个里面,这里常用的方法就是动态的生成节点,这里我们就要用到DOM
的创建方法document.createElement
,通过这个方法我们可以生成一个节点:
li = document.createElement('li');
这个可以生成一个li
节点,我们需要为这个li
指定class
,通过对对象的className
赋值实现,如:li.className = 'mui-table-view-cell mui-media';
,我们使用appendChild(li)
方法将li
节点挂着父节点上,比如:
var list = document.getElementById("list");
list.appendChild(li);
这个就是把li
节点挂在list
下,同理我们可以在li
节点下 创建子节点,上面为了简单,我们使用给innerHTML
属性赋值的做法,这样innerHTML
的值同样会挂在li
节点下,大家需要注意的是innerHTML
属性的值我字符串,所以我们往中间插入了变量,要使用+
连接起来。我们可以通过循环创建多个节点,如下面这样创建十个段落:
for(var i = 0 ; i < 10; i ++) {
var p = document.createElement("p");
var oTxt = document.createTextNode("段落" + i);
p.appendChild(oTxt);
document.body.appendChild(p);
}
上面我们使用的是mui.each()
方法,效果类似。
如果细心的同学或许注意到我们使用了一个奇怪的写法:
var fragment = document.createDocumentFragment();
mui.each(songs,function(index,item){
...
fragment.appendChild(li);
});
list.appendChild(fragment);
为啥我们要在这里使用fragment
呢?
如果是对前端技术感兴趣的同学说不定回去查一下,我相信大部分人可能就放过了吧!这里我查了一下资料:
在《javascript高级程序设计》一书的6.3.5:创建和操作节点一节中,介绍了几种动态创建html节点的方法,其中有以下几种常见方法:
- crateAttribute(name): 用指定名称name创建特性节点
- createComment(text): 创建带文本text的注释节点
- createDocumentFragment(): 创建文档碎片节点
- createElement(tagname): 创建标签名为tagname的节点
- createTextNode(text): 创建包含文本text的文本节点
其中最感兴趣且以前没有接触过的一个方法是createComment(text)方法,书中介绍说:在更新少量节点的时候可以直接向document.body节点中添加,但是当要向document中添加大量数据是,如果直接添加这些新节点,这个过程非常缓慢,因为每添加一个节点都会调用父节点的appendChild()方法,为了解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片一次性添加到document中。—— document的createDocumentFragment()方法
页面传值
我们点击了列表,我们会进入一个详情页,我们肯定是想知道我们究竟点了哪一个我们想把一些数据传入到详情页面,这里我们使用了mui.openWindow()
方法中的拓展参数extras
传入几个值,在详情页面通过plus.webview.currentWebview
获取:
mui.plusReady(function(){
var self = plus.webview.currentWebview();
var musicId = self.musicId;
var audioUrl = self.audioUrl;
document.write("musicId:" + musicId + "<br />");
document.write("audioUrl:" + audioUrl);
});
这是在页面初始化时,通过扩展参数extras
传值;另外还有页面已创建,通过自定义事件传值,参考mui官网中自定义事件的介绍,这里先不讲得太多,后面会专门花时间详细讲解相关细节。
当我们写到这里,发现这篇依然是长长的一篇干货,很多内容摘自文档,主要是为了新手可以详细去了解整个流程。其实还有很多没有写出来,限于篇幅还是后面再写吧!由于代码在文章中写得很详细,工程代码先不给出来,最后整个系列写完了再放出来吧!
为了良好的阅读体验,推荐转到本人博客小青年博客或者segmentfault
文章来源:小青年原创
发布时间:2016-05-29
关键词:mui,html5+,XMLHttpRequest ,ajax,懒加载
转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20160529
写在前面
这是这个系列的的第三篇文章,前面的文章在多个地方(本人github博客、dcloud ask社区、segmentfault)发出来了,很多朋友收藏点赞,只是没有多少人反映内容的深浅,也没有人提出意见,所以实话说不知道符不符合大家胃口,不过我写博客一向以详细为标准,尽可能照顾到各种人群,特别是入门级的同学,力求还原我学习这个东西的一个思路和过程,在文章中也分享一些不错的干货,最近在折腾博客,用webpack和vue-cli打包了一下,目前还有些问题有待解决,自己尝试写一个markdown编辑器因为bug过多的问题,然后开始使用马克飞象写博客,毕竟生成的界面美观多了,这样可以方便大家阅读吧。废话不多说,开始我们今天的内容,今天主要是学习一下html5+的XMLHttpRequest以及mui的基本用法。
基础铺垫
Javascript XMLHttpRequest网络请求
XMLHttpRequest 是一个 JavaScript 对象,它最初由微软设计,随后被 Mozilla、Apple 和 Google采纳. 如今,该对象已经被 W3C组织标准化. 通过它,你可以很容易的取回一个URL上的资源数据. 尽管名字里有XML, 但 XMLHttpRequest 可以取回所有类型的数据资源,并不局限于XML。 而且除了HTTP ,它还支持file 和 ftp 协议. —— MDN XMLHttpRequest
XMLHttpRequest
让发送一个HTTP
请求变得非常容易。你只需要简单的创建一个请求对象实例,打开一个URL
,然后发送这个请求。当传输完毕后,结果的HTTP
状态以及返回的响应内容也可以从请求对象中获取。
XMLHttpRequest网络请求的一般步骤:
第一步:创建一个 XMLHttpRequest 实例
new XMLHttpRequest();
第二步:初始化HTTP请求参数
void open(
DOMString method,
DOMString url,
optional boolean async,
optional DOMString user,
optional DOMString password
);
- method:请求所使用的HTTP方法; 例如 "GET", "POST", "PUT", "DELETE"等. 如果下个参数是非HTTP(S)的URL,则忽略该参数.
- url:该请求所要访问的URL
- async:一个可选的布尔值参数,默认为true,意味着是否执行异步操作,如果值为false,则send()方法不会返回任何东西,直到接受到了服务器的返回数据。如果为值为true,一个对开发者透明的通知会发送到相关的事件监听者。这个值必须是
true
,如果multipart
属性是true,否则将会出现一个意外。 - user:用户名,可选参数,为授权使用;默认参数为空string.
- password:密码,可选参数,为授权使用;默认参数为空string.
第三步:发送请求
send();
发送请求. 如果该请求是异步模式(默认),该方法会立刻返回. 相反,如果请求是同步模式,则直到请求的响应完全接受以后,该方法才会返回.
如下例:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
console.log(this.responseText);
};
xhr.onreadystatechange = function() {
console.log(this.readyState);
};
xhr.open("get", "https://www.baidu.com", true);
xhr.send();
我们在hbuilder里面打开,控制台会报错:
[Web浏览器] "XMLHttpRequest cannot load https://www.baidu.com/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access."
用浏览器打开,按F12在控制台console下查看也会发现上述错误,这是为啥呢?
这是因为普通网页能够使用XMLHttpRequest对象发送或者接受服务器数据, 但是它们受限于同源策略。只要先获取了跨域请求许可,就可以进行跨域请求。
同源策略:如果两个页面的协议、域名和端口是完全相同的,那么它们就是同源的。同源策略是为了防止从一个地址加载的文档或脚本访问或者设置从另外一个地址加载的文档的属性。如果两个页面的主域名相同,则还可以通过设置
document.domain
属性将它们认为是同源的。
跨域请求的几种常用方法:
第一种:CORS,使用XMLHttpRequest对象
CORS 的全称是 Cross-Origin Resource Sharing,即跨域资源共享。他的原理就是使用自定义的 HTTP 头部,让服务器与浏览器进行沟通,主要是通过设置响应头的 Access-Control-Allow-Origin 来达到目的的。这样,XMLHttpRequest 就能跨域了。
在服务器端添加响应头Access-Control-Allow-Origin,使用XMLHttpRequest对象请求。值得注意的是,正常情况下的 XMLHttpRequest 是只发送一次请求的,但是跨域问题下很可能是会发送两次的请求(预发送)。
PHP:
header('Access-Control-Allow-Origin: *');
java:
response.addHeader( "Access-Control-Allow-Origin", "*" );
第二种:Jsonp,只适用于get请求
Jsonp的跨域不是用XMLHttpRequest实现的,而是一个script标签,script是可以跨域的,回调函数作为get参数传入请求里。
原理很简单,比如你在A域名请求B域名:
- 在A域名的页面中使用script标签src写成B域名中服务器的URL
script标签是可以跨域的,比如你调用Google Map或Google Analytics时引入的js就是google域名下的。 - 后端程序在最后需要把一段js代码的字符串print出来,这样就可以运行A域名js中写好的callback方法,将要返回的数据放入参数就可以了
A域名中的js文件:
<script type="text/javascript" src="http://www.b.com/action?callback=myCallback"></script>
<script type="text/javascript">
function myCallback (data) {
alert(data);
}
</script>
B域名中服务器
String cb = get('callback');
Int b = '我是数据';
print('<script type="text/javascript"> ' + cb + '(' + b + '); </script>');
后端print数据到页面中后就会这样
<script type="text/javascript">
myCallback('我是数据');
</script>
注:引用自segmentfault 的tychio的回答。
总之,不论是XMLHttpRequest的跨域,还是Jsonp,都是需要请求的网站服务器端提供支持,在愿意分享给你数据的情况下你才能得到。在对方没有提供支持的情况下,你是取不到它的数据的。当然跨域的解决方案有很多种,由于本人没有实践过,没有实践就没有发言权,这里给大家贴一个帖子,自己跨域自行验证,浅谈浏览器端JavaScript跨域解决方法。
html5+ XMLHttpRequest网络请求
上面我们花了很大篇幅讲解了JavaScript XMLHttpRequest对象,而且也简单的讲解了同源策略和跨域请求的常用方法,我们注意到无论是JavaScript XMLHttpRequest还是jsonp都需要通过服务器端的支持才能实现跨域,另外还有几种也有一定的局限性,所以总还是让人觉得美中不足。html5+提供了一个XMLHttpRequest模块,在APP端很完美的解决了这种问题,而且提供了和JavaScript XMLHttpRequest对象用法类似的一系列属性方法。由于本文的重在在于讲解html5+ XMLHttpRequest,所以前面的JavaScript XMLHttpRequest相关的属性方法只是初略介绍了一下,下面重点介绍html5+ XMLHttpRequest模块。
适用范围:
由于html5+ XMLHttpRequest是一种拓展方案,所以需要底层支持,基于html5+ XMLHttpRequest的方法不能用于非5+环境,如果对这些概念不清楚的欢迎先阅读我之前写的文章mui初级入门教程(一)— 菜鸟入手mui的学习路线。
我们用hbuilder新建一个app工程,然后运行下面的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title></title>
</head>
<body>
<script type="text/javascript">
document.addEventListener('plusready', function(){
var xhr = new plus.net.XMLHttpRequest();
xhr.onreadystatechange = function () {
switch ( xhr.readyState ) {
case 0:
console.log( "xhr请求已初始化" );
break;
case 1:
console.log( "xhr请求已打开" );
break;
case 2:
console.log( "xhr请求已发送" );
break;
case 3:
console.log( "xhr请求已响应");
break;
case 4:
if ( xhr.status == 200 ) {
alert( "xhr请求成功:"+xhr.responseText );
} else {
console.log( "xhr请求失败:"+xhr.readyState );
}
break;
default :
break;
}
}
xhr.open("GET", "https://www.baidu.com/");
xhr.send();
}, false );
</script>
</body>
</html>
我们会发现最后弹出了弹框,里面写有百度首页的代码。
XMLHttpRequest对象:
创建一个XMLHttpRequest 对象,对象创建时不触发任何时间和网络请求,需和open,send方法配合使用。
var xhr = new plus.net.XMLHttpRequest();
xhr.open(method, url);
xhr.send();
XMLHttpRequest的属性:
- readyState: HTTP 请求的状态
- response: 请求从服务器接收到的响应数据
- responseText: 请求从服务器接收到的响应数据(字符串数据)
- responseType:请求响应数据response的类型
- responseXML: 请求响应的Document对象
- status: 服务器返回的HTTP状态代码
- statusText: 服务器返回的HTTP状态描述
- timeout: 请求服务器的超时时间,单位为毫秒(ms)
- withCredentials: 是否支持跨域请求
XMLHttpRequest的方法:
- abort: 取消当前响应,关闭连接并且结束任何未决的网络活动
- getAllResponseHeaders: 获取HTTP响应头部信息
- getResponseHeader: 获取指定的HTTP响应头部的值
- open: 初始化HTTP请求参数,例如URL和HTTP方法,但是并不发送请求
- send: 发送HTTP请求
- setRequestHeader: 指定一个HTTP请求的Header
XMLHttpRequest的事件:
- onreadystatechange: 网络请求状态发生变化事件
- onloadstart: 网络请求开始事件
- onprogress: 网络请求传输数据事件
- onabort: 网络请求取消事件
- onerror: 网络请求错误事件
- onload: 网络请求成功事件
- ontimeout: 网络请求超时事件
- onloadend: 网络请求结束事件
mui ajax
mui框架基于htm5plus的XMLHttpRequest,封装了常用的Ajax函数,支持GET、POST请求方式,支持返回json、xml、html、text、script数据类型; 本着极简的设计原则,mui提供了mui.ajax方法,并在mui.ajax方法基础上,进一步简化出最常用的mui.get()、mui.getJSON()、mui.post()三个方法。
mui.ajax( url [,settings] )
- url:请求发送的目标地址
- settings:key/value格式的json对象,用来配置ajax请求参数,支持的参数如下:
- data:发送到服务器的业务数据;
- type:请求方式,目前仅支持'GET'和'POST',默认为'GET'方式;
- dataType:预期服务器返回的数据类型;如果不指定,mui将自动根据HTTP包的MIME头信息自动判断;
支持设置的dataType可选值:- "xml": 返回XML文档
- "html": 返回纯文本HTML信息;
- "script": 返回纯文本JavaScript代码
- "json": 返回JSON数据
- "text": 返回纯文本字符串
- success:Type: Functon(Anything data,String textStatus,XMLHttpRequest xhr)
请求成功时触发的回调函数,该函数接收三个参数:- data:服务器返回的响应数据,类型可以是json对象、xml对象、字符串等;
- textStatus:状态描述,默认值为'success'
- xhr:xhr实例对象
- error:Type: Functon(XMLHttpRequest xhr,String type,String errorThrown)请求失败时触发的回调函数;
该函数接收三个参数:- xhr:xhr实例对象
- type:错误描述,可取值:"timeout", "error", "abort", "parsererror"、"null"
- errorThrown:可捕获的异常对象
- timeout:Type: Number,请求超时时间(毫秒),默认值为0,表示永不超时;若超过设置的超时时间(非0的情况),依然未收到服务器响应,则触发error回调;
- headers:Type: Object,格式为:{'Content-Type':'application/json'},
详情参考html5+ setRequestHeader。
基本格式如下:
mui.ajax(url,{
data:{
username:'username',
password:'password'
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
mui.post( url [,data] [,success] [,dataType] )
mui.post()方法是对mui.ajax()的一个简化方法,直接使用POST请求方式向服务器发送数据、且不处理timeout和异常(若需处理异常及超时,请使用mui.ajax()方法)
mui.post('http://server-name/login.php',{
username:'username',
password:'password'
},function(data){
//服务器返回响应,根据响应结果,分析是否登录成功;
...
},'json'
);
mui.get( url [,data] [,success] [,dataType] )
mui.get()方法和mui.post()方法类似,只不过是直接使用GET请求方式向服务器发送数据、且不处理timeout和异常(若需处理异常及超时,请使用mui.ajax()方法)。如下为获得某服务器新闻列表的代码片段,服务器以json格式返回数据列表:
mui.get('http://server-name/list.php',
{category:'news'},
function(data){
//获得服务器响应
...
},'json'
);
mui.get( url [,data] [,success] )
mui.getJSON()方法是在mui.get()方法基础上的更进一步简化,限定返回json格式的数据,其它参数和mui.get()方法一致,如上获得新闻列表的代码换成mui.getJSON()方法后,更为简洁,如下:
mui.getJSON('http://server-name/list.php',
{category:'news'},
function(data){
//获得服务器响应
...
}
);
注:初学者肯对于GET与POST的区别不是很清楚,这里不做详细介绍,若要深入了解请查看:GET,POST — 简述
项目实战
我们接着上一篇文章的项目开始进行本节的内容,上一篇我们讲解了html5+ webview的使用方法,并且实现了一个基于父子webview的tab bar切换的案例,我们这次利用网易音乐API接口请求数据,完成我们后续的音乐播放器功能。
API分析
网易音乐搜索API:
- url:http://s.music.163.com/search/get/
- type:"GET"或“POST" //HTTP请求类型
- 请求参数:
- type: 1
- s: //关键词
- limit: 10 //限制返回结果数为10
- offset: 0 //偏移
- src: lofter //可为空
- filterDj: true | false //可为空
- callback: //为空时返回json,反之返回jsonp callback
由于HTTP请求类型包含get,我们只需要把请求的参数拼接到url里面就可以得到返回的数据,格式为url?key1=value1&key2=value2。
在这个例子中我们打开这个网址http://s.music.163.com/search/get/?type=1&limit=5&s=喜欢你,我们会发现一些数据返回了,如下图:
OK,我们下面讲解怎么通过程序得到这些数据,并且我们并且怎么解析这些数据。
在开始之前我们先对我们要得到的数据进行美化,这里我在网上随便搜了一个
在线JSON校验格式化工具,我们只需要把刚刚那些数据复制粘贴到我给的这个工具里面,然后点击校验就变整齐了。
{
"result": {
"songCount": 3224,
"songs": [
{
"id": 28949444,
"name": "喜欢你",
"artists": [
{
"id": 7763,
"name": "G.E.M.邓紫棋",
"picUrl": null
}
],
"album": {
"id": 2956076,
"name": "喜欢你",
"artist": {
"id": 0,
"name": "",
"picUrl": null
},
"picUrl": "http://p1.music.126.net/u_1EudmF8Swgow6vfgYe1g==/8896148580676276.jpg"
},
"audio": "http://m2.music.126.net/_icR1apQHVl8wa0EP_REkQ==/3269947581061892.mp3",
"djProgramId": 0
}
]
},
"code": 200
}
我们可以看到
"picUrl":"http://p1.music.126.net/u_1EudmF8Swgow6vfgYe1g==/8896148580676276.jpg"
打开这个图片地址我们就可以看到邓紫棋了,哈哈,也就是说我们只需要抓取到这个地址就可以进行下面的工作咯,其他的类似。
mui.ajax请求实例
我们在上次新建的M-BOX下的home.html下写这个例子:
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
var url = "http://s.music.163.com/search/get/";
mui.ajax(url,{
data: {
'type': 1,
's': "喜欢你",
'limit': 10
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
console.log(JSON.stringify(data));
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
</script>
hbuilder
很方便的一个功能就是真机调试,我们直接将电脑与手机连接,通过console.log()
函数可以很方便的将数据在控制台打印出来,例如上述例子如果我们在success
的回调函数中执行console.log(data);
,在控制台会输出[object Object]
,我们只需要利用JSON.stringify()
方法可以将任意的JavaScript
值序列化成 JSON
字符串。
Javascript语法基础
每次看到很多同学在解析json
的时候错误百出,严重暴漏了基本功,这里我就总结几条与解析json
可能相关的知识点。
什么是JSON?
JSON:JavaScript Object Notation
(JavaScript 对象表示法),JSON
是存储和交换文本信息的语法,独立于语言。类似 XML
。JSON
比 XML
更小、更快,更易解析,具有自我描述性,更易理解的特点。
JSON
就是一串字符串,只不过元素会使用特定的符号标注。
- {} 双括号表示对象
- [] 中括号表示数组
- "" 双引号内是属性或值
- :表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)
{"name": "Dcloud"}
可以理解为是一个包含name
为Dcloud
的对象;
[{"name": "mui"},{"name": "html5+"}]
就表示包含两个对象的数组。
通过JavaScript
,您可以创建一个对象数组,并像这样进行赋值:
var employees = [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName": "Jones" }
];
可以像这样访问 JavaScript 对象数组中的第一项:
employees[0].lastName;
返回的内容是:
Doe
可以像这样修改数据:
employees[0].firstName = "Jonatan";
运算符[ ] 和 .
[ ]可以用于数组和对象取值,数组中按下边取值。
var array=["one","two","three","four"];
array[0];
对象属性取值时,当我们不知道属性名或属性名本身包含点(.)的键,应当使用[ ]。
for(var key in obj){
console.log(key + ":" + obj[key]);
}
var obj={
id:"obj",
"self.ref":ref
}
console.log(obj["self.ref"]);
.运算符的左边为一个对象,右边为属性名。如:obj.id
可以动态访问属性:
var key="property";
console.log(key);
var obj={
property:"hello word"
}
console.log(obj[key]);
数组的map方法:
var array=[1,2,3,4,5];
array.map(function(item){
return item*2;
});
数组map
方法可以接受一个匿名函数,数组中每个元素都会调用这个匿名函数,并且讲返回结果放在一个数组中。
获取数据更新UI
mui
中的each()
方法既是一个类方法,同时也是一个对象方法,两个方法适用场景不同;换言之,你可以使用mui.each()
去遍历数组或json
对象,也可以使用mui(selector).each()
去遍历DOM
结构。
mui.each( obj , handler )
- obj :
Type: Array||JSONObj
需遍历的对象或数组;若为对象,仅遍历对象根节点下的key - handler :
Type: Function( Integer||String index,Anything element)
为每个元素执行的回调函数;其中,index表示当前元素的下标或key,element表示当前匹配元素
对于前面说到的音乐api
返回的json
数据,首先我们要通过var songs=data.result.songs;
获取"songs"
的值,然后遍历"songs"
对象的子对象。
···
success:function(data){
// console.log(JSON.stringify(data));
var songs=data.result.songs;
mui.each(songs,function(index,item){
var id = item.id,
name = item.album.name,
author = item.artists[0].name,
picUrl = item.album.picUrl,
audio = item.audio;
})
},
···
我们用上述代码可以得到我们想要的数据,下面就是需要将信息展示出来,这里我们只获取 歌曲id
、歌曲所属专辑名name
、歌曲第一作者author
、歌曲所属专辑图片picUrl
、歌曲音频文件audio
。
考虑到要加载很多图片,这里我们使用懒加载实现效果,这里我们直接使用hello mui
里面的模板页面lazyload-image.html
,我们需要引入mui.lazyload.js
和mui.lazyload.img.js
两个文件,还有占位图。下面先贴出修改后的基本的代码,然后再讲解其中的内容。
home.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>M-BOX</title>
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!--标准mui.css-->
<link rel="stylesheet" href="../css/mui.min.css">
<style type="text/css">
.mui-content>.mui-table-view:first-child {
margin-top: 0px;
}
</style>
</head>
<body>
<div class="mui-content">
<ul id="list" class="mui-table-view mui-table-view-chevron"></ul>
</div>
</body>
<script src="../js/mui.min.js "></script>
<script src="../js/mui.lazyload.js"></script>
<script src="../js/mui.lazyload.img.js"></script>
<script>
mui.init();
var url = "http://s.music.163.com/search/get/";
mui.ajax(url,{
data: {
'type': 1,
's': "喜欢你",
'limit': 10
},
dataType:'json',//服务器返回json格式数据
type:'post',//HTTP请求类型
timeout:10000,//超时时间设置为10秒;
success:function(data){
//console.log(JSON.stringify(data));
var songs=data.result.songs;
var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
var li;
mui.each(songs,function(index,item){
var id = item.id,
name = item.album.name,
author = item.artists[0].name,
picUrl = item.album.picUrl,
audio = item.audio;
li = document.createElement('li');
li.className = 'mui-table-view-cell mui-media';
li.innerHTML = '<a class="mui-navigate-right" id='+ id +' data-audio='+ audio +'>'+
'<img class="mui-media-object mui-pull-left" data-lazyload="'+picUrl+'">'+
'<div class="mui-media-body">'+name+
'<p class="mui-ellipsis">'+author+'</p>'+
'</div>'+
'</a>';
fragment.appendChild(li);
})
list.appendChild(fragment)
mui(document).imageLazyload({
placeholder: '../img/60x60.gif'
});
},
error:function(xhr,type,errorThrown){
//异常处理;
console.log(type);
}
});
//列表点击事件
mui("#list").on('tap','li a',function(){
var id = this.getAttribute('id');
var audio = this.getAttribute('data-audio');
//打开详情页面
mui.openWindow({
url:'music.html',
id:'music.html',
extras:{
musicId:id,
audioUrl:audio
}
});
});
</script>
</html>
music.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title></title>
<link href="../css/mui.min.css" rel="stylesheet"/>
</head>
<body>
<script src="../js/mui.min.js"></script>
<script type="text/javascript">
mui.init();
mui.plusReady(function(){
var self = plus.webview.currentWebview();
var musicId = self.musicId;
var audioUrl = self.audioUrl;
document.write("musicId:" + musicId + "<br />");
document.write("audioUrl:" + audioUrl);
});
</script>
</body>
</html>
我们这里说几个开发者常见的问题:
拼接html字符串
首先打开hello mui
里面的模板页面lazyload-image.html
,我们打开控制台查看elements
,结构如下:
<ul id="list" class="mui-table-view mui-table-view-chevron">
<li class="mui-table-view-cell mui-media">
<a class="mui-navigate-right">
<img class="mui-media-object mui-pull-left" data-lazyload-id="0" src="http://www.dcloud.io/hellomui/images/1.jpg?version=447.4190210457891">
<div class="mui-media-body">
主标题
<p class="mui-ellipsis">列表二级标题</p>
</div>
</a>
</li>
</ul>
我们需要将获取的内容动态的填充到这个里面,这里常用的方法就是动态的生成节点,这里我们就要用到DOM
的创建方法document.createElement
,通过这个方法我们可以生成一个节点:
li = document.createElement('li');
这个可以生成一个li
节点,我们需要为这个li
指定class
,通过对对象的className
赋值实现,如:li.className = 'mui-table-view-cell mui-media';
,我们使用appendChild(li)
方法将li
节点挂着父节点上,比如:
var list = document.getElementById("list");
list.appendChild(li);
这个就是把li
节点挂在list
下,同理我们可以在li
节点下 创建子节点,上面为了简单,我们使用给innerHTML
属性赋值的做法,这样innerHTML
的值同样会挂在li
节点下,大家需要注意的是innerHTML
属性的值我字符串,所以我们往中间插入了变量,要使用+
连接起来。我们可以通过循环创建多个节点,如下面这样创建十个段落:
for(var i = 0 ; i < 10; i ++) {
var p = document.createElement("p");
var oTxt = document.createTextNode("段落" + i);
p.appendChild(oTxt);
document.body.appendChild(p);
}
上面我们使用的是mui.each()
方法,效果类似。
如果细心的同学或许注意到我们使用了一个奇怪的写法:
var fragment = document.createDocumentFragment();
mui.each(songs,function(index,item){
...
fragment.appendChild(li);
});
list.appendChild(fragment);
为啥我们要在这里使用fragment
呢?
如果是对前端技术感兴趣的同学说不定回去查一下,我相信大部分人可能就放过了吧!这里我查了一下资料:
在《javascript高级程序设计》一书的6.3.5:创建和操作节点一节中,介绍了几种动态创建html节点的方法,其中有以下几种常见方法:
- crateAttribute(name): 用指定名称name创建特性节点
- createComment(text): 创建带文本text的注释节点
- createDocumentFragment(): 创建文档碎片节点
- createElement(tagname): 创建标签名为tagname的节点
- createTextNode(text): 创建包含文本text的文本节点
其中最感兴趣且以前没有接触过的一个方法是createComment(text)方法,书中介绍说:在更新少量节点的时候可以直接向document.body节点中添加,但是当要向document中添加大量数据是,如果直接添加这些新节点,这个过程非常缓慢,因为每添加一个节点都会调用父节点的appendChild()方法,为了解决这个问题,可以创建一个文档碎片,把所有的新节点附加其上,然后把文档碎片一次性添加到document中。—— document的createDocumentFragment()方法
页面传值
我们点击了列表,我们会进入一个详情页,我们肯定是想知道我们究竟点了哪一个我们想把一些数据传入到详情页面,这里我们使用了mui.openWindow()
方法中的拓展参数extras
传入几个值,在详情页面通过plus.webview.currentWebview
获取:
mui.plusReady(function(){
var self = plus.webview.currentWebview();
var musicId = self.musicId;
var audioUrl = self.audioUrl;
document.write("musicId:" + musicId + "<br />");
document.write("audioUrl:" + audioUrl);
});
这是在页面初始化时,通过扩展参数extras
传值;另外还有页面已创建,通过自定义事件传值,参考mui官网中自定义事件的介绍,这里先不讲得太多,后面会专门花时间详细讲解相关细节。
当我们写到这里,发现这篇依然是长长的一篇干货,很多内容摘自文档,主要是为了新手可以详细去了解整个流程。其实还有很多没有写出来,限于篇幅还是后面再写吧!由于代码在文章中写得很详细,工程代码先不给出来,最后整个系列写完了再放出来吧!
收起阅读 »