$.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 标签的 srcurl ,即可实现本地图片预览

  • 作用二:加入到 FormData 中,实现文件上传

    • 创建 FormData 对象:let fd = new FormData()

    • 将文件对象加入到 FormData 中: fd.append('avatar', fileObj)

    • Ajax 提交 FormData 即可完成文件上传

同步任务和异步任务

原理

JS代码分为同步代码和异步代码。目前,我们学习过的异步代码有:

  • 事件

  • 定时器

  • Ajax请求

除此之外,其他所有代码都是同步代码

为什么要把代码分为同步和异步两类呢?因为它们的执行顺序有很大差别。

假设有几段代码,既有同步代码,又有异步代码,他们的执行顺序如下:

  1. 优先执行同步代码

  2. 前一行同步代码没有执行完,后面的代码只能等待,这就是“阻塞”效果。

  3. 遇到异步代码,去排队等待

  4. 所有的同步代码执行完,才去检查是否有异步代码

  5. 如果有异步代码,按顺序执行,但不会有“阻塞”效果。

    1. 异步任务执行前,一般都会提前绑定一个回调函数

    2. 当前的异步任务执行完毕,就会调用提前帮的回调函数

同步的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数据。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐