Ajax

JavaScript和普通的jQuery都是操作Html标签以及css属性,不能发送接收数据,最多也只是.submit(),
实际发送数据还是Form表单,提交到同一个url,后台view获取数据然后return同一个页面

悄悄发送数据到后台进行处理,并返回结果而页面不刷新,只能通过Ajax实现

一、原生Ajax

Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),
Ajax首次出现IE5.5中存在(ActiveX控件)。

1、XmlHttpRequest对象的主要方法:

		a.	void open(String method,String url,Boolen async)
		   用于创建请求	
		   
		   参数:
			   method: 请求方式(字符串类型),如:POST、GET、DELETE...	#get方式时,xhr.send(null),数据写在url上
			   url:    要请求的地址(字符串类型)
			   async:  是否异步(布尔类型)      #异步发,不影响任何效果
			   
		b. void send(String body)      #对比jQuery的data:
			用于发送请求
		 
			参数:
				body: 要发送的数据(字符串类型)
		 
		c. void setRequestHeader(String header,String value)
			用于设置请求头
		 
			参数:
				header: 请求头的key(字符串类型)
				vlaue:  请求头的value(字符串类型)
		 
		d. String getAllResponseHeaders()
			获取所有响应头
		 
			返回值:
				响应头数据(字符串类型)
		 
		e. String getResponseHeader(String header)
			获取响应头中指定header的值
		 
			参数:
				header: 响应头的key(字符串类型)
		 
			返回值:
				响应头中指定的header对应的值
		 
		f. void abort()
		 
			终止请求

  



终止请求

2、主要属性,如xhr.xxx来使用,不用加括号
a. Number readyState
状态值(整数)

详细:
0-未初始化,尚未调用open()方法,只创建了xml对象;
1-启动,调用了open()方法,未调用send()方法;
2-发送,已经调用了send()方法,未接收到响应;
3-接收,已经接收到部分响应数据;
4-完成,已经接收到全部响应数据;

b. Function onreadystatechange
当readyState的值改变时自动触发执行其对应的函数(回调函数)

这是一个属性,写在open前也可以,只要在创建xhr之后即可

c. String responseText
服务器返回的数据(字符串类型)

d. XmlDocument responseXML
服务器返回的数据(Xml对象)

e. Number states
状态码(整数),如:200、404... 如return HttpResponse(json.dumps(ret),status=404,reason='NOT FOUND')

f. String statesText
状态文本(字符串),如:OK、NotFound...

3、示例:

		function Ajax1() {
            var xhr = getXHR();                        		#一般创建写法var xhr = new XMLHttpRequest()         
            xhr.onreadystatechange = function(){          	#状态码改变时自动执行
                if (xhr.readyState == 4){                 	#状态码
                    var obj = JSON.parse(xhr.responseText);	#转化为json对象,可以理解为字典
                    console.log(obj);
                }
            };
			xhr.open('POST','/ajax_json/',true);
            //xhr.setRequestHeader('k1','v1');               #设置请求头,如csrf
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
															#POST必须按照格式设置文件解析请求头,GET不用设置直接发
            xhr.send('name=root;pwd=123');                	#发送数据

  



4、浏览器兼容问题:

		function getXHR(){
            var xhr = null;
            if(XMLHttpRequest){
                xhr = new XMLHttpRequest();
            }else{
                xhr = new ActiveXObject("Microsoft.XMLHTTP");
            }
            return xhr;

        }

二、jQuery Ajax

内部调用原生XmlHttpRequest,一种浏览器对象,低版本IE没有,有替代的对象active object,jQuery可以用这个替代xml
jQuery 2.x 3.x不支持active object,而1.x支持,兼容性好

1、前端写法:

	$('#ajax_submit').click(function () {
		$.ajax({                           			开始语句
			url: "/test_ajax/",    					提交到哪个url
			type: 'POST',          					提交方式
			data: {'k': 'v', 'list': [1,2,3,4], 'k3': JSON.stringfy({'k1': 'v'}))}, $(form对象).serilize() 
													# 字典不能嵌套字典,可以将字典stringfy传过去
			traditional:true,						# 提交的data中value包括数组时要声明
			
			// dataType:'JSON',						# 后台发送的字符串自动转换为json对象,text\html不作处理,xml能转就转这格式
			// data:$('#add_form').serialize(),   	封装提交更方便
			success: function (data) {       		提交成功后执行函数
				// JSON.parse(data);    			#将字符串转为对象,转字符串是stringfy(),对应前端json.dumps\loads
													#声明dataType:'JSON'后,就不用转换了	
				if(data == 'ok'){
					location.reload()				# 重新加载
					location.href = "某个地址"     	# 跳转,只能在这跳转,不能在视图函数中redirect
				}
				else{
					alert(data);
				}
			},
			error:function(){
				#网络异常,url错误等
			}
		});
	})
		此外还有:
			$.get(url='',data={},success=)
			$.post()                       #内部都是调用ajax方法

  


2、Django序列化与Ajax

通过Ajax发送数据,在返回时,只能返回字符串,故进行序列化

Django发送:

			a.HttpResponse返回字符串时,无需序列化与反序列化
				HttpResponse('ok')
				
			b.返回render渲染模板后生成的字符串,也无需序列化与反序列化
				user_list = models.UserInfo.objects.all()
				return render(request,'get_data.html',{'user_list':user_list})
				
				注:不能return redirect,ajax不受理;而render返回的是渲染好数据的字符串,不用再dumps和parse
			
			c.返回一个普通的字典,定义一个字典用于返回,统一,判断时修改其中的value
				ret = {'status':True,'error':None,'data':{}}
				return HttpResponse(json.dumps(ret))			#只能返回字符串,用dumps序列化为形式字典
				
				注:python中序列化与反序列化是json.dumps\loads(),JavaScript中是JSON.stringfy\parse()
				
					也可以返回JsonResponse(ret)		#django内部执行json.dumps(),只能传字典
					
					JsonResponse([],safe=False),列表也可以,需要传safe=False
				
			d.返回的字典中value是对象的QuerySet时,需要先将对象序列化为字符串,再加入字典中
				from django.core import serializers
				user_list = models.BookType.objects.all()
				ret['data']= serializers.serialize("json", user_list)	#前端需要JSON.parse()转为对象列表即可循环,生成标签等
			
			e.字典中value是字典的QuerySet时,list即可,将QuerySet变成python的list
				user_list = models.UserInfo.objects.all().values('id','username')
				return HttpResponse(json.dumps(ret))
				
			g.字典中value是元组的QuerySet时,list即可,将QuerySet变成python的list
				user_list = models.UserInfo.objects.all().values_list('id','username')
				return HttpResponse(json.dumps(ret))	

  



Ajax发送:

			a.普通的字典
				data: {'k': 'v'}
				
			b.字典value有数组时,需要声明
				data: {'k': 'v'}, 'list': [1,2,3,4]}			
				traditional:true						#声明数组
				
			c.字典value有字典时,需要序列化字典
				data: {'k': 'v'}, 'list': [1,2,3,4], 'k3': JSON.stringfy({'k1': 'v'}))}
				
			d.封装普通表单数据	
				data: $(form对象).serilize() 
			
			f.表单数据有文件时,需要创建FormData对象并声明
				var form = new FormData();      
				form.append('avatar_img', file_obj);
				form.append('csrfmiddlewaretoken','{{ csrf_token }}');
				
				$.ajax({                          		 	
						url: '/avatar_upload.html',
						type:'POST',
						data: form,
						processData: false,  // tell jQuery not to process the data 	#声明1
						contentType: false,  // tell jQuery not to set contentType		#声明2	
						success: function (arg) {              	#这里处理回调数据
							var obj = JSON.parse(arg);    		
							$('#previewImg').attr('src','/' + obj.data);
						}
					})



3、CSRF请求头 X-CSRFToken
全局默认的settings中会更新seetings.py配置,其中csrf有默认设置,字段为HTTP_X_CSRFTOKEN='',HTTP_是django自动
加的前缀,请求头不能包含下划线,这是非法的,后台拿不到数据,X-CSRFTOKEN,官网推荐为X-CSRFToken

方式一:

		$.ajax({
			...
			headers:{'X-CSRFToken':$.cookie('csrftoken')}
		})
		

  



方式二:统一配置一次即可,发送前

		$.ajaxSetup({
			beforeSend:function(xhr,settings){        #xhr为xmlhttprequest对象
				xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'))   #设置csrf
			}
		})

  

4、与Form组件验证的关系
- Ajax提交:验证正确了cleaned_data是一个字典,可以传,但错误信息ErrorDict不是字典,是一个django对象,不能用python的json.dumps序列化。
- 可以as_json化为字典,再as_json化为字符串HttpResponse给浏览器
(常用)- 通过json.dumps定制一个Clis,进行特殊对象的序列化,什么类型取什么值,构造出json对象,返回需要的值

5、与原生Ajax的联系:

$.ajax({
...
success: function (data,a1,a2) { #第一个参数是success,第二个参数为XmlHttpRequest对象,即可调用原生ajax方法写
if(){}
else{}
}
})

三、伪Ajax

1、原理:利用iframe框改src时框跳转,但大页面不刷新,实现不刷新发送请求,而普通的form表单会刷新
兼容性最好
2、iframe标签跳转:

		<input type="text" id="url"/>
		<input type="button" value="发送" onclick="ifm_request();"/>
		<iframe id="ifm" src="http://www.baidu.com"></iframe>             #跳转网页
	
		function ifm_request() {
			var url = $('#url').val();
			// console.log(url)
			$('#ifm').attr('src',url);
		}
		

  



因此,利用iframe实现伪ajax方法,不依赖任何插件

3、iframe实现发送和接收数据

		<form action="/ajax_json/" method="post" target="ifm1">  #target属性让form和iframe建立关系,表单数据通过iframe发送
			<iframe id='ifm1' name="ifm1"></iframe>				 #iframe框,可写在表单外
			<input type="text" name="username" />
			<input type="text" name="email" />
			<input type="submit" onclick="submitForm();" value="提交"/>
		</form>

  



写一个js,当点击提交时,获取发送的数据:

		function submitForm() {
			$('#ifm1').load(function () {
				var text = $('#ifm1').contents().find('body').text(); #contents是整个html,找到body标签
				var obj = JSON.parse(text);                           #text是字符串
			})
		}

  



4.iframe标签的内容:

iframe标签包含的是document对象,相当于上下文,或者空间管理,嵌套了html,innerText、children等无法使用
对象里面有html标签-header\body标签,body标签的文本即返回的字符串

Jquery方式:
通过.contents()拿到html对象
$('#ifm1').contents().find('body').text()\html():文本内容

DOM方式:
.contentWindow:拿到嵌套的document
.contentWindow.document.body:拿到body内容
.contentWindow.document.body.innerHtml:拿到body文本内容

5.iframe接收数据的时机:

form提交后,要等到服务器返回数据时iframe框才接收到数据,同时触发onload事件,在jQuery为$().load()

由于从上到下加载时先给iframe绑定load事件会报错,可以点submit时再绑定load

6.上传文件图片以及预览

		view函数中
	    username = request.POST.get('username')
		fafafa = request.FILES.get('fafafa')       #获取文件,可chunks()写入
		img_path = os.path.join('static/imgs/',fafafa.name)
		with open(img_path,'wb') as f:
			for item in fafafa.chunks():
				f.write(item)
		ret = {'status':True,'error':None,'data':img_path}    #返回文件路径,用于预览
		return HttpResponse(json.dumps(ret))
		
		前端
		function ifmSubmit() {
            $('#ifm1').load(function () {
                var text = $('#ifm1').contents().find('body').text();
                var obj = JSON.parse(text);
                $('#preview').empty();						#先清空
                var imgTag = document.createElement('img');	#创建标签,也可以创建好一个img标签,直接赋值src即可
                imgTag.src = "/"+obj.data;        			#路径要以/开头,这是静态路径,添加到src即可查看
                $('#preview').append(imgTag);				#添加内容
            })
        }

  



对比jQuery:

			success: function (arg) {    
				var obj = JSON.parse(arg);    				#对比iframe,这里return的数据直接拿到,arg即ret
				if(obj.status){
					$('#previewImg').attr('src','/' + obj.data);     #不同于上面的创建标签,这里是直接对img标签操作
				}		
			}

  



对比原生Ajax:

			xhr.onreadystatechange = function(){     
                if(xhr.readyState == 4){
                    var obj = JSON.parse(xhr.responseText);         #拿到
                    $('#previewImg').attr('src','/' + obj.data);
                }
            };

  



三个的不同在于返回数据的获取,标签src都要使用jQuery,也可以dom

====================================ajax操作时机===============================
如果发送的是普通的数据、字符串 ------> jQuery,XMLHttpRequest,iframe
如果发送的是文件 ------> iframe,jQuery(FormData),XMLHttpRequest(FormData)
===============================================================================

posted @ 2018-07-28 15:39  心平万物顺  阅读(144)  评论(0编辑  收藏  举报