zoukankan      html  css  js  c++  java
  • AjaxFileUpload 方法与原理分析

    AjaxFileUpload需求

    传统的form表单方式上传文件,  必然会刷新整个页面。 那么在不刷新界面的情况下实现文件的上传呢?

    在 HTML4下, 聪明的程序员们发明了 ajax file upload 方式(form + hidden iframe方式), 为本文介绍的对象。

     在HTML5中XMLHttpRequest实现了异步上传文件(介绍见 http://wenzhixin.net.cn/2013/11/28/ajax_file_upload_html5)。

    开源项目

    官网为 https://github.com/davgothic/AjaxFileUpload

    此插件支持, 选择文件后,  立刻上传文件, 整体页面不刷新,  并可以根据后台返回的json报给用户上传的状况。

    使用说明

    此插件是基于jquery库,  需要引用jquery库,

        <script type="text/javascript" src="jquery-1.6.1.min.js"></script>
        <script type="text/javascript" src="../jquery.ajaxfileupload.js"></script>

    文件控件(使用此插件 form都不用  写):

        <form method="post" action="" enctype="multipart/form-data">
            <label>File Input: <input type="file" name="file" id="demo1" /></label>
            <div id="uploads">
    
            </div>
        </form>

    使用此插件初始化控件:

        <script type="text/javascript">
            $(document).ready(function() {
                $("#demo1").AjaxFileUpload({
                    onComplete: function(filename, response) {
                        $("#uploads").append(
                            $("<img />").attr("src", filename).attr("width", 200)
                        );
                    }
                });
            });
        </script>

    后台实现PHP参考:

    <?php
    /**
     * This is just an example of how a file could be processed from the
     * upload script. It should be tailored to your own requirements.
     */
    // Only accept files with these extensions
    $whitelist = array('jpg', 'jpeg', 'png', 'gif');
    $name      = null;
    $error     = 'No file uploaded.';
    if (isset($_FILES)) {
        if (isset($_FILES['file'])) {
            $tmp_name = $_FILES['file']['tmp_name'];
            $name     = basename($_FILES['file']['name']);
            $error    = $_FILES['file']['error'];
            
            if ($error === UPLOAD_ERR_OK) {
                $extension = pathinfo($name, PATHINFO_EXTENSION);
                if (!in_array($extension, $whitelist)) {
                    $error = 'Invalid file type uploaded.';
                } else {
                    move_uploaded_file($tmp_name, $name);
                }
            }
        }
    }
    echo json_encode(array(
        'name'  => $name,
        'error' => $error,
    ));
    die();

    定制接口

    四个定制接口, 可以定制内容包括:

    1 上传url (定制自定义的 action)

    2  提交submit事件 (例如对文件后缀校验不成功, 不上传)

    3  选中文件change事件 (定制选中文件后的 等待进度条等)

    4 提交完成后的响应事件 complete (提交成功后, 将提交结果添加到列表中)

        <form method="post" action="" enctype="multipart/form-data">
            <label>File Input: <input type="file" name="file" id="demo1" /></label>
        </form>
        <script type="text/javascript" src="jquery-1.6.1.min.js"></script>
        <script type="text/javascript" src="../jquery.ajaxfileupload.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                var interval;
                function applyAjaxFileUpload(element) {
                    $(element).AjaxFileUpload({
                        action: "upload.php",
                        onChange: function(filename) {
                            // Create a span element to notify the user of an upload in progress
                            var $span = $("<span />")
                                .attr("class", $(this).attr("id"))
                                .text("Uploading")
                                .insertAfter($(this));
                            $(this).remove();
                            interval = window.setInterval(function() {
                                var text = $span.text();
                                if (text.length < 13) {
                                    $span.text(text + ".");
                                } else {
                                    $span.text("Uploading");
                                }
                            }, 200);
                        },
                        onSubmit: function(filename) {
                            // Return false here to cancel the upload
                            /*var $fileInput = $("<input />")
                                .attr({
                                    type: "file",
                                    name: $(this).attr("name"),
                                    id: $(this).attr("id")
                                });
                            $("span." + $(this).attr("id")).replaceWith($fileInput);
                            applyAjaxFileUpload($fileInput);
                            return false;*/
                            // Return key-value pair to be sent along with the file
                            return true;
                        },
                        onComplete: function(filename, response) {
                            window.clearInterval(interval);
                            var $span = $("span." + $(this).attr("id")).text(filename + " "),
                                $fileInput = $("<input />")
                                    .attr({
                                        type: "file",
                                        name: $(this).attr("name"),
                                        id: $(this).attr("id")
                                    });
                            if (typeof(response.error) === "string") {
                                $span.replaceWith($fileInput);
                                applyAjaxFileUpload($fileInput);
                                alert(response.error);
                                return;
                            }
                            $("<a />")
                                .attr("href", "#")
                                .text("x")
                                .bind("click", function(e) {
                                    $span.replaceWith($fileInput);
                                    applyAjaxFileUpload($fileInput);
                                })
                                .appendTo($span);
                        }
                    });
                }
                applyAjaxFileUpload("#demo1");
            });
        </script>

    实现原理

    参考下面文章的说明:

    http://wenzhixin.net.cn/2013/11/27/ajax_file_upload_iframe

    此处结合此开源项目的代码介绍下:

    1、 应用 AjaxFileUpload 到 file控件后, 此file控件就绑定了 change事件, 事件函数为 onChange

            return this.each(function() {
                var $this = $(this);
                if ($this.is("input") && $this.attr("type") === "file") {
                    $this.bind("change", onChange);
                }
            });

    2、 用户选择文件后, 触发 change事件, 调用 onChange 函数

         此函数, 先克隆一个 file控件, 并将 此克隆控件,  也使用 AjaxFileUpload  初始化(即绑定了 onChange函数,地位与原始控件相同了),

         并将此控件 插入到 原始控件前。

                    $clone   = $element.removeAttr('id').clone().attr('id', id).AjaxFileUpload(options),
    。。。。。
                // We append a clone since the original input will be destroyed
                $clone.insertBefore($element);

         后创建  隐藏的 iframe, 并初始化 iframe的 load事件(form提交后响应的框架), 事件函数即为 响应处理函数:

                    iframe   = createIframe(),
    。。。。
    
                iframe.bind("load", {element: $clone, form: form, filename: filename}, onComplete);

         后创建提交的form, 将form的提交事件绑定为onSubmit, 并做提交动作:

                    form     = createForm(iframe);
    。。。。。
                form.append($element).bind("submit", {element: $clone, iframe: iframe, filename: filename}, onSubmit).submit();

    3、 2步骤中form提交后, 文件上传成功, 在iframe的load事件被触发, 执行onComplete函数, 将执行结果进行处理, 处理完毕后将 onChange中创建的 form 和 iframe删除:

            function onComplete (e) {
                var $iframe  = $(e.target),
                    doc      = ($iframe[0].contentWindow || $iframe[0].contentDocument).document,
                    response = doc.body.innerHTML;
    
                if (response) {
                    response = $.parseJSON(response);
                } else {
                    response = {};
                }
                // 自定义的处理逻辑
                settings.onComplete.call(e.data.element, e.data.filename, response);
                
                // Remove the temporary form and iframe
                e.data.form.remove();
                $iframe.remove();
            }

    change事件只生效一次说明

    如果对 file 控件应用 ajaxfileupload 控件初始化后, 接着设置 一个附加的 change 事件, 在第一用户选择文件上传后, 会丢失, 是因为 文件控件被替换为clone体, 但是clone体没带有old event, 生效代码为 clone参数为空, 意味着浅拷贝:

            function onChange(e) {
                var $element = $(e.target),
                    id       = $element.attr('id'),
                    $clone   = $element.removeAttr('id').clone().attr('id', id).AjaxFileUpload(options),
                    filename = $element.val().replace(/.*(/|\)/, ""),
                    iframe   = createIframe(),
                    form     = createForm(iframe);
    
                // We append a clone since the original input will be destroyed
                $clone.insertBefore($element);

    解决方法,使用代理:

    $(document).on('change', '#upload', function() {
    
    });

    参考:

    http://wenzhixin.net.cn/2013/11/26/jquery_file_upload_change_once

  • 相关阅读:
    switch语句
    switch语句
    if语句三种格式
    dowhile语句
    if语句三种格式
    if语句配对
    ansible
    linux系统中网站服务程序(web服务/httpd服务)
    ansible
    ansible
  • 原文地址:https://www.cnblogs.com/lightsong/p/4625822.html
Copyright © 2011-2022 走看看