AJAX

作者: zhchhhemmm | 来源:发表于2020-02-06 19:53 被阅读0次

    概述

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

    应用场景:
    • 实现页面上拉加载更多数据
    • 列表数据无刷新分页
    • 表单项离开焦点数据验证(避免如邮箱重复等造成用户重新填写整个表单)
    • 搜索框提示文字下拉列表
    运行环境

    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  
            }
    
    传递请求参数
    • 传统表单网站 : 请求参数需要通过表单的方式来传递.
      get请求的参数格式:
      www.example.com?参数名称=参数值&参数名称=参数值....

      image.png
    • Ajax中
      get请求

    客户端:
            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,一般会有回调函数
    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(){})
    //并没有进入回调函数,也就是说,并没有触发事件,但是可以成功得到服务器的响应。。。。
    

    相关文章

      网友评论

          本文标题:AJAX

          本文链接:https://www.haomeiwen.com/subject/ztgpthtx.html