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

时间: 2024-10-15 07:05:05

AjaxFileUpload 方法与原理分析的相关文章

Android ListView实现不同item的方法和原理分析

ListView实现不同item的方法和原理分析 一问题抛出Listview是android里面的重要组件,用来显示一个竖向列表,这个没有什么问题:但是有个时候列表里面的item不是一样的,如下图,列表里面应该有3种类型的item  1. 头像在左边的气泡Item ,比如”今天下午我就不出来了,...”2. 头像在右边的气泡Item,比如”那就等着我发你好吧”3. 单张图片显示圆角图片item几种Item的风格是完全不同的,那么怎么实现呢? 二实现方法实现的方法我这里可以列举出两种1. 每个It

hashmap冲突的解决方法以及原理分析:

在Java编程语言中,最基本的结构就是两种,一种是数组,一种是模拟指针(引用),所有的数据结构都可以用这两个基本结构构造,HashMap也一样.当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片段为例: HashMap<String,Object> m=new HashMap<String,Object>(); m.put("a", "rrr1"); m.put("b", "tt9&q

String类中intern方法的原理分析

一,前言 ? 昨天简单整理了JVM内存分配和String类常用方法,遇到了String中的intern()方法.本来想一并总结起来,但是intern方法还涉及到JDK版本的问题,内容也相对较多,所以今天就弥补昨天缺失的知识点. 二,String.intern() ? 先来看下网上流行的关于intern()方法的示例代码: public static void main(String[] args) { String s = new String("1"); s.intern(); St

jQuery的ready方法实现原理分析

jQuery中的ready方法实现了当页面加载完成后才执行的效果,但他并不是window.onload或者doucment.onload的封装,而是使用 标准W3C浏览器DOM隐藏api和IE浏览器缺陷来完成的,首先,我们来看jQuery的代码 DOMContentLoaded = function()  {          //取消事件监听,执行ready方法 if ( document.addEventListener ) {      document.removeEventListen

黑马day03 字符流乱码解决方法以及原理分析

1.字符流的乱码 response.getWriter().write("中国");这行代码,首先会把中国写入到缓冲区,然后使用老外喜欢用的iso-8859-1进行编码. 然后浏览器使用本地编码表进行解码.因此会产生乱码. package com.itheima; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import

String类原理分析及部分方法

//String类原理分析及部分方法 //http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html //http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html //String类包含在java.lang包中,这个包在java的时候就自动import //String类是唯一一个不需要new关键词来创建对象的类. public class Test{ public

HashMap底层原理分析(put、get方法)

1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那hash值就是相同的.当hash值相同时,就会出现hash冲突,HashMap通过链表来解决冲突. 原理图: 实例: import java.util.HashMap; import java.util.Map; ? public class HashMapTest { public static vo

kafka producer实例及原理分析

1.前言 首先,描述下应用场景: 假设,公司有一款游戏,需要做行为统计分析,数据的源头来自日志,由于用户行为非常多,导致日志量非常大.将日志数据插入数据库然后再进行分析,已经满足不了.最好的办法是存日志,然后通过对日志的分析,计算出有用的数据.我们采用kafka这种分布式日志系统来实现这一过程. 步骤如下: 搭建KAFKA系统运行环境 如果你还没有搭建起来,可以参考我的博客: http://zhangfengzhe.blog.51cto.com/8855103/1556650 设计数据存储格式

android脱壳之DexExtractor原理分析[zhuan]

http://www.cnblogs.com/jiaoxiake/p/6818786.html内容如下 导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1.  需要动态调试 2.  对抗反调试方案 为了提高工作效率, 我们不希望把宝贵的时间浪费去和加固的安全工程师去做对抗.作为一个高效率的逆向分析师, 笔者是忍不了的,所以我今天给大家带来一种的新的脱壳方法——DexExtractor脱壳法. 资源地址: Dex