Ajax、Iframe、Jsonp

  • 一、向后台提交数据的方式

  • 1、通过 Form 表单提交,页面会刷新
  • 2、通过 Ajax 提交,向后台偷偷发送请求,页面不刷新
  • 二、Ajax

  • 1、Ajax 本质是 XMLHttpRequest 对象

AJAX:Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),一种创建交互式网页应用的网页开发技术方案

  • 异步的 JavaScript:
    使用 【JavaScript语言】 以及相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个 JavaScript 的回调函数】
    PS:以上请求和响应的整个过程是【偷偷】进行的,页面上无任何感知
  • XML:
    XML 是一种标记语言,是Ajax在和后台交互时传输数据的格式之一

利用 AJAX 可以做:
1、注册时,输入用户名自动检测用户是否已经存在。
2、登陆时,提示用户名密码错误
3、删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除

可以手动通过 XMLHttpRequest 对象使用,也可以利用 jQuery 使用

  • 2、Ajax 发送 GET 请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    <h3>1.Ajax发送GET请求</h3>
    <div>
        <a class="btn" onclick="AjaxSubmit1();">点我</a>
    </div>


    <script src="/static/jquery-3.3.1.js"></script>
    <script>

        function AjaxSubmit1(){
            $.ajax({
                url:'/ajax1.html',
                type:'GET',
                data:{'p':123},
                success:function(arg){

                }
            })
        }

    </script>

</body>
</html>
jQuery版
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    <h3>1.Ajax发送GET请求</h3>
    <div>
        <a class="btn" onclick="AjaxSubmit2();">点我</a>
    </div>


    <script>

        function AjaxSubmit2(){
            // 创建XMLrequest对象
            var xhr = new XMLHttpRequest();
            // 设置回调函数,一定要在send前设置
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 接收完毕服务器返回的数据
                    console.log(xhr.responseText);
                }
            };
            // 创建请求链接
            xhr.open('GET', '/ajax1.html?p=123');
            // 发送请求
            xhr.send(null);

        }

    </script>

</body>
</html>
XML对象原生版
  • 3、Ajax 发送 POST 请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    <h3>2.Ajax发送POST请求</h3>
    <div>
        <a class="btn" onclick="AjaxSubmit3();">点我</a>
    </div>

    
    <script src="/static/jquery-3.3.1.js"></script>
    <script>

        function AjaxSubmit3(){
            $.ajax({
                url:'/ajax1.html',
                type:'POST',
                data:{'p':123},
                success:function(arg){

                }
            })
        }

    </script>

</body>
</html>
jQuery版
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    <h3>2.Ajax发送POST请求</h3>
    <div>
        <a class="btn" onclick="AjaxSubmit4();">点我</a>
    </div>


    <script>

        function AjaxSubmit4(){
            // 创建XMLrequet对象
            var xhr = new XMLHttpRequest();
            // 设置回调函数
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 接收完毕服务器返回的数据
                    console.log(xhr.responseText);
                }
            };
            // 创建请求链接
            xhr.open('POST', '/ajax1.html');

            // 设置请求头,不然django无法将request.body里的数据转化到request.POST里
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');

            // 发送请求(请求体内容)
            xhr.send('p=456');

        }
    </script>

</body>
</html>
XML对象原生版

注:利用 XML 对象发送 POST 请求时需要手动设置请求头

  • 4、"伪"Ajax:利用 Iframe+Form 模仿 Ajax 发送请求和接收回调函数

Iframe+Form 这种方式兼容性更好,历史比 Ajax 的两种版本更悠久

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

    <h3>3."伪"Ajax</h3>

        <h6>基于Ifame+Form表单</h6>
        <iframe id='iframe' name="ifra"></iframe>
        <form id='fm' action="/ajax1.html" method="post" target="ifra">
            <input type="text" name="root" value="111111">
            <a onclick="AjaxSubmit5();">提交</a>
        </form>

    </div>


    <script>
        
        function AjaxSubmit5(){
            document.getElementById('iframe').onload = reloadIframe;
            document.getElementById('fm').submit();
        }

        function reloadIframe(){
            // this=当前标签
            // 通过js获得iframe里的值
            console.log(this.contentWindow.document.body.innerHTML);
            // 通过jQuery获得iframe里的值
            console.log($(this).contents().find('body').html());
            // 伪造回调函数
            var content = this.contentWindow.document.body.innerHTML;
            var obj = JSON.parse(content);
            if(obj.status){
                alert(obj.message);
            }

        }
        
    </script>

</body>
</html>
"伪"Ajax版
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

    <h3>3."伪"Ajax</h3>

        <h6>基于Ifame+Form表单,加载顺序bug版</h6>
        <iframe id='iframe' name="ifra" onload="reloadIframe(this);"></iframe>
        <form id='fm' action="/ajax1.html" method="post" target="ifra">
            <input type="text" name="root" value="111111">
            <input type="submit" value="提交">
        </form>

    </div>


    <script>
        
        function reloadIframe(ths){
            console.log(ths);
            console.log(ths.contentWindow);
            // 通过js获得iframe里的值
            console.log(ths.contentWindow.document.body.innerHTML);
            // 通过jQuery获得iframe里的值
            console.log($(ths).contents().find('body').html());
            // 伪造回调函数
            var content = ths.contentWindow.document.body.innerHTML;
            var obj = JSON.parse(content);
            if(obj.status){
                alert(obj.message);
            }
        }
        
    </script>

</body>
</html>
加载顺序bug版

注:

(1)表单提交绑定事件:document.getElementById('fm').submit()

——————————————————————

(2)不同绑定事件方法中 this 指代对象总结

方式一:在标签上进行事件绑定

<body>

    <div>
        <h6>方式一:在标签上绑定</h6>
        <iframe id='iframe' name="ifra" onclick="funcName(this)"></iframe>
        <form id='fm' action="/ajax1.html" method="post" target="ifra">
            <input type="text" name="root" value="111111">
            <a onclick="AjaxSubmit5();">提交</a>
        </form>

    </div>

        
    <script>

        function funcName(arg){
            // this = window
            // arg = 当前标签
        }

    </script>

</body>

方式二:通过 js 进行事件绑定

<body>

    <div>
        <h6>方式二:通过js绑定</h6>
        <iframe id='iframe' name="ifra"></iframe>
        <form id='fm' action="/ajax1.html" method="post" target="ifra">
            <input type="text" name="root" value="111111">
            <a onclick="AjaxSubmit5();">提交</a>
        </form>

    </div>


    <script>

        function AjaxSubmit5(){
            document.getElementById('iframe').onclick = funcName;
            document.getElementById('fm').submit();
        }

        function funcName(){
            // this = 当前标签
        }

    </script>

</body>

(3)获得 Iframe 标签里内容的方法:通过获取 Iframe 标签里的内容作为回调函数返回的内容

this :代表整个 Iframe 标签

this.contentWindow :进入 Iframe 标签的里面取 #document 的整体 window 内容页面

this.contentWindow.document :进入内层的 window 中取整个内容文档

取内层文档的 body 标签里的内容作为回调函数的返回的内容:

<1> 通过 js 获得里面的值:this.contentWindow.document.body.innerHTML

<2> 通过 jQuery 获得里面的值:$(this).contents().find('body').html()

  • 三、Iframe

作用:用来嵌套别人网站

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    <div>
        <h6>学习iframe</h6>
        <input type="text">
        <div>
            <input type="text" id="url" placeholder="请输入URL"><a onclick="Test1();">查看</a>
        </div>
        <iframe id='ifm' style="height:800px; width:600px;" src="https://www.xcar.com.cn"></iframe>
    </div>

    
    <script src="/static/jquery-3.3.1.js"></script>
    <script>
        
        function Test1(){
            var url = $('#url').val();
            $('#ifm').attr('src', url);
        }

    </script>

</body>
</html>
iframe

注:点击跳转 url 时页面不刷新

利用 Iframe 标签创建一个接收通道和页面不刷新特性,加上 Form 表单可以提交数据的功能,利用 target 属性进行关联,可以模仿 Ajax 提交数据和带有回调函数的功能:

结果为:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>
    
        <h6>基于Ifame+Form表单</h6>
        <iframe id='iframe' name="ifra"></iframe>
        <form id='fm' action="/ajax1.html" method="post" target="ifra">
            <input type="text" name="root" value="111111">
            <input type="submit" value="提交">
        </form>

</body>
</html>
Iframe+Form
from django.shortcuts import render,HttpResponse,redirect
import json
# Create your views here.


def index(request):
    return render(request, 'index.html')

def ajax1(request):
    print(request.GET)
    print(request.POST)
    print(request.FILES)
    # print(request.body)
    import json
    ret = {'status':True, 'message':'123'}

    return HttpResponse(json.dumps(ret))
views.py
  • 四、Ajax 实现文件上传

  • 1、通过 FormData 对象来封装用户提交的数据进行文件上传

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

    <h3>4.文件上传</h3>

{#    利用 formData 对象上传,但是低版本ie不支持#}
    <input type="file" id="img">
    <a class="btn" onclick="AjaxSubmit6();">上传</a>

    
    <script src="/static/jquery-3.3.1.js"></script>
    <script>
        
        function AjaxSubmit6(){
            // 选择器加 .files[0] 表示标签里上传的文件对象
            // document.getElementById('img').files[0];
            var data = new FormData();
            data.append('k1','v1');
            data.append('k2','v2');
            data.append('k3',document.getElementById('img').files[0]);

            $.ajax({
                url:'/ajax1.html',
                type:'POST',
                data:data,
                success:function(arg){
                    console.log(arg);
                },
                processData:false,    // tell jQuery not to process the data
                contentType:false    //  tell jQuery not to set contentType
            })

        }
        
    </script>

</body>
</html>
jQuery版
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

    <h3>4.文件上传</h3>

{#    利用 formData 对象上传,但是低版本ie不支持#}
    <input type="file" id="img">
    <a class="btn" onclick="AjaxSubmit7();">上传</a>

    
    <script>
        
        function AjaxSubmit7(){
            var data = new FormData();
            data.append('k1','v1');
            data.append('k2','v2');
            data.append('k3',document.getElementById('img').files[0]);

            // 创建XMLrequest对象
            var xhr = new XMLHttpRequest();
            // 设置回调函数
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4){
                    // 接收完毕服务器返回的数据
                    console.log(xhr.responseText);
                }
            };
            // 创建请求链接
            xhr.open('POST', '/ajax1.html');
            // 发送请求
            xhr.send(data);

        }
        
    </script>

</body>
</html>
XML对象原生版

注:

(1)选择器加 .files[0] 表示标签里上传的文件对象:document.getElementById('img').files[0];

 

(2)通过 jQuery 版上传文件时,需要添加两个参数:代表不对传送的 FormData 数据进行任何格式处理

 processData:false,

 contentType:false

(3)利用 formData 对象上传文件,对低版本 ie 不支持

  • 2、通过 Iframe+Form 进行文件上传(推荐使用)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

    <h3>4.文件上传</h3>

{#    利用 Iframe+Form 上传,推荐使用#}
    <iframe id='iframe1' name="ifra1" style="display: none;"></iframe>
    <form id='fm1' action="/ajax1.html" method="post" enctype="multipart/form-data" target="ifra1">
        <input type="text" name="k1">
        <input type="text" name="k2">
        <input type="file" name="k3">
        <a onclick="AjaxSubmit8();">提交</a>
    </form>

    
    <script>
        
        function AjaxSubmit8(){
            document.getElementById('iframe1').onload = reloadIframe1;
            document.getElementById('fm1').submit();
        }

        function reloadIframe1(){
            // 通过js获得iframe里的值
            console.log(this.contentWindow.document.body.innerHTML);
            // 通过jQuery获得iframe里的值
            console.log($(this).contents().find('body').html());
            // 伪造回调函数
            var content = this.contentWindow.document.body.innerHTML;
            var obj = JSON.parse(content);
            console.log(obj);

        }
        
    </script>

</body>
</html>
"伪"Ajax版

注:需要将 Iframe 标签设置样式 style="display: none;"

  • 3、图片上传实时预览

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 10px;
            background-color: coral;
            color: white;
        }

    </style>

</head>
<body>

{#    利用 Iframe+Form 上传,推荐使用#}
    <iframe id='iframe1' name="ifra1" style="display: none;"></iframe>
    <form id='fm1' action="/upload_img.html" method="post" enctype="multipart/form-data" target="ifra1">
        <input type="file" name="k3" onchange="uploadFile();">
    </form>

    <h3>预览</h3>
    <div>
        <div id="preview"></div>

    </div>

    <script src="/static/jquery-3.3.1.js"></script>
    <script>

        function uploadFile(){
            document.getElementById('iframe1').onload = reloadIframe1;
            document.getElementById('fm1').submit();
        }

        function reloadIframe1(){
            {#console.log(ths);#}
            {#console.log(ths.contentWindow);#}
            // 通过js获得iframe里的值
            console.log(this.contentWindow.document.body.innerHTML);
            // 通过jQuery获得iframe里的值
            console.log($(this).contents().find('body').html());
            // 伪造回调函数
            var content = this.contentWindow.document.body.innerHTML;
            var obj = JSON.parse(content);
            console.log(obj.data);
            // 创建一个img标签,预览图片使用
            var tag = document.createElement('img');
            // img标签的src属性赋值为图片的在服务器端的静态路径
            tag.src = obj.data;
            // 需要清空之前上传的图片再追加新的图片
            $('#preview').empty().append(tag);
        }

    </script>

</body>
</html>
upload.html
from django.shortcuts import render,HttpResponse,redirect
import json


def upload(request):
    return render(request, 'upload.html')

def upload_img(request):
    import os
    import uuid

    nid = str(uuid.uuid4())
    ret = {'status':True, 'data':None, 'message':None}

    obj = request.FILES.get('k3')
    file_path = os.path.join('static', nid+obj.name)    # 拿到文件所在服务器的静态目录路径

    f = open(file_path, 'wb')
    for line in obj.chunks():
        f.write(line)
    f.close()
    ret['data'] = file_path
    return HttpResponse(json.dumps(ret))
views.py

注:

(1)上传的图片需要保存在服务器静态目录下,返回前端的也得是服务器的静态路径

(2)为了防止文件重名,可以在文件名前加入uuid进行拼接

(3)前端利用代码创建 img 标签,src 属性为图片的服务器静态路径,展示之前要先清空原先的图片

  • 五、Jsonp:跨域 Ajax

 Jsonp 是随机生成 script 块添加到 head 里,其中 src 属性为远程网站的 url,然后再移除这个 script 标签,用来突破浏览器的同源策略,可以跟不同的网站进行交互的一种方式

但是对方返回数据的时候,前面一定包裹一个函数名,本地也得有相应函数来对返回的数据进行处理

注:

(1)浏览器的同源策略,XMLHttpRequest 对象往本地发请求,浏览器可以接收返回的信息,但是往其他域名发送请求,对方服务器可以收到请求,但是返回的信息会被浏览器拦截,不能接收

(2)具有 src 属性的标签一般都不遵循同源策略,可以利用这一机制突破同源策略,例如:img、script、iframe 等

(3)jsonp 本质是GET请求,只能发送GET请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <input type="button" value="发送3" onclick="submitJsonp3();">

    <script>

        function submitJsonp3(){
            var tag = document.createElement('script');
            tag.src = 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403';
            document.head.appendChild(tag);
            document.head.removeChild(tag);
        }

        // 必须与返回数据包裹的函数名一致
        function list(arg){
            console.log(arg);
        }

    </script>
</body>
</html>
Jsonp原理
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <input type="button" value="发送4" onclick="submitJsonp4();">
    
    <script src="/static/jquery-3.3.1.js"></script>
    <script>

        function submitJsonp4(){
            $.ajax({
                url:'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403',
                type:'GET',
                dataType:'jsonp'
            })
        }

        // 必须与返回数据包裹的函数名一致
        function list(arg){
            console.log(arg);
        }

    </script>
</body>
</html>
Ajax版Jsonp

Jsonp 总结:

1、在 ajax 里设置参数 jsonp 和 jsonpCallback

jsonp:'callback',
jsonpCallback:'list' --> 此处填返回数据的包裹的函数名,如果对方可以动态获取函数名,那么这里可以自己设置函数名,以 "list" 为例

2、对方服务器最好可以动态获取接收请求发送过去的函数名:request.GET.get('callback')

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <input type="button" value="发送4" onclick="submitJsonp4();">
    
    <script src="/static/jquery-3.3.1.js"></script>
    <script>

        function submitJsonp4(){
            $.ajax({
                url:'http://127.0.0.1:9000/xiaokai.html',
                type:'GET',
                dataType:'jsonp',
                jsonp:'callback',
                jsonpCallback:'list'
            })
        }

        function list(arg){
            console.log(arg);
        }

    </script>
</body>
</html>
Jsonp最终Ajax版
from django.shortcuts import render,HttpResponse

# Create your views here.

def xiaokai(request):

    name = request.GET.get('callback')
    return HttpResponse('%s("小云");' %(name,))
对方服务器的views.py

注:设置响应头方法

from django.shortcuts import render,HttpResponse

# Create your views here.


def xiaobo(request):

    obj = HttpResponse('小云')
    obj['Access-Control-Allow-Origin'] = '*'
    return obj
View Code

 

posted @ 2020-11-15 23:58  江畔何人初见月/  阅读(210)  评论(0)    收藏  举报