3

ajax 简介

业务:
做一个在线投票,给歌手投票。
要求:无刷新,并且不允许使用XMLHttpRequest对象.
分析:在XHR对象,没有流行之前,已经有了“无刷新”这种效果的方法.

  1. 从http角度看,可以利用204 No content 状态码的特性

  2. 可以使用iframe

  3. 利用图片加载的特性

  4. 可以使用script

<script src="" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href=""/>
<a href=""></a>
<iframe src="" width="" height=""></iframe>
<img src=""/>

无刷新只是表面现象,本质上,是需要发送一个请求,把数据送到后台.

<?php

    if ( !file_exists('./res.txt') ) {
        fopen('./res.txt', 'wbr');
    }
    
    $cnt = file_get_contents('./res.txt');

    $cnt += 1;
    
    file_put_contents('./res.txt', $cnt);

    
    // 利用HTTP协议的204特性
    header('HTTP/1.1 204 No Conent'); // 没有内容,浏览器不理会当前文件,这次请求之后的一系列的跳转就当作没有发生.
    
?>

业务需求:
AJAX注册,提交表单,要求页面无刷新.
利用iframe特性

iframe嵌入在当前页面。
post提交到当前页面的iframe中,达到ajax效果

<form action="reg.php" method="post" target="regzone">
    <p>
        用户名:<input type="text" name="username" />
    </p>
    <p>
        密码:<input type="password" name="pass" />
    </p>
    
    <input type="submit" value="注册"/>
    <iframe style="display: none;" width="" height="" name="regzone"></iframe>
</form>

总结:
在不使用XMLHttpRequest对象的情况下,依然可以用js来实现对后台服务器的请求,同时不带来页面刷新或者跳转。

所谓AJAX:
即是指:页面不刷新的情况下,利用XMLHttpRequest对象发送HTTP请求.或者JavaScript的网络化.

AJAX文件上传实现原理(HTTP协议+JS引擎)的角度:
分析:从HTTP协议的角度来看,则要把文件的内容发送到服务器.如果可以,说明XMLHttpRequest对象在POST数据时,把文件的内容也发送到服务器,---> XHR对象获取了你要上传的文件的内容. ---> JavaScript读取了本地的文件内容. ---> 处于安全原因,JavaScript是不能够读取到本地文件内容.
因此:AJAX原理上是无法实现的.

利用伪AJAX方式来实现.

  1. iframe来实现.

  2. 用flash实现。如:swfuploaded插件

  3. HTML5实现。(HTML5增加了文件读取API)

AJAX

核心:XMLHttpRequest对象.
XML对象一个专门的HTTP请求的工具.

如何使用XMLHttpRequrest对象做AJAX请求?
分析:

  1. 如何实例化该对象.

  2. 如何请求后台资源.

  3. 请求结果如何得到(双向通信).

创建XML对象.

new XMLHttpRequest();

如何通过XHR发送请求?

分析HTTP协议,要请求需要明确因素?

clipboard.png

根据请求行:

  1. 用什么方法来请求.

    GET,POST,PUT,DELETE,HEAD
  2. 请求那个资源(URL)

  3. 同步方式

    同步,异步    
    

获取返回信息

XHR对象本身有一些属性,responseText,表示返回值.

xhr.responseText

使用异步,如何知道请求完成.

XHR对象在请求与响应的过程中,状态会不断变化(0-4)xhr.readyState,逐步变化. 可以绑定一个函数,监听状态变化,只要状态发生变化,就触发函数xhr.onreadystatechange

返回值类型

不考虑HTML5最新的标准,返回值:普通文本/xml文档.二种返回形式

XML文档

function createXHR() {
    var xhr = null;
    
    if ( window.ActiveXObject ) {
        xhr = new window.ActiveXObject();
    } else if ( XMLHttpRequest ) {
        xhr = new XMLHttpRequest('Microsoft.XMLHTTP');
    }
    return xhr;
}

// xml
function test1() {
    
    var xhr = createXHR();
    
    xhr.open('GET', './returntype.php', true);
    
    xhr.onreadystatechange = function () {
        if ( this.readyState == 4 ) {
            var xmldom = this.responseXML;
            console.log( xmldom );
        }
    }
            
    xhr.send(null);        
}

普通文本

普通文本变通形式:

  1. 后台返回大段的html代码,直接innerHTML到前台页面.

  2. json格式的普通文本.

  3. 返回简短的标志字符串 如: 0, 1, ok.

function createXHR() {
    var xhr = null;
    
    if ( window.ActiveXObject ) {
        xhr = new window.ActiveXObject();
    } else if ( XMLHttpRequest ) {
        xhr = new XMLHttpRequest('Microsoft.XMLHTTP');
    }
    return xhr;
}

// 返回普通文本的html代码字符串
function test2() {

    var xhr = createXHR();
    
    xhr.open('GET', './returnhtml.php', true);
    
    xhr.onreadystatechange = function () {
        
        if ( this.readyState == 4 ) {
            console.log( this.responseText );
        }
        
    }
    
    xhr.send(null);

}

// json格式字符串对象
function test3() {
    var xhr = createXHR();
    xhr.open('GET', './returnjson.php', true);
    
    xhr.onreadystatechange = function () {
        
        if ( this.readyState == 4 ) {
            console.log( this.responseText );
        }
        
    }
    
    xhr.send(null);
}

jsonp格式

jsonp是跨域解决的一种方式.

<script type="text/javascript">
    
    var oSc = document.createElement('script');
    
    // (调用函数)
    oSc.src = 'http://?callback=pink';
    oSc.setAttribute('type', 'text/javascript');
    
    oSc.appendChild('body');
    
    // 返回的数据 (定义函数)
    function pink( data ) {
    };
</script>

异步原理

readyState 状态值:

clipboard.png

通过插队机制,把回调函数插入到当前已经执行代码的前方。

HTML5与AJAX

iframe

  1. 扑捉表单提交动作(onsubmit)

  2. 创建一个iframe

  3. 把表单的target修改 指向 该 iframe

  4. 销毁iframe

$('form').submit(function () {
    var upName = 'up' + Math.random(); 
    $('<iframe>').attr('name', upName).css('display', 'none').appendTo($('body'));
    $(this).attr('target', upName);
    
    // loading
    $('#msg').html('<img src="./load.gif" />');
});

    $error = $_FILES['pic']['error'] == 0 ? 'success' : 'fail';
    
    sleep(2);
    
    if ( $error == 0 ) {
        echo '<script>
            parent.document.getElementById("msg").innerHTML = "'. $error .'"
        </script>';
    } else {
        echo '上传失败';
    }

FormData

进度条: 总大小, 已上传大小
解决:在HTML5中,有一个"上传过程"的事件(onprogress),事件中,可以读取到当前两个信息.
思路:在上传过程中,不断触发函数,读取(已上传/总大小),更新页面数据。

FormData使用注意

  1. 每个表单域必须有name属性

  2. 不能设置setRequestHeaer

  3. 特殊符号无须编码

  4. 在form标签里无须设置enctype='multipart/form-data'属性(即使有上传文件域也不需要设置)
    (无刷新上传附件,FormData可以收集上的文件域信息)

AJAX对象-> upload -> onprogress

AJAX对象有成员属性upload,是一个对象,该对象有一个onprogress属性,该属性是一个时间,该事件每间隔0.1秒执行一次,执行过程中会知道当前的附件上传情况。(例如:文件上传的总大小,目前已经上传大小等信息)

/**
 * file文件上传
 */
function selfile() {
    
    // 创建FromData对象
    var fd = new FormData();
    
    // 获取文件对象
    var pic = document.getElementsByTagName('input')[0].files[0];
    
    // 把获取的文件对象追加到表单数据中.
    fd.append('pic', pic);
//    fd.pic = pic;
    
    // AJAX
    var xhr = new XMLHttpRequest();
    
    xhr.open('POST', 'upfile.php', true);
    
    xhr.onreadystatechange = function () {
        
        if ( xhr.readyState == 4 ) {
            document.getElementById("debug").innerHTML = xhr.responseText;
        }
        
    }
    
    xhr.upload.onprogress = function ( ev ) {
        
        // 长度是否可以计算. (区分:分块上传) 
        if ( ev.lengthComputable ) {
            // 当前已经上传多少/总共多少
            var percent = 100 * ev.loaded / ev.total;
            
            document.getElementById('debug').innerHTML = '已经上传:' + percent.toFixed(2);
            
        }
    }
    
    xhr.send(fd);
    
}

大文件切割上传

Blob对象

while循环实现文件上传

/**
 * 使用的API
 * file --> Blob
 * Blob有slice, 可以截取二进制对象的一部分.
 */

/**
 * 思路:
 * 截取10M,上传
 * 判断文件是否截取完毕
 * 
 * while( 存在数据 ) { // 截取, 上传 }
 */
    
/**
 * 上传文件
 */
function sendFile() {
    
    const LENGTH = 10 * 1024 * 1024; // 一次性截取长度
    var start = 0; // 从哪里开始截取
    var end = start + LENGTH // 到哪边截至
    
    var blob = new Blob();
    var fd = null;
    
    // XHR对象
    var xhr = null;
    
    // 获取总的文件大小
    var pic = document.getElementById("pic").files[0];
    var totalSize = pic.size;
    var percent = 0;
    
    while ( start < totalSize ) {
        
        // 截取文件
        blob = pic.slice(start, end);
        
        fd = new FormData();
//                    fd.append('part', blob);
        fd.part = blob;
        
        // xml对象
        xhr = new XMLHttpRequest();
        xhr.open('POST', 'sliceup.php', true);
        
        xhr.upload.onprogress = function ( ev ) {
        }
        
        // 发送请求
        xhr.send(fd);
        
        start = end;
        end = start + LENGTH;
        
        percent += 100 * end / totalSize;
        if ( percent > 100 ) {
            percent = 100;
        }
        document.getElementById("msg").style.width = percent + '%'; 
        
    }
    
    
}

定时器实现切割上传

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            #progress {
                margin-top: 20px;
                width: 500px;
                height: 25px;
                border: 1px solid greenyellow;
            }
            #msg {
                width: 0;
                height: 25px;
                background: greenyellow;
            }
        </style>
    </head>
    <body>
        
        <input type="file" name="pic" id="pic" /><br /><br />
        <button onclick="file()">大文件切割上传</button>
        <div id="progress">
            <div id="msg"></div>
        </div>
    
        <script type="text/javascript">
            /**
             * 使用的API
             * file --> Blob
             * Blob有slice, 可以截取二进制对象的一部分.
             */
            
            /**
             * 思路:
             * 截取10M,上传
             * 判断文件是否截取完毕
             */
                
            var xhr = new XMLHttpRequest();
            var timer = null;
            /**
             * 上传文件
             */
            
            function file() {
                timer = setInterval(sendFile, 1000);    
            }
            
            // 每个一秒执行产生的问题
            // 在一秒内,没有上传完成
            var sendFile = (function () {
                
                const LENGTH = 10 * 1024 * 1024; // 一次性截取长度
                var start = 0; // 从哪里开始截取
                var end = start + LENGTH // 到哪边截至
                var sending = true; // 上一块是否发送完毕
                var blob = null;
                var fd = null;
            
                // 百分比
                var percent = 0;
                    
                return function () {
                    
                    if (sending == true) {
                        return false;
                    }
                    var file = document.getElementById("pic").files[0];
                    
                    if ( start > file.size ) {
                        clearInterval(timer);
                        return false;
                    }
                    
                    blob = file.slice(start, end);
                    
                    fd = new FormData();
                    fd.append('part', blob);
                    
                    // 上传
                    up(fd);
                    
                    start = end;
                    end = start + LENGTH;
                    
                    sending = false;
                    
                    // 进度条
                    percent = 100 * end / file.size;
                    if ( percent > 100 ) {
                        percent = 100;
                    }
                    document.getElementById("msg").style.width = percent + '%'; 
                }
                
            })();
            
            /**
             * 上传文件
             * @param {} fd
             */
            function up( fd ) {
                xhr.open('POST', 'sliceup.php', true);
                xhr.send(fd);
            }
            
        </script>
        
    </body>
</html>

alogy
1.3k 声望121 粉丝

// Designer and Developer


« 上一篇
PHP_HTTP协议
下一篇 »
PHP_Smarty