Ajax 封装

00.原生ajax存在的问题

问题:发送一次请求代码过多,发送多次请求代码冗余且重复

解决方案:将请求代码封装到函数中,发请求时调用函数即可。

关于ajax请求,关心的有:

  1. 请求方式
  2. 请求的地址
  3. 对请求结果的处理

因为在发送每一个请求的时候,以上三个可能都是不一样的。所以,在封装函数的时候,我们需要将代码中不确定的地方作为函数的参数传递进函数当中。

在这里插入图片描述

由图可以看出,在调用ajax函数的时候,传递的是一个对象,这样做的好处是:在查看代码的时候,每一个参数代表什么是非常清晰的。

01. 初步封装一个简单的ajax函数:

10-ajax函数封装.html 中的js代码:

        // 定义一个函数,这个函数用来发送ajax请求
        
        function ajax(options) {
            // 创建 ajax 对象
            var xhr = new XMLHttpRequest()
            
                // 配置 ajax 对象
                // xhr.open('请求方式','请求地址')
            xhr.open(options.type, options.url)
            
                // 发送请求
            xhr.send()
            
                // 监听xhr 对象下面的 onload 事件
                // 当xhr 接收完响应数据后触发
            xhr.onload = function() {
                options.success(xhr.responseText)
            }
        }
        
        
        // 调用 ajax() 函数,需要传递参数
        
        ajax({
            // type 代表请求方式
            type: 'get',
            
            // url 代表请求地址
            url: 'http://localhost:3000/first',
            
            // 具体解释在下面
            success: function(data) {
                console.log('这里是success函数:' + data);
            }
        })

关于 success 函数 以及 onload 事件处理函数的解释

  • success 函数在请求成功的时候调用,因此 要放在 onload 事件处理函数里面
  • 并且我需要在 调用success 函数时传递请求结果 xhr.responseText(实参)
  • 在success函数中,data 是形参
  • 所以:xhr.responseText 传递给 data
  • success 函数体会对参数做处理
  • 如果 没有向 success 函数传递参数,或者说success函数没有参数,则onload 事件处理函 就没有对 请求结果 xhr.responseText进行处理, 这样的函数是没有意义
  • 切记:重要的是要对 请求结果进行处理,所以必须将请求结果作为参数传递

浏览器显示如下:

在这里插入图片描述

02. 对ajax函数作进一步的扩展:

我希望在发送请求的时候,向服务器端传递一些请求参数。

可能会想到,把请求参数直接拼接在请求地址的后面即可。

但是,我们要注意:get方式的请求参数确实是直接拼接,但是post方式的请求参数 需要被放在请求体当中,需要放到send()方法中。

因此,这里要综合考虑


  • 关于 请求参数位置的问题:
    我们要把请求参数传递到ajax函数当中,在函数内部,我们根据请求方式的不同,将请求参数拼接到不同的地方
  1. 如果是get请求,就拼接到请求地址后面
  2. 如果是post请求,就将请求参数放到send()方法中
  • 关于 请求参数格式的问题:
    application/x-www-form-urlencoded : name=zhangsan&age=20
    application/json : {name:‘zhangsan’,age:20}
  1. 传递对象数据类型对于函数的调用者更加友好
  2. 在函数内部对象数据类型转换为字符串数据类型更加方便

改进后的 10-ajax函数封装.html 中的 js代码:

        // 定义一个函数,这个函数用来发送ajax请求
        function ajax(options) {
            // 创建 ajax 对象
            var xhr = new XMLHttpRequest()
            
                // 拼接请求参数的变量
            var params = ''
                /* 接下来 需要将
                 {
                    name: 'zhangsan',
                    age: 20
                }
                    转换成:
                name=zhangsan&age=20  */
                
            // 循环用户传递进来的对象格式参数
            for (var attr in options.data) {
                // 将参数 转换为 字符串格式
                params += attr + '=' + options.data[attr] + '&'
            }
            
            // 将参数最后面的'&'截取掉
            // 将截取的结果重新赋值给params 变量
            params = params.substr(0, params.length - 1)
            
            // 如果请求方式 为 GET ,直接在url后面拼接参数
            if (options.type == 'get') {
                options.url = options.url + '?' + params
            }
            
            // 配置 ajax 对象
            xhr.open(options.type, options.url)
            

            // 如果是 POST,就在send()方法里面传递 请求参数,且需要 设置 xhr.setRequestHeader
            // 如果是 GET ,send()就传递空
            if (options.type == 'post') {
                 // 设置 请求参数格式的类型
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
                
                xhr.send(params)
            } else {
                xhr.send()
            }
            
            // 监听xhr 对象下面的 onload 事件
            xhr.onload = function() {
                options.success(xhr.responseText)
            }
        }
        
        // 调用 ajax() 函数,需要传递参数
        ajax({
            type: 'post',
            url: 'http://localhost:3000/first',
            data: {
                name: 'zhangsan',
                age: 20
            },
            success: function(data) {
                console.log('这里是success函数:' + data);
            }
        })
  

03. 对ajax函数作进一步的完善:

问题一: 可以发现 在“设置请求参数格式的类型”这里,将Content-Type属性的值写成了固定的,如果调用函数的人 想向服务器端传递 json 数据格式的参数,就没办法传递了。

因此;Content-Type属性的值应该是调用函数的人传递进来,然后我们在函数内部再对这个值进行处理。

在这里插入图片描述
进一步完善,如下为部分修改了的代码:

在这里插入图片描述
对应的,在 调用ajax()函数时,多加了一个参数 header,来存放希望的 请求参数格式类型:

在这里插入图片描述

04. 对ajax函数再作进一步的完善:

现在 着眼于 请求成功以后 的代码:
在这里插入图片描述

当onload 事件被触发以后,只能说明当前这次ajax请求完成了,不能代表这次请求一定是成功的。万一服务器端返回了非 200 状态码呢?

所以,在这里,我们 还要对http状态码进行判断,当http状态码等于200 的时候,我们再调用success 函数。如果 http 状态码为 非200, 我们就调用另外一个函数。

这样我们就将处理成功的情况和处理失败的情况进行了分离。

贴上修改后的代码:

在这里插入图片描述

对应的 调用的ajax()函数,其他属性不变,对success进行了修改,增加了error函数:

在这里插入图片描述

05. 对ajax函数再再作进一步的完善:

现在我们已经将请求成功的处理和请求失败的处理进行了分离,接下来呢,我们将注意力放在服务器端的返回结果上。

在使用ajax技术发送请求的时候,大多数情况下,服务器端都会返回 json数据 作为响应内容,但是在客户端,我们拿到的是json对象字符串。

所以,在使用前,我们还要将json字符串转换为 json 对象。这个操作我们要直接封装在函数当中,这样的话,函数的调用者就又少关心了一件事。

但是在这个地方一定要考虑全面。怎么样才能确定服务器端返回的就是json类型的数据呢?万一服务器端返回的就是一串字符呢?

服务器端在返回数据的时候,会在响应头中设置数据的返回类型。我们只需要获取到响应头中设置的这个数据类型,然后对类型进行判断即可。

如果返回的是json类型的数据,我们就对数据进行转换,如果返回的不是json类型的数据,我们就不进行转换了

  • 如何获取响应头中的数据呢?
  • 回答:在xhr对象下面有一个方法,这个方法是 getResponseHeader()
  • 我们可以用其来获取响应头中的数据。
  • xhr.getResponseHeader() 获取响应头中的数据
  • 这个方法接收一个参数:响应头中的属性名称
  • 服务器端的返回类型 在响应头中的属性名称是 Content-Type
  • 因此我们要获取服务器端的返回的数据类型,我们只需要把 Content-Type 传到方法里面即可

修改后的代码:
在这里插入图片描述
对应的ajax()函数调用,因为会将字符串转成对象,所以直接输出即可:

在这里插入图片描述

06. 最后,对ajax函数再再再作进一步的完善:

仍然存在一个问题:我们调用ajax函数的时候,传递了很多参数。如果每次调用ajax()函数都需要传递这么多参数的话,很不方便。

我希望:调用ajax()函数,只需要传递必要的参数就可以了,比如说:请求地址,处理请求成功的回调函数。
没有传递参数的选项应该有一个默认值,不传递就使用默认值:比如说,请求参数的类型,默认是 字符串类型的参数,如果想使用json数据类型的参数,就传递application/json。

实现只需要在函数的内部定义一个对象,对象中存储的数据就是默认参数,如果用户传递了某个参数,就不使用默认值。定义好 defaults 对象后,使用覆盖对象函数Object.assign(),然后把所有的options改成defaults

最后呈现出来的代码:

        // 定义一个函数,这个函数用来发送ajax请求
        function ajax(options) {
        
            var defaults = {
                type: 'get',
                url: '',
                data: {},
                header: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                success: function() {},
                error: function() {}
            }
            
            // Object.assign() 对象覆盖函数
            // 使用options 对象中的属性覆盖defaults 对象中的属性
            Object.assign(defaults, options)
            
            // 创建 ajax 对象
            var xhr = new XMLHttpRequest()
            
               // 拼接请求参数的变量
            var params = ''
            
            // 循环用户传递进来的对象格式参数
            for (var attr in defaults.data) {
                // 将参数 转换为 字符串格式
                params += attr + '=' + defaults.data[attr] + '&'
            }
            
            // 将参数最后面的'&'截取掉
            // 将截取的结果重新赋值给params 变量
            params = params.substr(0, params.length - 1)
            
            // 如果请求方式 为 GET ,直接在url后面拼接参数
            if (defaults.type == 'get') {
                defaults.url = defaults.url + '?' + params
            }
            
            // 配置 ajax 对象
            xhr.open(defaults.type, defaults.url)
            
            // 如果是 POST,就在send()方法里面传递 请求参数,且需要 设置 xhr.setRequestHeader
            // 如果是 GET ,send()就传递空
            if (defaults.type == 'post') {
                // 用户希望向服务器端传递的请求参数的类型
                var contentType = defaults.header['Content-Type']
                
                    // 设置 请求参数格式的类型
                xhr.setRequestHeader('Content-Type', contentType)
                
                // 判断用户希望的 请求参数格式类型
                // 如果类型为 json
                if (contentType == 'application/json') {
                    // 如果请求参数格式类型是  application/json
                    xhr.send(JSON.stringify(defaults.data))
                } else {
                    // 如果请求参数格式类型是  application/x-www-form-urlencoded
                    // 向服务器端传递普通类型的请求参数
                    xhr.send(params)
                }
            } else {
                xhr.send()
            }
            
            // 监听xhr 对象下面的 onload 事件
            xhr.onload = function() {
                // xhr.getResponseHeader() 获取响应头中的数据
                var contentType = xhr.getResponseHeader('Content-Type')
                
                // 服务器端返回的数据
                var responseText = xhr.responseText
                
                // 如果相应类型中 包含 application/json
                if (contentType.includes('application/json')) {
                    // 将 json 字符串转化为 json 对象
                    responseText = JSON.parse(responseText)
                }
                
                if (xhr.status == 200) {
                    defaults.success(responseText, xhr)
                } else {
                    defaults.error(responseText, xhr)
                }
            }
        }
        
        // 调用 ajax() 函数,需要传递参数
        ajax({
            type: 'get',
            url: 'http://localhost:3000/responseData',
            success: function(data, xhr) {
                console.log('这里是success函数:');
                console.log(data);
            }
        })
  • 10
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值