Ajax交互梳理

AJAX

服务器与客户端

服务器(server)

我们如果想把自己的网页,让其它人能够访问,就必须要用到服务器的知识了。

作用

服务器是一个非常重要的概念,做为一名前端人员,我们在实现的工作过程可能不会直接与服务器打交道,但是,我们应该理解所有的应用都需要有服务器的支持。

比如:生活中我们也会听到服务器这三个字。

(一台服务器服务于多台设备)

简单来理解:

服务器 = 硬件配置高的电脑 + 安装特殊软件

是提供服务的机器。给其它设备(电脑,手机,平板…)提供某种特殊服务的电脑

服务器的分类

简单来理解:

服务器 = 硬件配置高的电脑 + 安装特殊软件

安装的软件不同,它能提供的服务也不同。 根据所能提供的服务不同,可分成很多种:

  • web服务器: 安装了能提供web服务的软件。如iis, nginx, apache等。

  • ftp……:上传文件

客户端(client)

客户端:连接到服务器,享受服务的设备,就是客户端。

访问web服务器的基本流程

商场买电脑的过程

商场买东西

1.定位商场的地址

2.到商场,告诉专卖店你的需要

3.给你电脑

4.回家使用电脑

访问web服务器

在这里插入图片描述
(请求响应流程示意图)

基本流程

  1. 确认地址。用户在浏览器(客户端)地址栏输入要访问的网站网址(URL)

  2. 发送请求。浏览器向服务器发送请求(request),告知服务器要获取的内容

  3. 获取响应。服务端收到浏览器发送的请求,并把处理的结果返回给浏览器(response)

  4. 显示内容。浏览器将服务端返回的结果显示到界面上

本地虚拟web服务器

为了方便学习,我们会在自己的电脑上安装服务器软件,把自己的电脑虚拟成服务器。换句话说,我们的电脑既是客户端,又是服务器。

我们需要提供web服务:让其它同学能够访问我们网页。

web服务器 = 硬件配置高的电脑 + web软件(如iis,apache, nginx)

方法:

  • 安装特殊的web软件:iis apache nginx
  • 安装vscode的插件 live-server
  • 安装 Teseve
  • 使用第三方的集成软件 app_server, phpStudy等
  • 使用黑盒工具app.exe

其它任何一种方法都可以把你的电脑虚拟成服务器,让其它同学来访问。

介绍黑盒服务器

参见具体的文档。

  • 启动软件

    • 注意观察端口号。以3005为例。
  • 访问网页

    1. 先准备文件。把网页放在public文件夹下。
    2. 访问:
      1. 方法一:http://localhost:3005/index.html
      2. 方法二:http://本机ip/index.html
  • 访问数据

    行话也称为接口。get类型的接口可以直接在浏览器中观看效果。

AJAX技术的好处

总结如下两点好处:

  1. 局部更新,提升用户体验,提升性能。

  2. 分离开发,提高开发效率。在项目实际开发过程中,ajax是一个必不可少的技术,是前后端分离开发的基础。

    1. 后端同学提供接口。这个接口我们可以理解是一个函数:它的内部进行业务处理,数据库访问等等操作,并返回结果。如何去实现这函数的功能就是后端同学的任务了。
    2. 前端同学调用接口获取数据(有其特定的格式),然后再把数据转化成的图文并茂的网页。

通过network面板来观察AJAX

掌握:

  • network面板
  • all / xhr
  • response

ajax是什么

AJAX ,全称是:Asynchronous JavaScript And Xml 。 (async:表示异步,sync:表示同步)

  • 异步的JavaScript和XML。
  • 是一种创建交互式网页应用的网页开发技术。并不是一种新技术,而是一种解决方案,早在在1998年就开始使用。
  • 异步表示不阻塞:浏览器在请求数据时,并不会阻塞用户后续的操作。理解为浏览器派了一个小弟去服务器拿数据了。
  • XML表示一种数据格式,最初设计AJAX时,从服务器返回的数据是XML格式的,后面慢慢被JSON数据格式取代了。
  • 更具体一点,浏览器通过内置对象 XMLHttpRequest 向服务器发起请求,并可以接收服务器返回给浏览器的数据,这一过程或实现这一过程的技术就是我们所说的 Ajax。

使用jQuery提供的AJAX功能

jquery体验ajax

第一个$.ajax请求:获取服务器上的时间common/getCurrentTime

基本流程:

  1. 准备工作

    确保服务器端是已经就绪的。直接在地址栏中使用接口,测试接口common/getCurrentTime

  2. 新建页面,引入jquery。

  3. 参考给定的$.ajax格式,发送请求。

    1. 讲解回调函数的含义。
$.ajax()的基本格式
$.ajax(
  url,//  '/common/getCurrentTime',
  {
     type: 'get',// post
     data: {id:1},
     success: function (result) {
     	console.log(result)
  	 }
  }
)
// - url : 表示请求的地址,可以省略域名。
// - type: 表示请求的类型,常见取值 get,post。如果不写,默认为'get'
// - data: 表示发送请求时附加的参数,如果没有参数,可省略
// - success:它是一个回调函数。当请求成功之后会自动调用这个函数,它的第一个参数是服务器端返回的数据。

还有其它的配置项,我们在后面再去学习。

回调函数(Callback Functions)

作用:用于对特定的事件或条件进行响应。

两层含义:

- 1. 函数。表示它是一个函数,是可以被执行的,能做具体操作的函数。
- 2. 回调。在某个时刻,或者某个事件发生`自动去调用这个函数`。

代码示例:

​ 如下均是回调函数的使用

$(function(){
    
})
$(document).ready(function(){
    
})
$("#btn").click(function(){
    
})
[].sort(function(a,b){ return a - b;})
[1,2,3].forEach(function(item,index,self){ 
})

function ok(result){
    console.log(result)
}
$.ajax(
  url,//  '/common/getCurrentTime',
  {
     type: 'get',// post
     data: {id:1},
     success: ok
  }
)

注意:

​ 一般情况下,回调函数都是匿名函数。但,也是可以给它们起名字的。

带参数的get请求

用户名检测

上一个基本示例中,我们的请求并没有带上参数,而在真实的开发中,我们的请求经常是要带参数的。你可以理解为用户名占用检测这个案例就来解决请求接口要带参数的问题。并且用户名占用检测也是一个比好

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FBJ848MI-1581995138719)(ajax讲义.assets/案例-用户名检测.gif)]

目标:仿照博客园注册,实现用户名占用检测效果;学习使用带参数的get请求;

  1. 测试接口。直接在地址栏中使用接口(common/checkUser),注意在问号后附加参数的问题

  2. 给出静态代码

  3. 分析要实现的功能;

  4. 两种方法传参:

    • 在url中拼接参数实现
  • 介绍$.ajax的参数中的data值,可以简化自己拼接参数的过程。

jquery-ajax-post

常见的两种请求方式get-post

  • get
  • post

字面理解

  • 不同点:

    • get :获取,得到。这种方式请求用于向服务器请求资源(图片,文件,数据…)。它是最常见的请求方式。它的重点在于,它只是请求,而不会改变服务器上的资源。
    • post:派送,投递。这种方式的请求用于向服务器上提交数据,它的重点在于,它可能会修改服务器上的资源。
  • 相同点

    • get和post请求都可以在发请求时附带一些数据。例如:根据用户名去检查这个用户是否被占用;在论坛中注册一个账号。
    • get和post请求都能够从服务器上获取返回的数据。

实操对比

get传数据直接显示在url中

-  query string parameters

post传递数据更安全

  • form Data

常用场景

常见的应用场景适用于get还是post?

  • 查看商品详情(get)
  • 把一件商品放入购物车(post)
  • 修改登陆密码(post)
  • 发表一个帖子(post)
  • 删除一个用户(post)

注意:在实际的开发过程中,由于接口是后端同学已经给定的,所以,可能它们能够支持多种请求方式,也可以只支持其中一种。

JQuery.ajax实现留言板

目标: 通过message/addMsgmessage/getMsg这两个接口,实现一个动态的留言板功能

基本内容:

  1. 效果展示及功能分析
  2. 获取留言
  3. 发送留言
  4. 小结

获取留言并显示

基本流程

发送请求

分析回来的数据

使用forEach或者for循环进行数组遍历,并进行数据拼接

修改显示区的dom

模板字符串

在做字符串拼接时,使用+来拼接复杂内容是很麻烦的,而模板字符串可以解决这个问题。

格式:`${变量} ${表达式}`

语法:

  • 模板字符串使用反引号 ` 把内容括起来,类似于普通字符串的""。
  • ${}充当界定符的作用,其中可以写变量名,表达式等。
  • 允许字符串内部进行换行,代码更好读更好的体验

示例:

let name = 'zs';
let age = 18;
// 拼接多个变量,在模板字符串中使用占位的方式,更易懂
let str = `我是${name},今年${age}`;

// 内容过多可以直接换行
let obj = [{name: 'flex', age: 20},{name: 'james', age: 21}];

let arr = ['175cm', '60kg'];
let html = `
	<div>
		<ul>
			<li>${obj.name}</li>
			<li>${obj.age}</li>
			<li>${arr[0]}</li>
			<li>${arr[1]}</li>
		</ul>
	</div>

原生ajax的实现

在实际的开发中,我们会直接使用如jquery这样的第三方工具库来调用ajax,而不会自己去手写一个原生的。但对于学习者来说,深入学习原生ajax能帮助我们更好的理解和掌握 。

目标: 能手写ajax;掌握XMLHttpRequest的用法;

第一个原生的ajax请求

手写一个ajax请求,来获取服务器时间。

4步:

  1. new 一个xhr对象。
  2. 设置请求信息。
  3. 设置回调函数,处理请求结果。
  4. 发送请求。
// 第一步: 新建一个XMLHttpRequest对象(xhr)
var xhr = new XMLHttpRequest();

// 第二步: 设置请求。 xhr.open(请求的方式,get|post, 请求的url地址);
xhr.open('get', 'common/getCurrentTime');

// 第三步:设置回调函数。返回的数据存放在xhr.responseText中。
xhr.onload = function() {
    console.info('从服务器返回的数据',    xhr.responseText);
};
// 第四步: 发送请求。 xhr.send()
xhr.send();

理解XMLHttpRequest对象

  • ajax的功能是基于XMLHttpRequest对象来实现的。
  • 它是内置对象,充当构造器使用。
  • 浏览器中的network中查看 xhr

属性和方法:

  • open()
  • send()
  • onload(function(){})
  • responseText

原生ajax-带参数的get

get带参数-检测用户名是否占用

get带参数的格式:附加在请求的url地址后面。

url?参数1=值1&参数2=值2&参数3=值3...
  • &
// 第一步: 新建一个XMLHttpRequest对象(xhr)
var xhr = new XMLHttpRequest();

console.info(xhr);
// 第二步: 设置请求。 xhr.open(请求的方式,get|post, 请求的url地址);
xhr.open('get', 'common/checkuser?username='+username);

// 第三步: 发送请求。 xhr.send()
xhr.send();
        
// 第四步: 设置回调函数。请求成功之后,获取服务器返回的数据.
// 返回的数据存放在xhr.responseText中。
xhr.onload = function() {
   console.info('从服务器返回的数据', xhr.responseText);
};

原生ajax-post 请求

post请求的格式
//1. 创建xhr对象
var xhr = new XMLHttpRequest();
//2. 初始化请求
xhr.open('post',服务器地址);
//3. 设置请求头,固定写法
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
//4. 监听响应的回调函数
xhr.onload = function(){
    console.log(xhr.responseText);
}
//5. 发送请求
xhr.send('提交给服务器数据字符串');// 'a=1&b=3'

注意:

  • 要设置请求头
  • 提交给服务器的数据写在send()中。
案例:用户登陆*

代码资料:

<style>
    .container {
        width: 800px;
        padding: 2em;
        margin: 40px auto;
        border: 1px solid #ccc;
    }
    .container label {
        display: inline-block;
        width: 80px;
    }
</style>
<div class="container">
    <h2>用户登陆</h2>
    <p>正确的账号信息是:用户名admin,密码admin</p>
    <div>
        <label for="userName">用户名</label
            ><input type="text" placeholder="请输入用户名" id="userName" />
    </div>
    <div>
        <label for="password">密码</label
            ><input type="text" placeholder="请输入密码" id="password" />
    </div>
    <div>
        <button id="btnLogin">登录</button>
    </div>
    <div id="result"></div>
</div>

整体分析

  • 传参
  • content-type:application/x-www-form-urlencoded

设置与不设置头的区别:

一定设置请求头。

原生ajax中get 和 post 区别

  • get

    • 参数拼接在url(url?name=1&age=30
    • 由于浏览器对url长度的支持(各个浏览器均不同)是有限,所以,它只能附加少量的数据。
  • post

    • 要设置请求头: xhr.setRequestHeader('content-type','application/x-www-form-urlencoded')
    • 参数写在send()方法中:send('name=1&age=30')
    • 相对于get 来说,没有传参大小的限制。

onreadystatechange事件和readyState属性

onreadystatechange事件

onload 是 HTML5 (2014年9月)以后新增的方便获取响应的事件,一些老的浏览器(ie6,ie7,ie8)对onload是不支持的。通过代码来验证这一点:以下代码在ie6,ie7,ie8中并不能使用。

var xhr = new XMLHttpRequest()
// open 方法的第一个参数的作用就是设置请求的 method
xhr.open('get', 'common/getCurrentTime')

xhr.onload = function () {
    alert('ok')
}
xhr.send()

在html5之前,获取服务器返回内容的时候使用的是 onreadystatechange事件,这个事件是在xhr对象状态变化时被触发,而一次请求过程中,XMLHttpRequest对象的状态会发生多次变化,也就意味着这个事件会被触发多次。

onreadystatechange

var xhr = new XMLHttpRequest()
// open 方法的第一个参数的作用就是设置请求的 method
xhr.open('get', 'common/getCurrentTime')
// onreadystatechange
xhr.onreadystatechange = function () {
    console.log('事件被触发了')
}
xhr.send()
xhr 对象的状态

一共有5种,用readyState属性表示,详见下表

readyState状态描述说明
0UNSENTXHR被创建,但尚未调用 open() 方法。
1OPENEDopen() 方法已经被调用,建立了连接。
2HEADERS_RECEIVEDsend() 方法已经被调用,并且已经可以获取状态行和响应头。
3LOADING响应体下载中, responseText 属性可能已经包含部分数据。
4DONE**响应体下载完成,可以直接使用 responseText

一次正常的send()话,xhr.readStatus的值的变化是:

0 -> 1 -> 2 -> 3 -> 4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Oax7sEsH-1581995138723)(ajax讲义.assets/1559037455667.png)]

get请求在IE 中的缓存问题

如下代码,在ie中运行:

<div>
    <button id="btn">获取时间</button>
<label for="" id="lblTimer"></label>
</div>
<script>
    document.getElementById('btn').onclick = function() {
    var xhr = new XMLHttpRequest();
    console.log(xhr.readyState);
    // open 方法的第一个参数的作用就是设置请求的 method
    xhr.open('get', 'common/getCurrentTime');
    console.log(xhr.readyState);
    xhr.send();
    // 更改事件为onreadystatechange
    xhr.onreadystatechange = function() {
        // 表示从服务器端返回的数据已经全部ok了。
        if (xhr.readyState == 4) {
            document.getElementById('lblTimer').innerHTML = xhr.responseText;
        }
    };
};
</script>

出现的原因:

  • 每次请求的地址都一样,浏览器自作聪明去使用了第一次请求的结果。

解决方法

  • 骗浏览器,让它以为每次的请求都不一样

  • http://localhost:3005/common/getCurrentTime?_t=1559038330427

document.getElementById('btn').onclick = function() {
          var xhr = new XMLHttpRequest();
          console.log(xhr.readyState);
          // open 方法的第一个参数的作用就是设置请求的 method
          var time = Date.now(); // 附加一个变化的值
          xhr.open('get', 'common/getCurrentTime?_t=' + time);
          console.log(xhr.readyState);
          xhr.send();
          // 更改事件为onreadystatechange
          xhr.onreadystatechange = function() {
            // 表示从服务器端返回的数据已经全部ok了。
            if (xhr.readyState == 4) {
              document.getElementById('lblTimer').innerHTML = xhr.responseText;
            }
          };
        };

以jd.com为例loginservice.aspx

服务器端返回的数据格式

前端人员通过ajax请求从服务器获取数据,数据拿回来之后,可能还需要做一步的操作,例如:如果是一个数组,则要遍历数组。

那么掌握服务器返回的数据的表现形式是非常重要的环节,只有知道了这些格式,我们才能更好去处理这些数据。

了解服务器端返回数据在类型上的区别;会对json进行操作; 简单了解xml;

内容:

  • 观察三种不同的返回值
  • 深入学习JSON
  • 简单学习XML

了解三个不同结构的字符串

引入:以4大名著书本信息为例,比较三种文件的回传的数据比较。

  • 文本:普通字符串
  • json:json格式的字符串
  • xml:xml格式的字符串

直接在浏览器中打开三个接口,列出结果如下:

  • 格式1:
作者:吴承恩,书名:西游记;作者:施耐庵,书名:水浒传;作者:罗贯中,书名:三国演义;作者:曹雪芹,书名:红楼梦
  • 格式2:
[
    {"author":"吴承恩","name":"西游记"},
 	{"author":"施耐庵","name":"水浒传"},
  	{"author":"罗贯中","name":"三国演义"},
  	{"author":"曹雪芹","name":"红楼梦"}
]
  • 格式3
<?xml version="1.0" encoding="utf-8" ?>
<booklist>
<book>
	<author>吴承恩</author>
	<name>西游记</name>
</book>
<book>
	<author>施耐庵</author>
	<name>水浒传</name>
</book>
<book>
	<author>罗贯中</author>
	<name>三国演义</name>
</book>
<book>
	<author>曹雪芹</author>
	<name>红楼梦</name>
</book>
</booklist>

哪一种格式的字符串更好读?为什么?

Tip: 同样是作文,字迹字体也有工整之分。

JSON

发送ajax请求时,从服务器端返回的数据格式要统一,这样才能让不同的后端语言,不同的前端人员都 能读懂,都方便操作,而这时,我们就可以使用JSON格式。

它用于描述数据,它比普通字符串更具有表达力!

如何判断返回值是JSON字符串

观察几个真实的JSON数据:

从服务器返回的数据都是字符串格式的,如何判断数据是JSON字符串格式的?

[在线验证json格式](http://www.bejson.com/

tip: 直接在线进行字符串校验,判断一个字符串是不是json字符串。

JSON是什么

JSON: JavaScript Object Notation(JavaScript 对象表示法) 。

  • JSON 是一种通过普通字符串描述数据的手段,用于表示有结构的数据。
  • JSON 是轻量级的文本数据交换格式,类似 XML。
  • JSON 独立于编程语言 (php,java,go,js 都会通过它来进行数据交流)
  • JSON 具有自我描述性,更易理解
JSON字符串常见格式

作为前端人员,我们是通过调用服务器端接口的方式来获取JSON字符串,也就是说,我们一拿到数据,它是JOSN格式的,而这个JSON格式的数据显然是由后端同学给提供的。

但是,我们也要知道如何去写出一个标准的JSON字符串。

有如下三种情况:

  • 普通字符串

  • 数组字符串

    '["a","b","c"]'
    

做法是:在javascript数组前后加上单引号,变成字符串就行。

  • 对象字符串

    '{"name":"curry","age":40}'
    

做法是:

  1. 在javascript对象的属性名加上’双引号’(不能用单引号);
  2. 把整个对象前后加上单引号
JSON字符串相关的两个操作
    1. 把JSON字符串转成具体某个编程语言中的数据格式;
    1. 在某个编程语言中,把数据格式转成JSON字符串;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-deUUB9Z2-1581995138725)(ajax讲义.assets/1559101747981.png)]

从JSON字符串转成编程语言支持的数据从数据类型转成JSON字符串
jsJSON.parse()JSON.stringify()
phpjson_decode()json_encode()
javaJSON.parseObject(),JSON.parseArray()JSON.toJSONString

js中提供了一个静态对象JSON来处理json。 它与Math相似,不需要new,而是直接通过对象名.方法来调用。

JSON.stringify

功能:把js数据,转成JSON格式的字符串

格式:var JSON字符串 = JSON.stringify(js数据)

// 1.把js中的数组,对象 转成 JSON字符串
var arr = [1, 2, 3, 'ok', 'hello'];
var arr_jsonStr = JSON.stringify(arr);
console.info(arr, typeof arr);
console.info(arr_jsonStr, typeof arr_jsonStr);

var obj = { name: 'flex', age: 30, favoriate: ['篮球', '前端'] };
var obj_jsonStr = JSON.stringify(obj);
console.info(obj, typeof obj);
console.info(obj_jsonStr, typeof obj_jsonStr);
JSON.parse

功能:把JSON格式的字符串,还原成JS中的数据格式

格式:var JS数据 = JSON.parse(JSON字符串)

案例:把四大名著json字符串以表格的形式显示

XML(简单了解)

可扩展标记语言(Extensible Markup Language)。

  • XML 于 1998 年 2 月 10 日成为 W3C 的推荐标准。

  • 它提供了一种描述结构数据的格式,简化了网络中数据交换和表示,使得代码、数据和表示分离,并作为数据交换的标准格式。

  • 独立于编程语言的。

  • AJAX(异步的javascript和XML)中的 X 就是 XML

示例

假设这个文件的名字为books.xml

<?xml version="1.0" encoding="utf-8" ?>
<booklist>
<book>
	<author>吴承恩</author>
	<name>西游记</name>
</book>
<book>
	<author>施耐庵</author>
	<name>水浒传</name>
</book>
<book>
	<author>罗贯中</author>
	<name>三国演义</name>
</book>
<book>
	<author>曹雪芹</author>
	<name>红楼梦</name>
</book>
</booklist>
操作(了解)

如果ajax所请求的接口,明确规定返回值是xml格式,你可以通过:

  • 通过xhr.responseXML来获取内容。

  • 拿到这个内容之后,就像操作dom元素一样去访问其中的内容。

var books = xhr.responseXML.getElementsByTagName('book')
for (var index = 0; index < books.length; index++) {
    var element = books[index]
    console.info(element.getElementsByTagName('author')[0].innerHTML)
}

XML VS JSON

相同点:

  • 都用来描述数据格式
  • 与具体的编程语言无关
  • 有自己文件格式的后缀名.xml和.json的文件

区别

  • JSON 有简易的语法(javascript基因);XML有规范的标签(html基因)
  • JSON存储效率更高

同步和异步

同步和异步是面试中经常会被问到的知识点,下面我们通过ajax来学习这个概念。

内容:

- 对比生活中的例子理解 同步和异步
- 简单代码认识异步的效果
- ajax中的异步
- ajax中的同步

生活中的同步异步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uJBo8elU-1581995138729)(ajax讲义.assets/1561249167046.png)]

同步方式: 一个时刻只能做一件事;

  • 我: 写代码
  • 我: 买咖啡,自己去买,花2小时
  • 我:写代码

异步方式:不是一件接一件做,而是可能同时做多件事情;

- 我: 写代码
- 我: 买咖啡,安排别人去买,跳过这一步,我自己不做。
- 我: 写代码 

ajax定义同步和异步

原生的ajax中,xhr.open()方法的第三个参数就可以决定同步和异步的方式。

xhr.open(参数1 ,参数2,参数3)
- 参数1 :请求的方式.  get,post
- 参数2 :请求的url地址。
- 参数3 :是否启用异步模式,默认为true,即异步, `如果设置为false,就是同步`

以请求黑盒服务器的接口sleep为例(这个接口已经预先写好了,直接调用即可)

// 创建ajax,设置,并发送请求
var xhr = new XMLHttpRequest();
xhr.open('get', 'common/sleep');// 第三个参数不写,默认是异步
xhr.onload = function() {
    console.info('现在的时间是:', new Date().toLocaleTimeString());
};
xhr.send();// 发送。

改成true和false观察效果。

异步的ajax

xhr.open()默认是异步的。通过下面的代码来理解异步。

// 1. 先输出一行提示代码
console.info('1  现在的时间是:', new Date().toLocaleTimeString());

// 2. 创建ajax,设置,并发送请求
var xhr = new XMLHttpRequest();
xhr.open('get', 'common/sleep');// 第三个参数不写,默认是异步
xhr.onload = function() {
    console.info('2 现在的时间是:', new Date().toLocaleTimeString());
};
xhr.send();// 发送。

// 3.再输出一行提示代码
console.info('3 现在的时间是:', new Date().toLocaleTimeString());

异步执行流程:

  • 浏览器:输出1
  • 浏览器:执行send(),发现是异步的,跳过这一步(不会阻塞代码,理解为:不用自己亲自做,找别人去做)
  • 浏览器:输出3

注意:异步ajax时,onload,可以写在send之后

同步的ajax

xhr.open(参数1 ,参数2,参数3)
- 参数1 :请求的方式。 get,post
- 参数2 :请求的url地址。
- 参数3 :是否启用异步模式,默认为true,即异步, `如果设置为false,就是同步`
xhr.open('get', 'common/getCurrentTime');       // 异步
xhr.open('get', 'common/getCurrentTime'true); // 异步
xhr.open('get', 'common/getCurrentTime', false);// 同步
  • 同步代码中,onload必须写在send之前。

  • 同步执行流程:

    • 浏览器:输出1
    • 浏览器:执行send(),发现是同步,只能死等。 整个代码块卡在send这句。
    • 浏览器:输出3

如果你设置成了同步的方式,你会在浏览器看到如下的错误信息:

[Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

有几个单词:

  • Synchronous: 同步的

  • deprecate:反对的,不赞成

  • detrimental:有害的,不利的

翻译一下就是:[deprecation]由于主线程上的同步xmlhttpRequest对最终用户的体验有不利影响,因此不推荐使用它。有关更多帮助,请查看https://xhr.spec.whatwg.org/

原生ajax代码封装

对前面学习的get请求有4步,post请求有5步,下面对这些代码封装,以提高效率。

封装代码的工作,我们可以从实现了某个具体功能的代码出发,例如前面用到的common/get请求的例子

初始代码

// 创建ajax,设置,并发送请求
var xhr = new XMLHttpRequest();
xhr.open('get', 'common/get?a=1&b=2');
xhr.onload = function() {
    console.info('现在的时间是:', new Date().toLocaleTimeString());
};
xhr.send();// 发送。

加括号,变成一个函数

给取一个响应的名字hiAjax

function hiAjax(){
    // 创建ajax,设置,并发送请求
    var xhr = new XMLHttpRequest();
    xhr.open('get', 'common/get?a=1&b=2');
    xhr.onload = function() {
        console.log(xhr.responseText)
    };
    xhr.send();// 发送。
}

hiAjax();

提炼出type参数

function myAjax(type) {
    var xhr = new XMLHttpRequest();
    xhr.open(type,'common/get?a=1&b=2');
    xhr.onload = function(){console.log(xhr.responseText)}
    xhr.send()
}
myAjax('get');

提炼出url和data

function myAjax(type,url,data) {
    var xhr = new XMLHttpRequest();
    if(data){
        url += "?"+data;
    }
    xhr.open(type,url);
    xhr.onload = function(){console.log(xhr.responseText)}
    xhr.send()
}
myAjax('get','common/get','a=1&b=2');

处理post请求

第一步:直接通过if,else进行两类的处理

function myAjax(type,url,data) {
    if(type == 'post'){
        var xhr = new XMLHttpRequest();
        xhr.open(type,url);
        xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
        xhr.onload = function(){console.log(xhr.responseText)}
        xhr.send(data)
    }
    else if(type == 'get'){
        var xhr = new XMLHttpRequest();
        if(data){
            url += "?"+data;
        }
        xhr.open(type,url);
        xhr.onload = function(){console.log(xhr.responseText)}
        xhr.send()
    }
    
}
myAjax('get','common/get','a=1&b=2');
myAjax('post','common/post','a=1&b=2');

第二步:优化代码

把if,else中的相同的代码提出来

function myAjax(type,url,data) {
    var xhr = new XMLHttpRequest();
    
    if(type=='get' && data){
        url += "?"+data;
    }
    xhr.open(type,url);
    xhr.onload = function(){console.log(xhr.responseText)}
       
    if(type == 'post'){
        xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
        xhr.send(data)
    }
    else if(type == 'get'){
        xhr.send()
    }
    
}
myAjax('get','common/get','a=1&b=2');

支持回调函数

  • 全局函数
  • 函数传参

代码:

/**
       * 功能 : 发出ajax请求
       * 参数:
       *    type: 类型是字符串。支持的取值是 "get","post"。决定ajax请求的类型
       *    data: 传给服务器的数据。支持的格式是字符串:a=1&b=2&c=3
       *    url : 请求的地址,
       *    sucess: 请求成功之后的回调函数。第一个参数是服务器返回的数据
       *
       * 示例:
          hiAjax('get', 'name=ok', 'common/get', function(result) {
              console.info('get', result);
          });

          hiAjax('get', '   ', 'common/get',dosomething1);
          hiAjax('get', '', 'common/get',dosomething2);
       */
function hiAjax(type, data, url, success) {
    var xhr = new XMLHttpRequest();

    if (type === 'post') {
        xhr.open(type, url);
        xhr.setRequestHeader(
            'content-type',
            'application/x-www-form-urlencoded'
        );
        xhr.send(data);
    } else if (type === 'get') {
        //如果 data有值,就在url后追加
        // trim() 用来清除字符串前后的空格
        if (data.trim()) {
            url = url + '?' + data;
        }
        xhr.open(type, url);
        xhr.send();
    } else {
        alert('不支持这个格式的请求:' + type);
        return;
    }

    xhr.onload = function() {
        success(xhr.responseText);
    };
}

function dosomething1(result) {
    alert('1');
    console.info(xhr.responseText);
    // alert(1);
}

function dosomething2(result) {
    alert('2');
    console.info(xhr.responseText);
    // alert(1);
}
// 每个请求,从服务器中返回数据之后,都是直接在控制台中输出。
// hiAjax('post', 'a=1&b=2', 'common/post', dosomething1);
hiAjax('get', 'name=ok', 'common/get', function(result) {
    console.info('get', result);
});

hiAjax('get', '   ', 'common/get', dosomething1);
hiAjax('get', '', 'common/get', dosomething2);

总结

封装的基本过程:

  1. 埋头苦干 。写出基本的,能正确运行的代码段
  2. 一名惊人。使用function包裹,变成一个可以被调用的函数;
  3. 从死到活。从具体到抽象。函数内部的固定数据抽成参数,同时写函数文档。
  4. 黑盒测试。列出多维度的测试用例,逐一验证。
  5. 升级优化
    • 目前data这个参数只是查询字符串的格式,是否可让它支持对象格式?

其它ajax库的使用

jquery中的ajax方法

$.ajax的其它选项
$.ajax(url,{
  type: 'get',
  dataType: 'json',
  data: { id: 1 },
  beforeSend: function (xhr) {
    console.log('before send')
  },
  success: function (data) {
    console.log(data)
  },
  error: function (xhr) {
    console.log(xhr)
  },
  complete: function (xhr) {
    console.log('request completed')
  }
})

常用选项参数介绍:

  • url:请求地址

  • type / method:请求方法,默认为 get

  • data:需要传递到服务端的数据。字符串和对象均可。如果是对象会自动拼接成字符串

  • success:请求成功之后触发

  • cache: 设置ie浏览器的缓存问题。默认为true,表示缓存。 cache: false 不缓存。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RXPLp7KP-1581995138732)(ajax讲义.assets/1559188688467.png)]

  • dataType:预期服务端返回的数据方式。如不指定,它会自动判断。

  • contentType:请求体内容方式,默认 application/x-www-form-urlencoded

  • timeout:请求超时时间。

  • beforeSend:请求发起之前触发

  • complete:请求完成触发(不管成功与否)

  • error:请求失败触发

  • processData:boolean。是否让jquery帮助处理传到服务器的数据

$.ajax方法的简便用法
  • $.get()
  • $.post()
  • $.getJSON()
$.get的格式

对于比较简单的get请求,jquery提供了一个快捷方法$.get()

$.get(url,[,data][,success]);
参数:
 - url     :字符串方式。指要请求的 URL 地址。
 - data    : js对象,或者字符串方式。 可选的。 指发请求带给服务器的信息。
 - success : function(result){} 。 可选的。它是一个回调函数,当请求成功时被自动调用,它的第一个参数是从服务器返回的数据。
$.post的格式
$.post(url,[,data][,success]);
参数:
- url     :字符串方式。指要请求的 URL 地址。
- data    : js对象,或者字符串方式。 可选的。 指发请求带给服务器的信息。
- success : function(result){} 。 可选的。它是一个回调函数,当请求成功时被自动调用,它的第一个参数是从服务器返回的数据。
$.getJSON
$.getJSON(url,[,data][,success]);
参数:
 - url     :字符串方式。指要请求的 URL 地址。
 - data    : js对象,或者字符串方式。 可选的。 指发请求带给服务器的信息。
 - success : function(json){} 。它是一个回调函数,当请求成功时被自动调用,它的参数是从服务器返回的JSON数据。

axios库

jquery中封装了ajax功能,但是它的体积比较大。如果我们只希望使用ajax功能,而不需要dom操作的话,我们可以选择使用axios库。(fetch)

应用:

- 它只专注于处理http请求,比jquery的体积小的多,适用于只需要ajax请求的业务场景;
- 后期学习三大前端框架时也会用到;
使用示例

通过官网查看其使用方法。

与jquery一样,要使用它,必须先引入这个文件。然后就可以按如下的格式去使用了。

中文网站:<http://www.axios-js.com/zh-cn/docs/

// 获取服务器的返回值
axios.get('/common/get?id=123').then(function(res) {
    // res 就是本次请求的信息
    console.info(res);
    // 获取 从服务器返回的数据
    console.info(res.data);
});

axios.get('/common/get', { params: { id: 123, name: 'jake' } }).then(function(res) {
    // res 就是本次请求的信息
    console.info(res);
    // 获取 从服务器返回的数据
    console.info(res.data);
});

// post请求,不带参数
axios.post('/common/post').then(function(res) {
    console.info(res.data);
});
// post请求,带参数
axios.post('/common/post', { id: 123, name: 'jake' }).then(function(res) {
    console.info(res.data);
});
是什么

​ Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。相比jquery它只专注于ajax请求。

  • 特性
    • 从浏览器中创建 XMLHttpRequests
    • 从 node.js 创建 http 请求
    • 支持 Promise API
    • 拦截请求和响应
    • 转换请求数据和响应数据
    • 取消请求
    • 自动转换 JSON 数据
    • 客户端支持防御 XSRF

XMLHttpRequest 2.0

XMLHttpRequest 2.0(2012年)中的新增功能一些功能我们重点给大家介绍如下两个内容:

https://xhr.spec.whatwg.org/

  • responseType
  • FormData

responseType / response

responseType:响应类型。表示对从服务器端回来数据的期待,即我们希望从服务器回来的数据是什么类型的。

使用场景

在前面使用原生的ajax过程中,我们提到了从服务器端获取的数据一般从xhr.responseText中获取,而这个值一般情况下是一个json字符串,所以我们要使用JSON.parse()来转一下这个字符串。

但是,如果已经确切地知道了从服务器端回来的数据格式是JSON字符串,那么我们在发出ajax请求之前,提前去设置xhr.responseType属性值,这样得到的数据就可以直接从xhr.response中拿了。

如果你已经能够知道从服务器中返回的数据类型,就可以通过:

  1. 预先设置xhr.responseType = “类型名”
  2. 直接从xhr.response中拿结果
基本介绍
  • responseType – 预期服务器返回数据的类型
    • “” – 空,表示文本,和text一样。空为默认值
    • text – 文本
    • json – JSON格式数据
    • document – 文档对象
  • response – 根据responseType的值自动处理返回结果,可以接收任何类型的结果
示例
var xhr = new XMLHttpRequest();
      xhr.open('get', 'common/get?id=123&name=jake');
      xhr.send();
      xhr.responseType = 'json';
      xhr.onload = function() {
        // responseText
        // 只有当responseType是"" 或者是"text"时才只可以使用;
        // console.info(typeof xhr.responseText);
        // console.info(JSON.parse(xhr.responseText));
        console.info(typeof xhr.response);
        console.info(xhr.response);
      };
  • 不需要再次对xhr.responseText进行转换
  • 不能再使用xhr.responseText,会报错。应该使用xhr.response

FormData

FormData:表单数据(官方api参考)。故名思义,它是用来处理html中与表单数据相关的操作的。

在ajax的使用过程, 一般先要收集用户的信息,然后再把信息通过post(或者get)的方式传递到后端。FormData的使用就是在收集用户信息这个部分。

它主要有如下两个使用场景:

  • 快速收集form表单中元素的信息,减少表单元素的拼接,提高工作效率
  • 上传文件
快速获取表单中的元素值

静态页面代码


<form id="myform">
    <div>
        <label for="">姓名</label>
        <input type="text" id="userName" name="userName" />
    </div>
    <div>
        <label for="">密码</label>
        <input type="password" id="userPassword" name="userPassword" />
    </div>
    <div>
        <label for="">性别</label>
        <input
               type="radio"
               id="genderMale"
               name="userGender"
               value="male"
               /><input
               type="radio"
               id="genderFemale"
               name="userGender"
               value="female"
               /></div>
    <div><button id="btn" type="button">注册</button></div>
</form>
不用FormData
document.getElementById('btn').onclick = function() {
    //收集用户信息
    var userName = document.getElementById('userName').value;
    var userPassword = document.getElementById('userPassword').value;
    var userGender = '';
    if (document.getElementById('genderMale').checked) {
        userGender = 'male';
    } else if (document.getElementById('genderFemale').checked) {
        userGender = 'famale';
    }
    console.info(userName, userPassword, userGender);

    // 通过post传值
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'json';
    xhr.open('post', 'common/post');
    xhr.setRequestHeader(
        'Content-type',
        'application/x-www-form-urlencoded'
    );
    xhr.send(
        `userName=${userName}&userPassword=${userPassword}&userGender=${userGender}`
    );
    xhr.onload = function() {
        console.info(xhr.response);
    };
};
使用FormData
document.getElementById('btn').onclick = function() {
    //收集用户信息
    var fd = new FormData(document.getElementById('myform'));
    // 通过post传值
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'json';
    xhr.open('post', 'common/post');
    // 不用设置请求头 
    // xhr.setRequestHeader(
    //   'Content-type',
    //   'application/x-www-form-urlencoded'
    // );
    xhr.send(fd);
    xhr.onload = function() {
        console.info(xhr.response);
    };
};

要注意:

  • FormData对象内部有一个键值对集合,其中的键名就是表单元素的name属性名,而值就是这个表单元素当前的值。
FormData对象的api

https://developer.mozilla.org/zh-CN/docs/Web/API/FormData

var fd = new Formdata();
fd.append(key,value);
// 向 FormData 中添加新的属性值,如果FormData 对应的属性值存在则覆盖原值,否则新增一项属性值。
fd.delete(key);
// 从 FormData 对象里面删除一个键值对。
fd.entries()
// 返回一个包含所有键值对的iterator对象。
fd.get(key)
//返回在 FormData 对象中与给定键关联的第一个值。
fd.getAll(key)
//返回一个包含 FormData 对象中与给定键关联的所有值的数组。
fd.has(key)
//返回一个布尔值表明 FormData 对象是否包含某些键。
fd.keys()
//返回一个包含所有键的iterator对象。
fd.set(key,value)
//给 FormData 设置属性值,如果FormData 对应的属性值存在则覆盖原值,否则新增一项属性值。
fd.values()
//返回一个包含所有值的iterator对象。

自定义键值对

上面的案例中,我们是从表单中快速获取所有的表单元素的值,并以键值的形式保存在FormDate对象中。除了这种方法之外,还可以手动决定收集哪些值,或者额外添加哪些值。

//   使用FormData
document.getElementById('btn').onclick = function() {
    //收集用户信息
    var fd = new FormData();
    // 数据在FormData内部是以键-值对的格式存在的.
    // 获取:值
    // 格式: fd.get(键名 )

    // 向fd中追加一个键值对
    fd.append('userName', document.getElementById('userName').value);
    fd.append(
        'userPassword',
        document.getElementById('userPassword').value
    );
    var userGender = '';
    if (document.getElementById('genderMale').checked) {
        userGender = 'male';
    } else if (document.getElementById('genderFemale').checked) {
        userGender = 'famale';
    }
    fd.append('userGender', userGender);

    //console.info(fd.get('email'));

    // 通过post传值
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'json';
    xhr.open('post', 'common/post');
    // 不用设置请求头
    // xhr.setRequestHeader(
    //   'Content-type',
    //   'application/x-www-form-urlencoded'
    // );
    xhr.send(fd);
    xhr.onload = function() {
        console.info(xhr.response);
    };
};
简单上传文件

在浏览器端,文件上传功能可以通过很简单的代码就能实现,而复杂的地方在服务器端。黑盒服务器已经预制了一个接口,可以用来上传文件。接口名地址是:formdata/upload

使用这个接口有两点注意:

  • 这个接口只能接收formdata对象,并且你上传的文件信息必须是保存在名为file的键中。也就是说input 的name值必须是file 。

  • app.exe的同级目录下必须有upload文件夹。这个文件夹就是用来保存上传的文件的。

核心代码如下:

<div class="container">
      <h1>FormData文件上传</h1>
      <form id="myForm">
        <label for="">请选择你要上传的文件</label>
        <input type="file" name="file" />
      </form>
      <div>
        <button id="btn">上传</button>
      </div>
    </div>

    <script>
      document.getElementById('btn').onclick = function() {
        var fd = new FormData(document.getElementById('myForm'));
        var xhr = new XMLHttpRequest();
        xhr.open('post', 'formdata/upload');
        xhr.onload = function() {
          console.info(xhr.responseText);
        };
        xhr.send(fd);
      };
    </script>
上传文件进度条onprogress

这个案例是在上一个案例的基础上进行拓展:让上传文件的过程可视化。

核心:

  • xhr对象中有一个子对象upload,upload对象中有一个事件 onprogress。
  • onprogress事件大约每100ms触发一次,其回调函数第一个参数是一个事件对象,这个事件对象中有两个属性 loaded 和 total
    • loaded:表示已上传文件的大小
    • total: 表示文件总大小

实现思路:

  • 制作进度条,使用两层嵌套的div即可:第一层是进度条的外边框,第二层才是进度条

  • 每次onprogress事件触发时:

    • 都计算当前已上传文件大小的百分比
    • 根据百分比去重绘进度条长度(宽度值可以是百分比值)

参考资料:静态页面中的样式

.outer {
    height: 20px;
    background: #171b3c;
    border-radius: 20px;
    box-shadow: 0 2px 2px #4f4c4c;
    margin-bottom: 40px;
    position: relative;
}
.inner {
    position: absolute;
    border-radius: 20px;
    width: 0%;
    height: 20px;
    background: #ef2d56;
}

参考资料:核心代码

document.getElementById('btn').onclick = function() {
    var innerDom = document.getElementById('inner');
    var fd = new FormData(document.getElementById('myForm'));
    var xhr = new XMLHttpRequest();
    xhr.open('post', 'formdata/upload');
	xhr.onload = function() {
        console.info(xhr.responseText);
    };
    xhr.upload.onprogress = function(ev) {
        console.info(Date.now());
        // 已上传 / 总大小
        console.info((ev.loaded / ev.total) * 100 + '%');
        // 设置百分比值
        innerDom.style.width = (ev.loaded / ev.total) * 100 + '%';
    };
    xhr.send(fd);
    
};

综合案例 - 会员管理

目标:实现一个相对复杂的功能

  • 会实现无限加载
  • 会用$.ajax发ajax请求
  • 会用postman

内容

  • 项目整体介绍
  • postman使用
  • 项目实现

基本介绍

项目功能介绍
  • 添加会员
  • 删除会员
  • 查看会员列表
  • 查看会员详情
  • 会员列表(无限加载)
项目的开发要点
  • 前后端分离开发
  • 前端使用bootstrap+ jquery
  • 使用postman对接口进行测试
  • 后端准备好相关接口以供前端调用
项目接口列表
  • list
  • list-last
  • detail
  • delete
  • add
接口名:list

url: /member/list

功能: 取出全部会员信息

类型: get

参数:无

返回值:取到的记录列表

接口名:list-last

url: /member/list-last

功能: 取出从当前记录(last)之后的6条记录

类型: get

参数:

​ - last: 指定的从哪条记录(id号)开始取 。如果不设置值,就取最新的6个成员

返回值:取到的记录列表

示例: member/list-last?last=100 。获取编号为100之后的6条数据

接口名:detail

url: /member/detail

功能: 获取指定编号的会员详情

类型: get

参数:

​ - id: 会员的编号。必传。

返回值:会员详情。

接口名:delete

url: /member/delete

功能: 删除指定编号的会员

类型: post

参数:

​ - id: 会员的编号。必传

返回值:无

接口名:add

url: /member/add

功能: 添加会员

类型: post

参数:

- name: 名字
- avatar: 头像文件,是一个图片文件
- bio: 介绍

返回值:{}

注意:必须要确保在public下面有一个upload文件夹

postman

对于get类型的接口,我们可以直接在地址栏中输入地址去发请求,对于post请求,测试起来就不方便了。这种情况下,我们就需要专业的接口测试工具了,这里给大家推荐postman。

  • 对后端提供的接口进行测试;
  • 前端必备工具;

基本操作

  1. 下载,安装
  2. 启动
  3. 测试接口

要点:

  • 选择参数

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2lksBzee-1581995138736)(ajax讲义.assets/1561186856276.png)]

查看会员详细信息
  • 整体分析
    • 流程分析
    • 接口测试
  • 从url中取值
  • 发送请求,更新页面元素
删除会员

思路:

  • 给每个删除链接上,补充成员id。
  • 给每个删除链接上,补充’href=“javascript:;”’,这样可以阻止默认的跳转事件。
  • 给弹出框中的删除按钮添加点击事件
    • 获取上面的label中的id。
    • 发ajax请求,进行删除

重点代码:

  1. 取消a标签的跳转动作
<a href="javascirpt:;" />
  1. 添加事件委托

    问题描述:元素是动态生成的,无法直接给元素添加点击事件。解决方法:给其父元素添加事件监听。由于元素上的事件具有冒泡特性:在子元素上的点击事件最终也会冒泡到父元素上。所以可以直接在父元素上监听。

$("#parent").on("click",".son",function(){
    // ....
})
新增会员
  • 文件控件

  • 本地图片预览

  • 整体实现

表单中的文件控件
  • multiple:是否可以多选
  • accept:设置默认筛选的格式
<input type="file" multiple />
  • 设置只显示图片

    // 只允许看到jpeg图片
    <input type="file" accept="image/jpeg" />
    // 只允许看到png图片
    <input type="file" accept=".png" />
    // 允许所有的图片
    <input type="file" accept="image/*" />
    

其它类型

文件类型accept属性值类型
*.3gppaudio/3gpp, video/3gpp3GPP Audio/Video
*.ac3audio/ac3AC3 Audio
*.asfallpication/vnd.ms-asfAdvanced Streaming Format
*.auaudio/basicAU Audio
*.csstext/cssCascading Style Sheets
*.csvtext/csvComma Separated Values
*.docapplication/mswordMS Word Document
*.dotapplication/mswordMS Word Template
*.dtdapplication/xml-dtdDocument Type Definition
*.dwgimage/vnd.dwgAutoCAD Drawing Database
*.dxfimage/vnd.dxfAutoCAD Drawing Interchange Format
*.gifimage/gifGraphic Interchange Format
*.htmtext/htmlHyperText Markup Language
*.htmltext/htmlHyperText Markup Language
*.jp2image/jp2JPEG-2000
*.jpeimage/jpegJPEG
*.jpegimage/jpegJPEG
*.jpgimage/jpegJPEG
*.jstext/javascript, application/javascriptJavaScript
*.jsonapplication/jsonJavaScript Object Notation
*.mp2audio/mpeg, video/mpegMPEG Audio/Video Stream, Layer II
*.mp3audio/mpegMPEG Audio Stream, Layer III
*.mp4audio/mp4, video/mp4MPEG-4 Audio/Video
*.mpegvideo/mpegMPEG Video Stream, Layer II
*.mpgvideo/mpegMPEG Video Stream, Layer II
*.mppapplication/vnd.ms-projectMS Project Project
*.oggapplication/ogg, audio/oggOgg Vorbis
*.pdfapplication/pdfPortable Document Format
*.pngimage/pngPortable Network Graphics
*.potapplication/vnd.ms-powerpointMS PowerPoint Template
*.ppsapplication/vnd.ms-powerpointMS PowerPoint Slideshow
*.pptapplication/vnd.ms-powerpointMS PowerPoint Presentation
*.rtfapplication/rtf, text/rtfRich Text Format
*.svfimage/vnd.svfSimple Vector Format
*.tifimage/tiffTagged Image Format File
*.tiffimage/tiffTagged Image Format File
*.txttext/plainPlain Text
*.wdbapplication/vnd.ms-worksMS Works Database
*.wpsapplication/vnd.ms-worksWorks Text Document
*.xhtmlapplication/xhtml+xmlExtensible HyperText Markup Language
*.xlcapplication/vnd.ms-excelMS Excel Chart
*.xlmapplication/vnd.ms-excelMS Excel Macro
*.xlsapplication/vnd.ms-excelMS Excel Spreadsheet
*.xltapplication/vnd.ms-excelMS Excel Template
*.xlwapplication/vnd.ms-excelMS Excel Workspace
*.xmltext/xml, application/xmlExtensible Markup Language
*.zipapplication/zipCompressed Archive
本地图片预览

html5 本地预览

文件控件选中图片后,文件控件中会保存图片信息它的files属性中。files属性是一个数组,如果只选中了一张图片,这张图片就放在files[0]中,如选了多张图片,则类似后推。

对于这些文件信息(本例中的文件就是用户选中的图片),我们通过window.URL.createObjectURL()来创建一个临时的路径,这个路径可能是像这样:

blob:http://localhost:3005/fc517910-1300-44f3-a6e8-d52f56f34e4e

你可以通过打一个新的浏览器窗口,并在地址栏中输入这个路径来访问这张图片。注意,它只是临时的,如果你关闭了选中图片的网页,这张图片也将会不可访问。

现在,我们拿到这个临时的url赋值给某一个img标签的src即可。

// input_avatar就是file控件的内容发生变化执行
$('#input_avatar').change(function () {
    // console.log('xxx');
    // 如果没有选择文件,返回
    if (!this.files[0]) return;

    var url = URL.createObjectURL(this.files[0]);
   
    // 设置图片的src
    $('#avatar').attr('src', url);
});
上传功能开发

这里的上传不是一个简单的post请求,它其中包含了文件的上传,在技术选型上我们选择了html5中的FormData,并使用jquery中的ajax方法来实现上传操作。

这里要注意两点:

  1. processData:false

不需要jquery去处理上传数据

  1. contentType:false

jquery会自动给post请求设置请求头,content-type:‘application-x-www-’。这种做法在大多数情况下,都是对的,但是,如果提交的数据是formdata,就不需要去设置了。

// 2. 添加会员
// 2.1 给按钮注册事件  注意,这个是提交按钮
$('#btn_add').click(function () {
    // 2.2 获取用户输入的内容,还有用户选择的文件
    // 2.3 FormData  设置请求体,可以提交二进制数据,可以上传文件
    //     xhr.send(formData);
    var fd = new FormData($("#myform")[0])

    // 2.4 发送请求,添加数据
    $.ajax({
        type: 'post',
        url: '/member/add',
        data: fd,
        processData: false,
        // 不设置content-type,而是当设置了formdata上传文件的时候,xhr对象会自动把content-type设置为multipart/form-data;
        contentType: false,
        success: function (data) {
            // 判断添加是否成功...
            // 2.5 跳转回首页
            location.href = '/';
        }
    });

    // 取消默认行为,不进行表单提交
    return false;
});

案例3:在jquery中使用FormData

<script src="./jquery-1.8.1.js"></script>
<script>
    $('#btn').click(function() {
    // 收集用户信息
    // var fd = new FormData(document.getElementById('myForm'));
    // FormData(必须是一个dom元素) (1)
    var fd = new FormData($('#myForm')[0]);
    console.info(fd);
    console.info(fd.get('userPassword'));
    $.ajax({
        url: 'common/post',
        type: 'post',
        data: fd,
        processData: false, // 不需要jquery去处理数据。 (2)
        contentType: false, // 不需要默认的contentType,而采用FormData自己的 (3)
        success: function(res) {
            console.info(res);
        }
    });
});
</script>

注意:以上三个地方。

加载更多
  • 测试接口

  • 分析加载数据的时机

  • 基本完成

    全局变量来记录最大的last值
    // 注册滚动的事件
    $(window).scroll(function () {
       // 判断当前是否正在加载数据,如果正在加载数据,就不要再次发送请求了
       if (loading) return;
       // 获取文档的高度
      var documentH = $(document).height();
      // 获取浏览器窗口的高度
      var windowH = $(window).height();
      // 文档滚动出去的距离
      var scrollTop = $(document).scrollTop();
      // 判断当前滚动条距离底部的距离是否 <= 100,加载更多数据
      if (documentH - windowH - scrollTop <= 100) {
        // 加载更多
        loadData();
      }
    });
    
  • 优化

    • 不要重复发请求
    • loading效果
    • 数据全部加载完成之后的处理

模板引擎

目标:

  • 理解模板引擎的作用;
  • 会用模板引擎;
作用

​ 把数据生成页面,这个过程叫渲染。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SUJ5N7ko-1581995138737)(D:\prepare\fanyoufu\01-ajax\笔记\讲义.assets\1558772178540.png)]

如果数据结构简单,可以直接通过字符串操作(拼接)的方式处理,但是如果数据过于复杂,字符串拼接维护成本太大,就不太适用,此时就可以使用模板引擎。模板引擎内部支持循环,选择,判断等高级的功能。

模板引擎:

模板引擎实际上就是一个 API,模板引擎有很多种,使用方式大同小异,目的是更容易更高效地将数据渲染到HTML字符串中。

使用模板引擎步骤
  1. 引入template-web.js文件
  2. 定义模板(具体语法可以去官网查看),指定script的id和type属性
  3. 准备数据。(变量,数组等)
  4. 调用template函数,为模板分配数据,template函数有两个参数一个返回值
    1. 参数1:模板的id
    2. 参数2:分配的数据,必须是一个JS对象的形式
    3. 一个返回值:是数据和模板标签组合好的结果
  5. 将 “拼接” 好的结果放回dom容量中
<div id="content">
    <!-- 准备一个存放数据的位置 -->
</div>

<!-- 1. 引入template-web.js -->
<script src="/template-web.js"></script>
<!-- 2. 定义模板(注意script标签的id和type必须指定) -->
<script id="test" type="text/html">
  <h2>{{data}}</h2>
</script>
<script>
    // 3. 替换模板
    // test对应上面script标签的id
    // data对应上面script标签中使用的$data
    var html = template('test', {
        data: 'hello world'
    });
    
    // 4. 将替换好的html放到指定位置
	document.getElementById('content').innerHTML = html;
</script>

注意:

  • 定义模板时的script标签一定好指定id和type
  • tempalte函数语法:var html = template(模板id, Object)
模板语法
输出普通数据(字符串,数值)
// 模块写法
{{ var }}

// template 函数写法
var html = template('id', {
	var: 'hello world'
})

条件
// 模板写法
{{if age > 18}}
	大于18
{{else}}
	小于18
{{/if}}

// template函数写法
var html = template('id', {
    age: 20
});
循环
// 模板写法1
{{each arr}}
	{{$index}} -- 数组的下标
	{{$value}} -- 数组的值
{{/each}}

// 模板写法1
{{each arr item idx}}
	{{idx}} -- 数组的下标
	{{item}} -- 数组的值
{{/each}}

// template函数写法
var html = template('id', {
    arr: ['apple', 'banana', 'orange']
});
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

别动我代码儿

感谢技术精进的你,加油不负韶华

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值