AJAX

2020-02-06  本文已影响0人  zhchhhemmm

概述

在不刷新页面的情况下更新页面的数据。(布局更新)

应用场景:
运行环境

Ajax技术需要运行在网站环境中才能生效,直接双击html文件运行是没有用的

实现步骤

1 创建Ajax对象

var xhr = new XMLHttpRequest();

2 告诉Ajax请求地址及请求方式

xhr.open('get','http://www.example.com')

3 发送请求

xhr.send();

4 获取服务器端给客户端给客户端响应的数据

xhr.onload = function(){
    //...
    console.log(xhr.responseText);
}
服务器端响应的数据格式

服务器端大多数情况下会以json对象作为响应数据的格式 ,客户端拿到数据后用DOM方法把数据添加到HTML页面中.
问题:服务端响应一个JSON对象时,前端拿到的是一个字符串,而不是JSON
,把JSON字符串转换为JSON对象的方法:

JSON.parse()

示例代码

xhr.onload = ()=>{
            // console.log(xhr.responseText)
            // console.log(typeof xhr.responseText)
            var responseText = JSON.parse(xhr.responseText)
            console.log(responseText)

            var str = '<h2>'+responseText.name+'<h2>'
            document.body.innerHTML = str  
        }
传递请求参数
客户端:
        var btn = document.getElementById("btn")
        var userName = document.getElementById('userName')
        var age = document.getElementById('age')
        btn.onclick = ()=>{
            console.log(userName.value)
            var xhr = new XMLHttpRequest()
            var nameValue = userName.value
            var ageValue = age.value
            var params = "name="+nameValue+'&'+"age="+ageValue
            
            xhr.open('get','http://localhost:3000/requestParameter?'+params)
            xhr.send()
            xhr.onload = ()=>{
                console.log(xhr.responseText)
            }
        }
服务器端:
app.get('/requestParameter',(req,res)=>{
  res.send(req.query)
})

post请求:


image.png
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//格式为: www.example.com?name=xxx&age=xxx....
xhr.setRequestHearder('Content-Type','application/json')
//格式为json字符串
- 将JSON转换成字符串的方法:
JSON.stringify()
- 将JSON字符串转换成JSON的方法
JSON.parse()
Ajax状态码
ajax状态码

onreadystatechange事件
该事件在ajax状态码改变时被触发


image.png
错误处理

1 网络畅通,服务器可以接收到请求,但是服务器端返回的结果不是预期结果
\color{#FF0000}{解决方法:可以判断服务器端返回的状态码,分别进行处理.xhr.status获取http状态码}
2 网络畅通,服务器端没有接收到请求,返回404状态码
\color{#FF0000}{检查请求地址是否错误}
3 网络畅通,服务器端能接收到请求,返回500状态码
\color{#FF0000}{这说明服务器代码出错了,是后端出了问题}
4 网络中断,请求无法发送到服务器端
\color{#FF0000}{这种情况不会触发xhr的onload事件,而是触发onerror事件,}
\color{#FF0000}{应该在onerror事件处理函数中对这种错误情况进行处理}

低版本IE浏览器中的缓存问题

在低版本的IE浏览器中,如果我们向服务器的同一个路由下再次发起请求,拿到的其实是上一次请求时的数据,这是因为在低版本的IE下,新的请求并没有发出,我们拿到的是浏览器的缓存数据

\color{#FF0000}{解决方法:在请求地址后面加上请求参数,保证每次的参数不同}
eg:

xhr.open('get','http://localhost:3000/IEcache?t='+Math.random())
同步异步概述
Ajax封装

问题:发送一次代码过多,真实项目中往往需要发送多个请求,代码比较冗余。
解决方案:把请求代码封装到函数中,发送时调用函数即可。
eg:


截屏2020-02-07下午12.07.52.png

实际代码:

        function ajax(options){
            //转换参数格式,拼接
            var params = ''
            for(attr in options.paramsData){
                params += attr + '=' + options.paramsData[attr] +'&'
            }
            params = params.substr(0,params.length-1) //截取掉最后的&
            console.log(params);
            //init ajax object
            var xhr = new XMLHttpRequest()
            //配置Ajax对象
            if(options.type === 'get'){
                options.url = options.url + '?' + params
            }
            xhr.open(options.type,options.url)
            if(options.type === 'post'){
                //设置请求参数格式的类型
                xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
                xhr.send(params)
            }else{
                xhr.send()
            }
            //发送请求
            //xhr.send()
            //监听onload事件
            xhr.onload = function(){
                options.success(xhr.responseText)
            }
        }    
        ajax({
            //请求方式
            type:'post',
            //请求地址
            url:'http://localhost:3000/function',
            paramsData:{
                name:'zhangsan',
                age:20
            },
            success:function(data){
                console.log('hh'+data);
                
            }

        })

服务器端返回数据的时候,会在相应头中存放响应的数据类型,以供前端开发人员操作

xhr.getResponseHeader()
//获取相应头中的数据

还有,我们应该只强制要求用户传递几个必要参数,而没有传递参数的地方,应该留有默认值。
解决的办法,再函数中定义一个对象,用来存放默认值,如果用户传递了参数,就用用户传递的,如果用户没有传递,那么就取出默认值
完整版如下:

        function ajax(options){
            //声明默认参数
            var defaults = {
                type:'get',
                url:"",
                paramsData:'',
                header:{
                    'Content-Type':'application/x-www-form-urlencoded'
                },
                success:function(){},
                error:function(){},
            }
            //对象覆盖

            Object.assign(defaults,options)
            
            
            //转换参数格式,拼接
            
            var params = ''
            for(attr in defaults.paramsData){
                params += attr + '=' + defaults.paramsData[attr] +'&'
            }
            params = params.substr(0,params.length-1) //截取掉最后的&
            //console.log(params);
            //init ajax object
            var xhr = new XMLHttpRequest()
            //配置Ajax对象
            if(defaults.type === 'get'){
                defaults.url = defaults.url + '?' + params
            }
            xhr.open(defaults.type,defaults.url)
            if(defaults.type === 'post'){
                //设置请求参数格式的类型
                var contentType = defaults.header['Content-Type']
                xhr.setRequestHeader('Content-Type',contentType)
                //判断用户期望的请求参数格式的类型
                if(contentType === 'application/json'){
                    xhr.send(JSON.stringify(defaults.paramsData))
                }
                else  {xhr.send(params)}
            }else{
                xhr.send()
            }
            //发送请求
            //xhr.send()
            //监听onload事件
            xhr.onload = function(){
                var responseText = xhr.responseText
                //查看服务器返还的数据的类型
                var contentType = xhr.getResponseHeader('Content-Type')
                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({
            //请求方式
            type:'post',
            //请求地址
            url:'http://localhost:3000/function',
            // paramsData:{
            //     name:'zhangsan',
            //     age:20
            // },
            // header:{
            //     'Content-Type':'application/json'
            // },
            success:function(data,xhr){
                console.log(data);
                
            },
            error:(data,xhr)=>{
                console.log(data)
                console.log(xhr);
                
            }
        })
Ajax请求限制

Ajax只能向自己的服务器发送请求,如果想要获取的数据是在别的服务器上的,就是不被允许的

什么是同源:
如果两个页面拥有相同的协议,域名和端口,那么这两个页面就属于同一个源,其中只有有一个不相同,就叫不同源。
不同源的网站之间是不允许发送Ajax请求的。

使用JSONP解决同源限制问题

JSONP是json with padding的缩写,它不属于Ajax请求,但是可以模拟出ajax的效果(需要前后端配合)
1 将不同源的服务器端请求地址鞋子script标签的src属性中
就好比,用script标签引入jquery,就是从外部服务器获取的数据
2 服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
eg:

const data = 'fn({name:"zhangsan",age:"14"})';
res.send(data)

3 在客户端全局作用域下准备好函数的定义,且要写在script标签的前面
function fn(data){}
4 在函数内部对服务器返回的具体数据进行处理

动态发送jsonp:用JS代码生成JS标签,然后追加到页面当中。

优化:应该想办法封装jsonp的代码
一个封装后的jsonp函数参考

function jsonp(options){
    //动态创建script标签
    var script =  document.createElement('script')
    //生成随机的函数名 math.random生成的是0-1的随机小数,把小数点替换成空
    var fnName = 'myJsonp'+Math.random().toString().replace('.','')

    //他已经不是全局函数了,要想办法把它变成全局的(options.success)
    window[fnName] =  options.success
    var params = ''
    for(var attr in options.data){
        params+='&'+attr+'='+options.data[attr]
    }
    //为标签添加src属性
    
    script.src = options.url + '?callback='+fnName+params
    //把标签追加到页面
    document.body.appendChild(script)
    script.onload = function(){
        document.body.removeChild(script)
    }
}

如果服务是express启动的,可以直接这样返回请求数据

res.jsonp({name:'lisi',age:13})

$.ajax()

这是Jquery封装好的方法
作用:发送ajax请求
用法:


image.png

除此之外,还可以用$.get()或者 .post()方法;

            $.get('http://example.com',{name:'zhangsan',age:12},function(data){})
            $.post('http://example.com',{name:'zhangsan',age:12},function(data){})
serialize方法:

作用:
将表单中的数据自动拼接成字符串类型的参数。
formData也提供了解决这个问题的方案,不过他是HTML5才支持的,老版本的浏览器并不适配。

var params = $('#form').serialize();
// name=zhangsan&age=20

还有一个方法:
serializeArray();
返回的是一个数组,数组的每一项都是一个对象
jquery的Ajax全局事件
.ajaxStart() // 当请求开始时触发
.ajaxComplete //当请求完成时触发
用法:
//    当页面中有ajax请求发送时触发,另一个类似
$(document).on('ajaxStart',function(){})

Nprogress插件用进度条,涓流动画来告诉用户真正发生的事情

http://ricostacruz.com/nprogress/

var btn = document.getElementById('btn')
        btn.onclick = function(){
            $.get('/index',function(data){console.log(data);
            })
        }

        $(document).on('ajaxStart',function(){
            NProgress.start()
            console.log('start');
            
        })
        $(document).on('ajaxComplete',function(){
            NProgress.done()
            console.log('end');
            
        })
//注:一开始写的是原生的ajax,$(document).on('ajaxStart',function(){})
//并没有进入回调函数,也就是说,并没有触发事件,但是可以成功得到服务器的响应。。。。
上一篇 下一篇

猜你喜欢

热点阅读