AJAX通信技术汇总(原生/jQuery方法),回调函数

在学习AJAX通信技术之前,强烈推荐大家学习一下阮一峰老师的《javaScript教程》
地址:https://wangdoc.com/javascript/bom/xmlhttprequest.html

浏览器与服务器之间,采用 HTTP 协议通信。用户在浏览器地址栏键入一个网址,或者通过网页表单向服务器提交内容,这时浏览器就会向服务器发出 HTTP 请求。

一 表单提交内容的方式

表单即是form标签,它可以包含文本框,复选框,单选框,提交按钮,作用它可以向服务器提交一段在表单元素里面的标签的内容数据.也就是说将文本框,复选框,单选框的内容提交给服务器.

一般情况下表单元素列表的最后会写个 submit 提交按钮,submit 标签不用写任何JS代码就可以在它被点击后把表单里的内容传给服务器.

注意:只有加了name属性的才能提交到服务器.

<form action="doFile.php" method="POST" 
		<!-- 这里提交的是文件 -->
        <input type="file" name="icon">
        <input id="name" name="name" type="text" placeholder="分类名称">
        <input id="slug" name="slug" type="text" placeholder="slug">
        <input id="submitBtn" type="submit">
</form>

//action属性:指定表单提交的哪里
//method属性: 指定提交的方式

//注意在表单元素form里面,如果提交的内容里面有文件的话,需要加上
//enctype="multipart/form-data"这句代码,否则提交文件是不会成功的

表单提交的一些注意点:

// 1.表单提交默认是get方式,如果需要设置为post,改method的方法就可以了

// 2.如果表单需要上传文件,那么需要加上enctype="multipart/form-data",同时上传文件必须是post的方式来提交

// 3.如果上传的文件用了get方式来提交,只能获取到文件名,不能获取到文件的内容

这样的提交表单的做法缺点是:
1.整个网页都要跳转到action指定的网页.
2.如果action没有指定跳转的页面或则为#,只会刷新当前页.

二 AJAX提交数据的方法:

AJAX 它是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分(局部刷新),而不用刷新整个网页。

2.1 JS原生的AJAX请求

 //封装Ajax函数
    function ajax (para) {
        //创建ajax对象
        var xhr = new XMLHttpRequest();
        //设置请求头
        if(para.type.toLowerCase() == "get" && para.data != undefined) {
        //请求方式为get方式
            para.url += '?' + para.data;
        }
        xhr.open(para.type,para.url);  
        //发送请求
        if(para.type.toLowerCase() == 'post') {
        //请求方式为post方式
            //设置请求头
            xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded');
            //发送数据
            xhr.send(para.data);
        }else {
            xhr.send();
        }
        //监听事件完成
        xhr.onload = function(){
            //这里不能把响应体写死了
            para.success(xhr.responseText);
        }
        
    }

调用原生封装的函数发ajax请求:

//发送get请求
document.getElementById('btn1').onclick = function(){
        ajax({
            type : 'get',
            url : 'a.php',
            data : 'name=rose',
            success : function(obj){
                console.log(obj);
            }
        });
    }

//发送post请求
    document.getElementById('btn2').onclick = function(){
        ajax({
                type : 'post',
                url : 'b.php',
                data : 'name=jack',
                success : function(obj) {
                    var jsonData = JSON.stringify(obj);
                    console.log(jsonData);
                }
        });
    }

//--------------------------------------插播开始----------------------------------------

2.1.1 回调函数的解析

这里着重解释函数success的工作原理:

//调用ajax函数里的写法:
 para.success(xhr.responseText); //这里在调用
//success是对象para的方法,传入的参数是xhr.responseText(响应体)

//传入定义
success : function(obj) {
    var jsonData = JSON.stringify(obj);
    console.log(jsonData);
}

//------上面代码的含义可以这样理解(伪代码)------
para.success(obj = xhr.responseText) {
	//其实obj就是xhr.responseText,相当于把xhr.responseText赋值给obj
    var jsonData = JSON.stringify(obj);
    console.log(jsonData);
}

整体的思路是,在定义ajax()函数的时候,success只是ajax函数里形参对象里面的方法,在定义ajax函数里只是调用success,但是定义success的具体函数体(实现怎样的操作)是后面传参的时候传入的。这样做的好处是:我在定义的时候,**只是暴露出ajax监听后的结果,至于具体怎么操作,便由开发者自己传入进来。**这就是回调函数的精髓所在。

2.1.1.1 回调函数深入理解

可能前面的解释,你很晕来看看这里。

function say (word = 'hello') { //es6写法
  console.log(word);
}

function execute(someFunction, value) {
  someFunction(value);
}

execute(say, "Hello world"); //'hello world'
execute(say); //'hello'
 
//-------上面的代码可以这样理解(伪代码)-------
function execute(someFunction = say, value = 'hello world') {  

//1.先执行参数的赋值,someFunction赋值得到整个say函数, value是传入的参数‘helloworld’
  	
  	say(word = value) { 
  	//2.将value的值赋值给say函数的word参数‘helloworld’
  		console.log(word); 
  		//3.执行say函数的函数体
  	}
}

我们把 say 函数作为execute函数的第一个变量进行了传递。这里传递的不是 say 的返回值,而是 say 本身!

这样一来, say 就变成了execute 中的本地变量 someFunction ,execute可以通过调用 someFunction() (带括号的形式)来使用 say 函数。

当然,因为 say 有一个变量, execute 在调用 someFunction 时可以传递这样一个变量。

上面的代码,其实回调函数的初级版本,我们发现在js里面可以直接传递函数作为参数,那么我们可不可以进阶呢?

2.1.1.2 回调函数升华理解

既然可以传递函数作为参数,那么为什么不把函数直接写在形参里面呢。

function execute(someFunction, value) {
  someFunction(value);
 }

//es6 函数直接写在形参里
execute((word = 'hello')=> console.log(word),'hello worlld');
//es6一下 这种写法是不是很熟悉
execute(function(word){
       console.log(word);
},'hello world');

在JavaScript中,一个函数可以作为另一个函数接收一个参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。

问题来了,上面的代码那么复杂,为什么我们要用这种方法呢?

2.1.1.3 为什么用回调函数

如果程序是同步执行的,我们完全可以用return返回我们想要的值,但是如果程序是异步的呢,比如我们的ajax就是异步,问题在于我们不知道ajax监听事件的函数何时才能拿到响应体xhr.responseText,又不能让程序停下来等ajax执行完之后才继续其他的事情,因为那样太消耗性能。

所以回调函数在这里就起作用了,我不用等你ajax执行完毕后才定义我应该执行的函数,我先提前定义好,直接就传到你需要操作的success方法里,不在关心你何时才能拿到响应体,而是先定义好操作的方法放在你哪里,如果你拿到响应体xhr.responseText去操作它就可以了,而主程序在你等待接收响应体的期间去处理其他同步程序。当你拿到响应体了,主程序再来响应你的操作。

这个就是传说中的 回调 。我们给某个方法传递了一个函数,这个方法在有相应事件发生时调用这个函数来进行 回调,这样的执行效率也会很高 。

//这种回调的办法在nodeJS里面使用的非常多
var http = require("http");

http.createServer(function(request, response) {
	//这里就是一个回调函数
	  response.writeHead(200, {"Content-Type": "text/plain"});
	  response.write("Hello World");
	  response.end();
}).listen(8888);

//定时器也是这样的,回调函数
setInterval(function(i = 0){
        i++; 
        console.log(i); //一直打印0
},1000);

//上面的代码的含义是:
	//1.每隔一秒,就去执行函数 function (i=0) { i++ }
	//2.但是每隔一秒i都被赋值0,因为参数默认值不是传值的,
	//而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。

//--------------------------------------插播结束----------------------------------------

2.2 jQuery发送ajax请求

三种方式:
	$.ajax()
	$.get()
	$.post()
//后面两种与第一种的区别就是不用加type属性
//传入一个对象
$.ajax({
  //请求网址
  url: './data.php',
  //请求类型
  type: 'post',
  //服务器响应数据类型,如果是跨域,可以改成jsonp
  dataType: 'json',
  //发送给服务器的数据(请求体),如果是get请求数据写在url,如果是post才写data属性
  data: { id: 1 },
  //回调函数:响应回来调用的函数
  success: function (data) {
    console.log(data)
  },
  //请求失败触发
  error: function (err) {
    console.log(err)
  }  
})

2.3 jQuery发送ajax的方法来提交表单:

在提交表单的之前,我们需要学习一个FormData 对象.它的作用:表单数据以键值对的形式向服务器发送,这个过程是浏览器自动完成的。但是有时候,我们希望通过脚本完成过程,构造和编辑表单键值对,然后通过XMLHttpRequest.send()方法发送。浏览器原生提供了 FormData 对象来完成这项工作。(可以利用FormData对象来获取表单里面的内容)

FormData语法知识:

var formdata = new FormData(document.querySelector('form'));

FormData()构造函数的参数是一个表单元素,这个参数是可选的。如果省略参数,就表示一个空的表单,否则就会处理表单元素里面的键值对。
注意点:这里是原生的JS方法,所以参数必须也是JS的元素,比如:

var formdata = new FormData($('form'));
//这里不能使用jQuery的元素

FormData 提供以下实例方法(常用):

// 1.FormData.get(key):获取指定键名对应的键值,参数为键名。
如果有多个同名的键值对,则返回第一个键值对的键值。

// 2.FormData.getAll(key):返回一个数组,表示指定键名对应的
所有键值。如果有多个同名的键值对,数组会包含所有的键值。

// 3. FormData.set(key, value):设置指定键名的键值,参数为键名。
如果键名不存在,会添加这个键值对,否则会更新指定键名的键值。如果第二个参数是文件,还可以使用第三个参数,表示文件名。

// 4.FormData.delete(key):删除一个键值对,参数为键名。

// 5.FormData.append(key, value):添加一个键值对。如果键名重复,则会生成两个相同键名的键值对。如果第二个参数是文件,还可以使用第三个参数,表示文件名。

发送前面表单里面的内容:

$('#submitBtn').on('click',function(e){
	//兼容
    e = e || window.event;
    //阻止表单的默认跳转
    e.preventDefault();

    //因为涉及到发送文件所以使用ajax2.0的技术
    var fm = new FormData( document.querySelector('form'));
	//可以查看表单里面提交的内容
    // console.log(fm.get('icon'));
    // console.log(fm.get('name'));
    // console.log(fm.get('password'));
    //发送请求,
    $.post(
      {
        url : 'api/updateProfile.php',
        //因为fm变量获取到了表单元素里所有的内容,那么data属性就可以直接传递fm
        data : fm,
        // 告诉jquery,不要把提交的数据对象解析成字符串形式
        processData:false,
        // 告诉jquery,你不要帮我加请求头,我的fm自己会加
        contentType:false,
        success : function(objStr) {
          if(objStr.trim() == 'ok') {
            //成功
            location.reload();
          }else {
            //失败
            alert('修改失败');
          }
        }
      }
    );
    });
/*
	上述代码中的注意点:
	* 1.必须阻止事件的默认行为,因为submit的默认行为就是提交表单(刷新整个网页),阻止后就可以发送局部请求了.
	* 2.var fm = new FormData( document.querySelector('form'));
	这行代码就把表单里面的内容获取到了,包括文本内容(name),密码内容(password),以及文件内容(icon)
	* 3.因为fm变量获取到了表单元素里所有的内容,那么data属性就可以直接传递fm
*/

其实FormData()方法不只是可以获取表单里的元素,用来提交数据到服务器,更重要的是它可以上传文件.

2.3.1 案例单个输入框发送文件

比如:我们只有一个input输入框,只是用来上传文件,但是它却没有包裹在form表单里面.

//图片预览的功能
<body>
    <input type="file" id="file">

	<img src="" alt="" id="icon">
</body>
</html>

<script>

    document.getElementById('file').onchange = function(){

        //创建请求对象
        var xhr = new XMLHttpRequest();

        //设置请求行
        xhr.open('post','file.php');

        //创建一个FormData对象
        var fm = new FormData();
        //添加一个提交到服务器的参数
        fm.append('icon',this.files[0]);

        //如果用了FormData就不用设置请求头了,因为它内部帮我们设置了
        
        //用了FormData后,直接传递FormData对象
        xhr.send(fm);

        xhr.onload = function(){

            document.getElementById('icon').src = xhr.responseText;
            
        }
    }
</script>

//1. var fm = new FormData();创建的空的表单
//2. fm.append('icon',this.files[0]);将文件的内容追加到formdata对象里.这样就可以利用formdata来提交文件了
//3. fm.append('icon',this.files[0]);中的this.files[0]将
//获取到的第一个文件对象传递给表单

2.4 demo:发送一个请求,请求包括一个表单以及页面的ID号:

//ajax2.0技术
    var fm = new FormData( document.querySelector('form'));
    //因为编辑器里面没有name属性,所以利用append方法将盒子里面的内容
    //添加到fm对象中
    fm.append('content',editor.txt.html());
    
    //将ID也添加到fm对象跟随表单一起发送请求到服务器
    fm.append('id',id);

    //发请求
    $.post(
      {
        url : "api/updatePosts.php",
        //将所有数据放在fm对象中一起提交到服务器
        data : fm, 
        // 告诉jquery,不要把提交的数据对象解析成字符串形式
        processData:false,
        // 告诉jquery,你不要帮我加请求头,我的fm自己会加
        contentType:false,
        success : function(strData) {

         if( strData.trim() == "ok" ){

			//成功的时候,页面跳转
           location.href = "posts.html";
         }else {
	
			//失败时报错
          alert('编辑失败');
         } 
        }
      }
    );
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值