赵梦欢
赵梦欢
  • 发布:2016-05-29 22:05
  • 更新:2019-09-23 09:36
  • 阅读:56792

mui初级入门教程(三)— html5+ XMLHttpRequest 与mui ajax用法详解

分类: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>

注:引用自segmentfaulttychio的回答。

总之,不论是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的事件:

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 是存储和交换文本信息的语法,独立于语言。类似 XMLJSONXML 更小、更快,更易解析,具有自我描述性,更易理解的特点。

JSON就是一串字符串,只不过元素会使用特定的符号标注。

  • {} 双括号表示对象
  • [] 中括号表示数组
  • "" 双引号内是属性或值
  • :表示后者是前者的值(这个值可以是字符串、数字、也可以是另一个数组或对象)

{"name": "Dcloud"}可以理解为是一个包含nameDcloud的对象;
[{"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.jsmui.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官网中自定义事件的介绍,这里先不讲得太多,后面会专门花时间详细讲解相关细节。

当我们写到这里,发现这篇依然是长长的一篇干货,很多内容摘自文档,主要是为了新手可以详细去了解整个流程。其实还有很多没有写出来,限于篇幅还是后面再写吧!由于代码在文章中写得很详细,工程代码先不给出来,最后整个系列写完了再放出来吧!

7 关注 分享
月护王 amo 3***@qq.com Cree jqr lifeng_dev 1***@qq.com

要回复文章请先登录注册

lifeng_dev

lifeng_dev

大佬,看了多篇博客,还是觉得不太理解,于是在此请教:
关于设置 Content-Type 和 get 请求 post 请求传参的问题,一般情况下,get请求需要拼接url,post 直接写在 data 里,
现在感觉get 拼接参数看起来不直观,想写到data 里。
下面是mui 官方文档关于 ajax 的一些说明:
headers 和 processData 是ajax 请求的两个参数,
headers
Type: Json
指定HTTP请求的Header
headers:{'Content-Type':'application/json'}

processData
Type: Boolean
为了匹配默认的content-type("application/x-www-form-urlencoded"),
mui默认会将data参数中传入的非字符串类型的数据转变为key1=value&key2=value2格式的查询串;
如果业务需要,希望发送其它格式的数据(比如Document对象),可以设置processData为false

通过上面的参数,又有一个问题,移动端应用一般都是用 application/json 的比较普遍,所谓的 application/x-www-form-urlencoded 表单提交只是为了参数写的地方不同的时候做的统一处理,还是另有别的考虑。
以上概念,理解比较笼统,望大佬给点通俗易懂的解答。
2019-09-23 09:36
兴趣然

兴趣然

代码中不存在跨域问题吗?
2019-05-08 11:40
Cree

Cree

mui ajax对IOS支持不友好,真机测试不能用ajax方法即使是crossdomain也不行。对and可以用。如果两种都兼容建议用XMLrequest
2018-05-29 12:06
z***@163.com

z***@163.com

不是说混合app打包后不存在跨域吗,如果不用pc浏览器,新手一枚,求解
2018-02-22 21:21
fategaga

fategaga

very nice
2017-04-07 10:59
ali

ali

IOS 手机上播放不了 音乐 怎么样才能正常播放呢 求助?
2017-01-21 19:15
ypf

ypf

回复 赵梦欢 :
mui.ajax的post方法回将json格式的数字参数解析成字符串传到服务器,大问题??
2017-01-18 11:32
ali

ali

我做一个 搜音乐 播放 可apple 手机上 播放时候 播放不了 安卓 正常播放 apple 在线音乐播放不了了 本地下地 正常播放了 求大神们来解答。。。。
2017-01-05 10:42
1***@qq.com

1***@qq.com

按照源码复制了一份为什么请求超时??
2016-11-22 10:17
水灵退散

水灵退散

回复 赵梦欢 :
那个。。可以给出一点代码吗?
2016-09-13 14:50