AI智能
改变未来

Ajax学习笔记(包含原生以及JQuery,以及跨域解决方案)


Ajax

Ajax概述

它是浏览器提供的一套方法,可以实现页面无刷新更新数据

  • 应用场景

    页面上拉加载更多数据

  • 列表数据无刷新分页
  • 表单项离开焦点数据验证
  • 搜索框提示文字下拉列表
  • Ajax的运行环境
    Ajax技术需要运行在网站环境汇总才能生效

  • Ajax的实现步骤

    1. 创建Ajax对象

      var xhr = new XMLHttpRequest()
    2. 告诉Ajax请求地址以及请求方式

      //第一个参数为请求方式,第二个参数是请求地址xhr.open(\'get\', \'http://localhost:8000\')
    3. 发送请求

      xhr.send()
    4. 获取服务器端给客户端的响应数据
      监听xhr的

      onload

      事件

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

    服务器端响应的数据格式

    在项目中,服务器端大多数情况下会以JSON对象作为响应数据的格式,当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后将拼接的结果展示在页面中

    在http请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换成对象字符串进行传输

    JSON.parse()//将JSON字符串转换为JSON对象

    请求参数传递

    • GET请求
    //请求参数需要手动拼接字符串xhr.open(\'get\', \'http://localhost:8000/get?name=zhangsan&age=18\')```- POST请求```js//设置请求参数格式类型//setRequestHeader第一个参数是报文属性名称,第二个参数是报文属性对应的值xhr.setRequestHeader(\'Content-Type\',\'application/x-www-form-urlencode\')xhr.send(\'name=zhangsan&age=20\')

    请求参数格式

    1. application/x-www-form-urlencode

      name=zhangsan&age=18&sex=male
    2. application/json

      {name: \'zhangsan\', age: 18, sex: \'male\'}

      在请求头中指定Content-Type属性是application/json,告诉服务器端当前请求参数的格式是json

      JSON.stringify() //将json对象转换为json字符串的方法

    注意:get请求是不能提交json对象数据格式的,传统网站的表单提交也是不支持json对象数据格式的

    Ajax运行原理及实现

    获取服务器端的响应

    • ajax状态码
      在创建ajax对象,配置ajax对象,发送请求,以及接受完服务器端响应数据,这个过程中的每一步都会对应一个数值,这个数值就是ajax状态码

      0:当xhr被实例化出来,状态就是0,。即初始化状态
      1:请求已经建立但是还没有发送,即:send方法还没有被调用,依然可以修改请求头
      2: 请求已经发出去了,即:send方法已经被调用了,不能再修改请求头,响应首行和响应头已经回来了
      3:数据回来了(但是数据可能不完整,如果数据小,会在此阶段直接接受完毕,数据大有待进一步接收)
      4:响应已经完成,数据完全回来了,可以获取并使用

      xhr.readyState //获取ajax状态码
      onreadystatechange//事件监听状态码变化

    ajax错误处理

    1. 网络畅通,服务器端能接受到请求,服务器端返回的救国不是预期结果
      可以判断服务器端返回的状态码,分别进行处理。
      xhr.status

      获取状态码

    2. 网络畅通,服务器没有接受到请求,返回404状态码
      检查请求地址是否错误
    3. 网络畅通服务器端能接受到请求,服务器端返回500状态码
      服务端错误,后端的锅
    //当网络中断时会触发onerror事件xhr.onerror = function(){alert(\'网络中断\')}
    • 低版本ie的缓存问题

      在低版本ie中,ajax有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务端,后续的请求都会从浏览器的缓存中获取结果,几十服务器端的数据跟新了,客户端依然拿到的是缓存中的旧数据

      解决方案:在请求地址的后面加请求参数,保证每一次请求中的请求参数值不相同

      xhr.open(\'get\'.\'localhost:8000/index?t=\' + Date.now())

    Ajax异步编程

    • 概述

      同步:

      上一行代码执行完之后,才能执行下一行代码,代码逐行执行

      console.log(\'before\');console.log(\'after\');

    异步:

    • 异步代码虽然要花时间去执行,但程序不会等到异步代码执行完后再执行后面的代码,而是直接执行后面的代码,当后续代码执行完后,再回头看异步代码是否返回结果,如果已有返回结果,再调用事先准备好的回调函数处理异步代码的执行结果

      console.log(\'before\')setTimeout(()=>{consol.log(\'last\')})console.log(\'after\')

    ajax封装

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

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

    function ajax({type, url, data, header, success, error}){const xhr = new XMLHttpRequest();//定义一个拼接参数的变量let params = \'\';for(let item in data) {//将参数转换成字符串格式params += item  + \'=\' + data[item] + \'&\'}//去掉参数最后面的&符params = params.substr(0, params.length - 1)//如果请求方式为get,将请求参数拼接在url后面if(type == \'get\') {url = url + \'?\' + params;}//配置ajax对象xhr.open(type, url);//如果请求参数为post,设置请求参数格式类型,并在发送请求时将参数传递进去if(type == \'post\') {//用户希望向服务器端传递请求参数的类型const contentType = header[\'Content-Type\'];xhr.setRequestHeader(\'Content-Type\', header[\'Content-Type\']);//判断用户设置的请求参数类型if(contentType == \'application/json\') {//如果是json格式,直接传递参数json字符串xhr.send(JSON.stringify(data))} else {//发送请求xhr.send(params);}} else {//发送请求xhr.send();}//监听xhr对象下的onload事件,当xhr对象接收完响应数据后触发xhr.onload = function(){//获取响应头中的数据const resContentType = xhr.getResponseHeader(\'Content-Type\') //参数为要获取的类型//服务端返回的数据let response = xhr.responseText//判断返回的数据是否是JSON字符串if(resContentType.includes(\'application/json\')) {response = JSON.parse(response)}//判断http状态码,等于200时调用处理成功情况的函数if(xhr.status == 200) {success(response, xhr);} else {//否则调用请求失败的函数error(response, xhr)}}}

    模板引擎

    1. 下载art-template模板引擎并在HTML页面中引入库文件

      <script src=\"./js/template-web.js\"></script>
    2. 准备art-template模板

      <script id=\"tpl\" type=\"text/html\"><div class=\"box\"></div></script>
    3. 告诉模板引擎将哪一个模板和哪个数据进行拼接

      let html = template(\'tpl\',{username: \'zhangsan\', age: 20})
    4. 将拼接好的html字符串添加到页面中

      document.getElementById(\'container\').innerHTML = html

    FormData

    • 作用

        模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数格式
      1. 异步上传二进制文件
    • 使用

      <!-- html中 --><form action=\"\" id=\"form\"><input type=\"text\" name=\"username\"><input type=\"password\" name=\"password\" id=\"\"><input type=\"button\" id=\"btn\" value=\"提交\"></form><script>//获取按钮const btn = document.querySelector(\'#btn\')//获取表单const form = document.querySelector(\'#form\')btn.addEventListener(\'click\',function(){//将普通的html表单转换成表单对象const formData = new FormData(form)//创建ajax对象const xhr = new XMLHttpRequest()//配置ajaxxhr.open(\'post\', \'http://localhost:8000/form\')//发送ajax请求xhr.send(formData)//监听xhr的onload事件xhr.onload = function(){//判断状态码if(xhr.status == 200) {console.log(xhr.responseText)}}})</script>
      //app.js//引入formidableconst formidable = require(\'formidable\')app.post(\'/form\', (req, res)=> {//创建表单解析对象const form = new formidable.IncomingForm()form.parse(req,(err, fields , files)=> {res.send(fields)})})

    formData对象的实例方法

    1. 获取表单对象中的属性值

      formData.get(\'key\') //key是表单name属性的值
    2. 设置表单对象中属性的值

      如果设置的表单属性存在,将替换原有的值
      如果不存在,将会创建这个表单属性

      formData.set(\'key\', \'value\') //key是表单name属性的值,value为将要设置的值
    3. 删除表单对象中的属性

      formData.delete(\'key\')
    4. 向表单对象中追加属性值

      formData.append(\'key\', \'value\')

    **注意:**set方法与append方法的区别是,在 属性名已存在的情况下,set会覆盖已有键名的值,append会保留两个值

    formData二进制文件上传

    <input type=\"file\" id=\"file\"/>
    const file = document.querySelector(\'#file\')//监听表单change事件(用户选择文件的时候)file.onchange = function(){//创建空表单对象let formData = new FormData()//将用户选择的文件追加到formData对象中formData.append(\'attrName\', this.files[[0]])//创建ajax对象let xhr = new XMLHttpRequest()//对ajax对象进行配置xhr.open(\'post\', \'http://localhost/8000/upload\')//发送ajax请求xhr.send(formData)//监听服务端响应给客户端的数据xhr.onload = function(){//判断状态码if(xhr.status == 200) {}}}
    • 文件上传进度展示

      监听xhr对象下的upload下的progress事件,事件对象

      e

      中的loaded代表已上传的文件大小,total代表文件总大小

      <style>#out {width: 800px;height:20px;background-color: rgba(245,245,245,.9);text-align: center;color: red;}#insert {width: 0%;height:100%;background: aquamarine;}</style><form action=\"\"><input type=\"file\" name=\"attrName\" id=\"file\"></form><div id=\"out\"><div id=\"insert\">0%</div></div>
      const file = document.querySelector(\'#file\')const insert = document.querySelector(\'#insert\')//监听表单change事件(用户选择文件的时候)file.onchange = function(){//创建空表单对象let formData = new FormData()//将用户选择的文件追加到formData对象中formData.append(\'attrName\', this.files[[0]])//创建ajax对象let xhr = new XMLHttpRequest()//对ajax对象进行配置xhr.open(\'post\', \'http://localhost:8000/upload\')//监听上传进度信息xhr.upload.onprogress = function(e){let res = parseInt((e.loaded / e.total) * 100) + \'%\'console.log(res);insert.style.width = resinsert.innerHTML = res}//发送ajax请求xhr.send(formData)//监听服务端响应给客户端的数据xhr.onload = function(){//判断状态码if(xhr.status == 200) {}}}

    Ajax请求限制

    1. cookie无法读取
    2. DOM无法获取
    3. Ajax请求可以发送,但响应的数据被拦截
    • 同源策略
      如果连个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源

    JSONP解决跨域

    JSONP(json with padding),是一个非官方的跨域解决方案,只支持get请求,利用的是标签请求资源不受同源策略限制的特点

    步骤:

    <button id=\"btn\">点击发送请求获取数据</button><script>//获取需要监听事件的元素let btn = document.querySelector(\'#btn\')//监听事件btn.addEventListener(\'click\', function(){// 1.动态创建script标签let scriptNode = decument.createElement(\'script\')//2.定义一个处理数据的函数(必须是全局作用域下的函数)window.getData = function(data){console.log(data)}//3.给动态创建的script标签加上请求地址(callback是要使用数据的函数的名)scriptNode.src = \'http://localhost:8000/getData?callback=getData\'//4.将标签放入页面,请求数据document.body.appendChild(scriptNode)})</script>

    关于jsonp解决跨域的说明:

    • 原理:利用了标签发送GET请求“天然跨域”(不受同源策略的限制)
    • 套路:创建script节点,指定src
    • 定义好一个数据处理函数
    • 把数据处理函数的名称传递给后端
    • 后端返回符合js函数调用语法的字符串
  • 局限性:
      只能解决GET请求跨域问题
    • 必须需要后端配合(配合返回调用函数的字符串)

    cors解决跨域(服务端允许跨域请求)

    app.use((req, res, next)=> {//第二个参数为  *  则允许所有网站跨域请求res.header(\'Access-Control-Allow-origin\', \'http://localhost:3000\')//第二个参数为允许的跨域请求方式res.header(\'Access-Control-Allow-Methods\', \'get, post\')next()})

    withCredentials属性

    在使用ajax技术发送跨域请求时,默认情况不会在请求中携带cookie信息(出于对安全性的考虑)

    **xhr下的属性:**withCredentials:指定在涉及到跨域请求时们是否携带cookie信息,默认值为false

    xhr.withCredentials = true

    **服务端响应头:**Access-Countrol-Allow-Credentials:true允许允许发送请求时客户端携带cookie

    res.header(\'Access-Control-Allow-Credentials\', true)

    JQuery中的

    $.ajax()

    $.ajax({type: \'get\',//如果协议、域名、端口,都相同的情况下,不必写完整的请求地址url: \'http://localhost:3000\',//也可以传递字符串参数值,\'name=zhangsan&age=18\'data: {name: \'zhangsan\', age: \'20\'},//如果需要传递JSON格式,将下面设置为\'application/json\'contentType: \'application/x-www-form-urlencoded\',//请求发送之前需要做的事,例如表单格式验证,如果不符将return false,阻止发送请求beforeSend: function(){return false},//请求成功被调用//返回的数据:会根据服务端返回的数据类型,自动转换为相应的类型success: function(response){},//请求失败被调用//接收ajax对象做参数,处理错误信息error: function(xhr){}})

    serialize()方法

    将表单内容拼接成字符串类型的参数

    $(\'#form\').serialize()//username=zhangsan&age=20

    封装将表单内容转换成对象的方法

    function(obj){let result = {};//将表单数据转换成数组,例:[{name: \'username\', value: \'zhangsan\'}, {name: age, value: \'20\'}]let params = obj.serializeArray();//循环这个数组将数组转换成对象$.each(params, function(index, value){result[value.name] = value.value;})return result}

    发送jsonp请求

    $.ajax({url: \'http://localhost:3000\',//代表发送的是jsonp请求dataType: \'jsonp\',//可选参数:修改向服务器传递函数名的参数的名称(默认是callback)jsonp: \'cb\',//可选参数:指定函数名称(一般用不上)jsonCallback: \'fnName\',success: function(response){}})

    $.get()

    $.post()

    //第二个向服务器传递参数的参数为可选参数,可以是字符串或对象$.get(\'http://localhost:3000\', {name: \'zhangsan\'}, function(response){})$.post(\'http://localhost:3000\', {name: \'zhangsan\'}, function(response){})

    ajax全局事件

    只要页面中有Ajax请求被发送,对应的全局事件就会背触发

    //当请求开始发送时触发$(document).on(\'ajaxStart\',function(){})()//当请求完成时触发$(document).on(\'ajaxComplete\',function(){})()

    NProgress进度条插件

    官宣:纳米级进度条,使用逼真的涓流动画来告诉用户正在发生的事

    <!--引入相应的js与css文件--><link rel=\"stylesheet\" href=\"nprogress.css\"><script src=\"nprogress.js\"></script>
    Nprogress.start()//进度条开始运动NProgress.done()//进度条结束运动
  • 赞(0) 打赏
    未经允许不得转载:爱站程序员基地 » Ajax学习笔记(包含原生以及JQuery,以及跨域解决方案)