$.ajaxPrefilter()
-
作用
-
在发送ajax请求前,可以使用
$.ajaxPrefilter()
修改ajax选项 或 增加新的选项。
-
-
特点
-
需要在发送请求前,调用
$.ajaxPrefilter()
-
调用
$.ajaxPrefilter()
之后,后续的所有Ajax请求(不包括原生的)都会被影响
-
-
语法
// 统一配置Ajax选项 $.ajaxPrefilter(function (option) { // option 表示Ajax请求的配置选项 // 这里可以增加新的配置项,也可以修改一些配置项 option.url --- 得到当前Ajax请求的url option.type --- 得到当前请求的type ...... })
jQuery方法请求参数的本质
jQuery的默认转换
无论使用 $.get()
还是 $.post()
还是 $.ajax()
方法,都可以设置请求参数,即 data
。示例如下
-
$.get('url',
data
, function (res) { ... }) -
$.post('url',
data
, function (res) { ... }) -
$.ajax({
data
: { id: 1 } })
实际上,在使用 jQuery 的上述三个方法的前提下,我们不但可以使用对象形式的参数,也能使用数组或者查询字符串,示例如下:
// 这里使用 $.ajax() 举例,另外两个方法同理 $.ajax({ url: 'http://www.itcbc.com:3006/api/getbooks', // 对象形式的写法 data: { id: 1, appkey: '13200008888' } // 数组形式的写法,注意,只能是这种写法 data: [{ name: 'id', value: 1 }, { name: 'appkey', value: '13200008888' }] // 字符串写法,注意,这种类型的字符串,叫做查询字符串 data: 'id=1&appkey=13200008888' })
无论我们填写的何种形式的参数,都会被jQuery转换成查询字符串形式传递到服务器。
如果不希望jQuery转换数据的格式,则可以通过 processData: false 指定。
jQuery方法的底层实现
当jQuery把参数转换成查询字符串后,是拼接到url后面呢?还是当做 send() 的参数呢?
-
xhr.open('请求方式', 'url?查询字符串') ------ jQuery的底层是这样拼接?
-
xhr.send('查询字符串') ------ 还是 当做请求体使用呢?
jQuery也是根据请求方式来区分的
-
如果是GET方式,jQuery会把查询字符串拼接到 url 后面
-
如果是其他方式(POST|PUT|DELETE),jQuery会把查询字符串当做请求体使用,也就是放到 xhr.send() 里
serialize和serializeArray方法
☞ 思考一个问题,添加书籍的时候,是如何获取输入框的值的?
答:一个一个获取的。
☞ 思考,如果输入框特别多,而且还有下拉框,单选按钮组、复选按钮组,又该如何获取这些值呢?
答:确实,jQuery提供的 serialize()
或者 serializeArray()
方法获取表单各项的值。这一点和 FormData 比较像。
语法:
$('form').serialize(); $('form').serializeArray();
也就是说,使用 serialize()
或者 serializeArray()
方法是通过 表单(form) 调用的,所以必须在HTML页面中加入 <form>...</form>
标签。如下所示:
<form> <!-- 把所有的框框、按钮都放这里面 --> <input type="text" name="bookname" /><br /> <input type="password" name="pwd" /><br /> <input type="radio" name="sex" value="nan" checked />男 <input type="radio" name="sex" value="nv" />女<br /> <select name="address"> <option value="bj">北京</option> <option value="sh">上海</option> </select><br /> <button>提交</button> </form>
接下来,就可以使用 serialize()
或者 serializeArray()
方法 获取全部的值了,代码如下:
// 监听表单的 submit 事件 (表单提交时触发) $('form').on('submit', function (e) { // 一定阻止表单提交,否则页面会跳转;默认跳转到当前页面,感觉和刷新一样 e.preventDefault(); // 保证页面不会跳转,接下来使用 serialize 获取表单数据 var str = $(this).serialize(); var arr = $(this).serializeArray(); });
小结:
-
在必须具有
<form>...</form>
标签的前提下,才能使用serialize()
或者serializeArray()
方法 -
各项表单元素(input、select、textarea)必须具备
name
属性,和FormData一样。 -
通过
serialize()
得到的是查询字符串类型;通过serializeArray()
得到的是数组类型。在jQuery中,两种结果都可以直接当做Ajax请求的参数。 -
两个方法均不能获取 禁用状态(disabled)的输入框的值,和FormData一样。
-
两个方法均不能获取文件域(
<input type="file" />
)的值,这一点和FormData不一样。 -
两个方法都能获取隐藏域(
<input type="hidden" />
)的值,和FormData一样。 -
FormData属于原生的代码,收集的结果是FormData对象;serialiaze和serializeArray是jQuery封装的方法,收集的结果会被jQuery转成查询字符串;
可以使用上述方法(
$.ajaxPrefilter
|$('form').serialize()
|$.ajax()
),重做图书管理案例
jQuery提交FormData
使用方法
<form action=""> 姓名:<input type="text" name="username"><br> 年龄:<input type="text" name="age"><br> 身高:<input type="text" name="height"><br> <button>提交</button> </form> <script src="./jquery.js"></script> <script> $('form').on('submit', function (e) { e.preventDefault(); // 使用FormData收集数据 var fd = new FormData(this); // 传入DOM对象哟~~~ // 使用$.ajax()提交 $.ajax({ url: 'http://www.itcbc.com:3006/api/formdata', type: 'POST', data: fd, // 这里直接使用FormData processData: false, // 必填项 contentType: false, // 必填项 success: function (res) { console.log(res); } }) }) </script>
processData:
前文讲,jQuery默认会把data转换成查询字符串格式,这里 processData: false
,表示不要把FormData对象转换成查询字符串。因为原生(底层)实现是 xhr.send(fd)
,也是直接提交FormData对象的。
contentType:
前文讲,提交FormData,不能自己设置Content-Type这个请求头,这里 contentType: false
,表示不要设置这个请求头。
带进度条的上传(jQuery版)
-
写基础的代码,实现文件上传
<form> <input type="file" name="avatar"> <button>上传</button> </form> <!-- 设置一个进度条,这里使用h5新标签,开始隐藏 --> <progress max="0" value="0" style="display: none"></progress> <script> $('form').on('submit', function (e) { e.preventDefault(); // 使用FormData收集输入框的值(这里是选择的图片) var fd = new FormData(this); // ajax提交fd对象 $.ajax({ type: 'POST', url: 'http://www.itcbc.com:3006/api/formdata', data: fd, processData: false, contentType: false, success: function (res) { console.log(res); } }); }); </script>
-
加入xhr选项,写原生的代码,实现进度条
-
jQuery没有提供实现进度条的选项,但是提供了一个xhr选项,允许我们写原生的代码。最终实现进度条,还是通过原生的代码实现的。
-
注意:使用xhr选项,必须
return xhr
;
-
$.ajax({ type: 'POST', url: 'http://www.itcbc.com:3006/api/formdata', data: fd, processData: false, contentType: false, success: function (res) { console.log(res); }, /*************************************************/ /*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/ xhr: function () { var xhr = new XMLHttpRequest(); var progress = $('progress'); // 注册上传监听事件 xhr.upload.onprogress = function (e) { progress.attr('max', e.total).attr('value', e.loaded).show() }; return xhr; // 必须返回xhr } /*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/ /************************************************/ });
文件域补充
input标签及属性
-
文件域:
<input type="file" />
-
accept属性:控制能够选择的文件类型,比如
accept="image/png,image/jpeg"
-
multiple属性:控制是否可以多选文件
-
File对象
什么是文件对象
文件对象,是本地文件的一个表示。通俗的说,在JavaScript中,使用文件对象类表示一个本地文件。
如何得到文件对象
通常情况下, 通过文件域的DOM对象,可以获取到选择的文件列表。文件列表中存放了文件对象。
<input type="file" multiple /> <script> // 文件域内容改变的时候,获取文件列表及文件对象 document.querySelector('input').onchange = function () { // 文件列表 (用户选择的文件列表) let fileList = this.files; // 得到一个伪数组,里面存放了一个一个的文件对象 // 获取某个文件对象,得到选择的第一个文件的文件对象,在JS中,使用文件对象表示一个文件 let fileObj = fileList[0]; } </script>
PS:还有其他途径得到文件对象,比如 canvas.toBlob()
方法等。
文件对象有什么用
-
作用一:本地图片预览
-
需要创建一个用于预览的 url :
let url = URL.createObjectURL(fileObj)
-
设置
img
标签的src
为url
,即可实现本地图片预览
-
-
作用二:加入到 FormData 中,实现文件上传
-
创建 FormData 对象:
let fd = new FormData()
-
将文件对象加入到 FormData 中:
fd.append('avatar', fileObj)
-
Ajax 提交 FormData 即可完成文件上传
-
同步任务和异步任务
原理
JS代码分为同步代码和异步代码。目前,我们学习过的异步代码有:
-
事件
-
定时器
-
Ajax请求
除此之外,其他所有代码都是同步代码。
为什么要把代码分为同步和异步两类呢?因为它们的执行顺序有很大差别。
假设有几段代码,既有同步代码,又有异步代码,他们的执行顺序如下:
-
优先执行同步代码
-
前一行同步代码没有执行完,后面的代码只能等待,这就是“阻塞”效果。
-
遇到异步代码,去排队等待
-
所有的同步代码执行完,才去检查是否有异步代码
-
如果有异步代码,按顺序执行,但不会有“阻塞”效果。
-
异步任务执行前,一般都会提前绑定一个回调函数
-
当前的异步任务执行完毕,就会调用提前帮的回调函数
-
同步的Ajax请求(了解)
目前,我们发送的Ajax请求,都是异步请求。但也可以通过修改选项设置Ajax同步请求。下面是一个例子。
console.log(111); $.ajax({ url: 'http://www.itcbc.com:3006/api/getbooks', data: { appkey: 13200008888 }, success: function (res) { console.log(222) }, async: false // 默认true,如果改为false,表示发送 同步 的Ajax请求 }); console.log(333);
同步的Ajax请求了解即可,因为它会阻塞代码的运行,开发中基本不用。
JSON
什么是JSON
JavaScript Object Notation (JSON) 是一种数据交换格式。
JSON在Ajax中的作用
JSON在Ajax请求的过程中,作用就是作为数据的载体。
比如中国人和英国人交流,双方的语言不通,所以必须找一个翻译。
服务端使用的编程语言可能是java、php等,前端使用的编程语言是JavaScript,双方的数据格式可能不一样,所以在交互数据的时候,需要转换成双方都能识别的格式,比如JSON格式。
古老的XML也具有和JSON相同的作用,现在基本不用了。
编写JSON
JSON长得和JS数据差不多,但JSON是字符串类型。比如:
// JS 对象 var obj = { id: 1, name: 'zs' }; // JSON 字符串 var json = '{ "id": 1, "name": "zs" }';
很少直接在JS代码中写JSON。一般都是在JSON文件(
xxx.json
)中写JSON。大部分接口响应的结果都是JSON字符串格式。
编写JSON的具体要求:
-
不允许出现 undefined
-
不允许写注释
-
不能有函数
-
无论是属性名还是字符串类型的值,都必须加双引号。(单引号都不行)
-
JSON中可以包括的数据类型
-
数字
-
字符串(必须加双引号)
-
布尔
-
null
-
数组
-
对象
-
-
一个完整的JSON字符串,前后的括号必须对应,且不能有其他内容。
JSON和JS数据转换
JSON ----> JS
-
var JS数据 = JSON.parse(JSON字符串);
-
这个过程叫做 反序列化
JS ----> JSON
-
var JSON字符串 = JSON.stringify(JS数据);
-
这个过程叫做 序列化
请思考下面的转换:
// ------------------------- 转成JSON格式 -------------------- var obj = { // 这里有一个注释 name: 'zs', age: undefined, sayHi: function () { console.log('Hi~'); } }; console.log( JSON.stringify(obj) ); // '{"name": "zs"}' // 思考,答案是怎样的呢? // ---------------------- JSON转成JS数据 --------------------- var json = 'true123["apple", "orange"]'; var aa = JSON.parse(json); // 报错,因为把三部分JSON格式的字符串放到一起了
封装Ajax
思路:
-
想好了,最终封装成什么样的 --- 封装成和 $.ajax 一样的(简略版)
-
我们希望和调用jQuery的$.ajax方法一样,来调用自己封装的函数,形式如下:
// 假设我们封装了一个 ajax 函数,调用方式如下 ajax({ type: 'GET', url: 'xxxx', data: {}, success: function (res) { // res 表示服务器响应的结果 } });
-
封装函数 ajax,参数只有一个,是对象形式,参照上面的代码
-
函数体
-
基本的Ajax代码(基本的步骤写出来)
-
判断GET和POST请求,分别写 open 和 send 方法
-
处理请求参数,把对象形式的参数处理成查询字符串格式
-
当ajax请求成功之后,调用success函数,把服务器响应的结果当做实参传给success。
-
细节处理(默认GET方式、不区分大小写等等、响应结果是否转换成JS对象...)
-
封装,不可能封装的和jQuery那样强大;通过自己封装,我们能够体会到jQuery中的$.ajax()方法是怎么封装的。
参考代码如下:
/** * 把字面量对象转换成查询字符串 * @param {object} obj 一个字面量对象 * @returns {string} 查询字符串 */ function ObjectToQueryString(obj) { var arr = []; for (var key in obj) { arr.push(`${key}=${obj[key]}`); } return arr.join('&'); } /** * 实现Ajax请求 * @param {object} option 对象形式的参数 * @param {string} option.type 请求方式 * @param {string} option.url 接口地址 * @param {object} option.data 请求参数 * @param {callback} option.success 成功后的回调 */ function ajax(option) { // 1. 把请求方式统一转大写,为后面的判断做准备 var type = option.type.toUpperCase(); // 2. 调用上面的函数,把请求参数处理成查询字符串 var params = ObjectToQueryString(option.data); // 3. 写Ajax的基本步骤 var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { // 当响应成功后,把JSON格式的结果转换为JS对象 var res = JSON.parse(this.responseText); // 把结果,传递给 success 回调函数 option.success(res); } } // 判断是GET还是POST请求方式 if (type === 'GET') { xhr.open('GET', option.url + '?' + params); xhr.send(); } else if (type === 'POST') { xhr.open('POST', option.url); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send(params); } }
封装,没有考虑FormData数据。