ThinkPHP5作为后台使用Ajax实现图片上传功能

来源:互联网 发布:上汽集团 知乎 编辑:程序博客网 时间:2024/06/05 09:02

说明:
(1)这里使用Thinkphp5作为后台代码,没有使用Tp5封装好的上传图片,而是使用的Ajax技术。
(2)本人对Tp5一窍不通,但是因为实例是真的执行成功了,所以为了加深理解才如此班门弄斧。
1、首先得有一个上传页面,使用要明确一件事,当在浏览器地址中输入URL时,它会执行Tp5代码,URL为上一级目录时默认寻找下一级为index的文件或方法,在这里在浏览器URL输入http://localhost/zyh2/index.php/wap/suggestion/跟输入http://localhost/zyh2/index.php/wap/suggestion/index.html效果是一样的,都是寻找的叫index的方法,这步操作是由Tp5完成的,那么我就带你们去寻找它是在哪执行这步操作的,因为我是用的PHPStudy,所以在WWW\zyh2\application\wap\controller下找到了Suggestion.php文件,这里有一个index方法,里面做了跳转操作,你要问我为什么会是Suggestion.php文件,那我也不知道,我只知道组长当初让我在菜单管理里配置过这个,怎么就变成它了,我也不清楚,我也在学习嘛。
实例:index方法代码如下:

public function index(){        if (empty($this->uid)) {            return view($this->style . "Login/ToLogin");        }else{            return view($this->style . "Suggestion/suggestions");        }    }

实例中:uid是存储的session中的标记,判断是否已经登录。

2、下面就是页面部分的展示了,页面就不教大家画了,仁者见仁智者见智了。点击加号图标就是添加图片按钮

3、
选中一张图片后如下所示效果

4、这步看见效果了,但是我们是来加深印象的,所以要一步步来解析介绍下。
(1)首先要明确这个操作不是眼睛看上去那么简单,当然也不复杂,我们想要做上传图片就得先做好页面展示部分,如何让用户点击上传按钮后看见上传的图片缩略图?又如何展示信息告诉用户成功与否?用户想要删除的话呢?用户能一直上传下去吗?用户能随便上传什么吗?这些都是需要一步步来实现的,我们先来第一步,要让用户看见样式。
(2)在确定思路后我们还不得不思考一件事,就是如何控制上传数量,如何展示图片,多张的话又该如何放置,我想到了li标签,我们为什么不使用li标签来拼接呢?图片可以多张是肯定的,如果你想到了循环,那么我告诉你这种操作不需要循环的,当用户点击一次上传按钮它就执行一次,而且只能一次一张,当然有人说一次多张不好吗?是可以的,但是这里就先用单张吧,比较安全。
(3)我们还需要给li标签外围套一层form标签,当用户点击一次上传我们就要把这个图片自动的上传到TP5后台处理好,再展示出来,相当于两个form,一个内嵌,一个在外面,里面小提交,外面大提交,大提交把小提交也一并带走。
HTML代码:

<form id="uploadimgs" name="uploadImgs" action="APP_MAIN/Suggestion/save" method="post" enctype="multipart/form-data" onsubmit="return checkInfo()">                    <!-- 详细信息 -->                    <div class="mui-row detail">                        <div class="mui-col-sm-12 mui-col-xs-12">                                <textarea id="complain" name="complain" rows="" cols="" placeholder="请输入您的宝贵意见,我们将不断完善"></textarea>                        </div>                    </div>                    <!--遮罩层-->                    <div class="z_mask">                        <!--弹出框(点击已经选中的图片后)-->                        <div class="z_alert">                            <p>确定要删除这张图片吗?</p>                            <p>                                <span class="z_cancel">取消</span>                                <span class="z_sure">确定</span>                            </p>                        </div>                    </div>                    <div id="formComplain">                    <!-- 照片添加 -->                        <input id="images" type="hidden" name="images" class="images">                        <!-- 点击图片上传图片 -->                        <div class="btn" onclick="F_Open_dialog()">                            <input id="fileupload" type="file" name="mypic" style="visibility: hidden;">                        </div>                        <ul id="bottonUl">                            <div>                                <div class="files"></div>                            </div>                        </ul>                    </div>                    <button id="toastBtn" type="submit" onclick="checkInfo();" >发送</button>                </form>`

(4)在这个上传页的JS如下,注释很友好。

<script type="text/javascript" charset="utf-8">    //组长教的    $(function () {        var showimg = $('#showimg');        var progress = $(".progress");        var files = $(".files");        var bottonUl = $("#bottonUl");        var ii = $('.images');    /*添加包围标签*/    $("#fileupload").wrap("<form id='myupload' action='APP_MAIN/Suggestion/AddSuggestionImg' method='post' enctype='multipart/form-data'></form>");    /*当用户点击上传时*/    $("#fileupload").change(function(){        //限制上传张数(它是根据当前的li也就是生成的图片数量来比对确定的)        if($('.img').length<4){        /*后添加包围的"form"使用ajax提交*/        $("#myupload").ajaxSubmit({            //使用json格式提交            dataType:  'json',            //ajax提交前执行的函数            beforeSend: function() {                files.html("上传中...");            },            success: function(data) {                //避免一开始图片就追加"|"符号                if(ii.val()==""){                    ii.val(data.pics);                }else{                    ii.val(ii.val()+","+data.pics);                }                var imgs = data.pics;                bottonUl.append("<li class='img' style='background-image: url(__UPLOAD__/public/uploads/suggestions/"+imgs+");' rel="+imgs+"></li>");                files.html("上传成功");                if($('.img').length>4){                    return false;                }            },            //异常信息            error:function(xhr){                files.html("上传失败");                //bar.width('0');                files.html(xhr.responseText);            }        });        }else{            files.html("顶多上传四张");        }        removeImg();    });});    //图片上传按钮触发    function F_Open_dialog() {                document.getElementById("fileupload").click();            }    function checkInfo(){            var complain=$("#complain").val();            if(complain.length==0){                mui.toast('内容不能为空!',{duration:'long'});                return false;            }            if(complain.length>300){                mui.toast('内容长度超出300!',{duration:'long'});                return false;            }            //防止攻击            if(complain.indexOf("<")!=-1||complain.indexOf(">")!=-1||complain.indexOf("location")!=-1||complain.indexOf("href")!=-1||complain.indexOf("script")!=-1){                mui.toast('内容有非法字符!请重新输入!',{duration:'long'});                return false;            }        }        //删除图片        function removeImg(){            var files = $(".files");            var imgList = document.getElementsByClassName("img");            var mask = document.getElementsByClassName("z_mask")[0];            var cancel = document.getElementsByClassName("z_cancel")[0];            var sure = document.getElementsByClassName("z_sure")[0];            //for (var j = 0; j < imgList.length; j++) {                //上面注释掉的更改为了冒泡事件,发现之前bug解决了                $("ul").delegate('li','click',function (){                    var pic = $(this).attr("rel");                    //alert(pic);                    t=this;                    mask.style.display = "block";                    cancel.onclick = function() {                        mask.style.display = "none";                    };                    sure.onclick = function() {                        //这是到后台php去执行删除服务器中的图片的,我还需要删除页面中的hidden标签修饰的value才行                        $.post("APP_MAIN/Suggestion/AddSuggestionImg?act=delimg",{imagename:pic},function(msg){                            if(msg=="删除成功"){                                files.html(msg);                            }else{                                alert(msg);                            }                        });                     //执行删除隐藏域中图片的名称(阻止它传递到数据库中)                    var deleteimages = $("#images").val().split(",");                        //执行删除数组中的指定元素,返回被删除的元素,所以这里不需要它返回的参数                        deleteimages.splice($.inArray(pic,deleteimages),1);                        //利用已经经历删除过的数组重新赋值实现删除隐藏域value效果                        $("#images").val(deleteimages);                    //删除隐藏域中的图片名称结束                    mask.style.display = "none";                    t.parentNode.removeChild(t);                    };                })        }        //px转换为rem        (function(doc, win) {            var docEl = doc.documentElement,                resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',                recalc = function() {                    var clientWidth = docEl.clientWidth;                    if (!clientWidth) return;                    if (clientWidth >= 640) {                        docEl.style.fontSize = '100px';                    } else {                        docEl.style.fontSize = 100 * (clientWidth / 640) + 'px';                    }                };            if (!doc.addEventListener) return;            win.addEventListener(resizeEvt, recalc, false);            doc.addEventListener('DOMContentLoaded', recalc, false);        })(document, window);</script>

5、还记得我说的index方法吗?在那个Suggesion.php中还有一个AddSuggestionImg方法,它就是配合上一步中的操作的TP5代码,实现了将图片存储到指定目录下的操作,如果用户点击发送按钮,那么就会执行save方法,它实现了将图片路径存储到数据库中的操作,方便下一次访问,如何在发送按钮前用户删除了图片,那么这个图片也不会在服务器中存在。
实例:

public function AddSuggestionImg(){        //屏蔽过时、或者一些不必要的错误影响整个功能        error_reporting(0);        //获得index.html中属性名叫act的属性值        $action = $_GET['act'];        $pic_path="";        //判断这个属性值是不是delimg        if($action=='delimg'){            //获得index.html中属性名叫imagename的属性值(其实为pic也就是自定义名称)            $filename = $_POST['imagename'];            //如果没有清空这个图片自定义名称(也就是没有点击删除按钮)            if(!empty($filename)){                //删除文件                unlink(ROOT_PATH . 'public/uploads/suggestions/'.$filename);                //输出1(返回到html中的post请求)                echo '删除成功';            }else{                //输出"删除失败"                echo '删除失败.';            }        }else{            //客户端文件的原名称            $picname = $_FILES['mypic']['name'];            //已传文件的大小(单位字节)            $picsize = $_FILES['mypic']['size'];            //如果原名称不为空            if ($picname != "") {                //如果文件不是小于1M                if ($picsize > 1024000 || $picsize ==0) {                    echo'图片大小不能超过1M';                    exit;                }                //截取$picname中首次出现"."后的字符串(包含".")                $type = strstr($picname, '.');                if ($type != ".gif" && $type != ".jpg" && $type != ".JPG" && $type != ".PNG" && $type !=".png") {                    echo '图片格式不对!';                    exit;                }                //随机数范围                $rand = rand(100, 999);                //格式化本地时间并按照给定规则生成新的                $pics = date("YmdHis") . $rand . $type;                //上传路径                $pic_path = ROOT_PATH . 'public/uploads/suggestions/'. $pics;                //前者为要移动的文件(语法意思为文件被上传后在服务端储存的临时文件名)、后者为移动到的路径                move_uploaded_file($_FILES['mypic']['tmp_name'], $pic_path);            }else{                echo '图片格式不对或未选中图片!';                exit;            }            //对浮点数进行四舍五入(前者为要被四舍五入的后者后小数点后位数也就是说这个$size必然为相对来说是java中的float类型)            $size = round($picsize/1024,2);            $arr = array(                'name'=>$picname,                'pic'=>$pic_path,                'size'=>$size,                'pics'=>$pics            );            //将数据转为json格式传输            echo json_encode($arr);        }    }
public function save(){        //查询出当前用户登录的uid数据            $list=Db::table('sys_user')->where('uid',$this->uid)->find();            //添加数据($_POST['images']必须使用[],如果用()那么会报什么0或1异常,不知道为什么)            $data = ['uid' => $list[uid], 'uname' => $list[nick_name], 'uiphone' => $list[user_tel], 'complain_content' => $_POST['complain'], 'complain_img' =>  $_POST['images'], 'status' => 0, 'time' => date("Y-m-d H:i:s")];            Db::table('ns_suggestion')->insert($data);            $this->success('提交成功','Suggestion/index');    }

最后差点忘记我用到的引入文件:

<link rel="stylesheet" type="text/css" href="__TEMP__/{$style}/public/suggestion/css/mui.min.css" />        <link rel="stylesheet" type="text/css" href="__TEMP__/{$style}/public/suggestion/css/suggestion.css"/>        <!--App自定义的css-->        <link rel="stylesheet" type="text/css" href="__TEMP__/{$style}/public/suggestion/css/app.css" />        <!-- 朱工给的 -->        <script type="text/javascript" src="__TEMP__/{$style}/public/suggestion/js/gaolu.js"></script>        <script type="text/javascript" src="__TEMP__/{$style}/public/suggestion/js/jquery.form.js"></script>        <script type="text/javascript" src="__TEMP__/{$style}/public/suggestion/js/mui.min.js"></script>

导入说明:
CSS部分:
(1)app.css内容:

/* *这是单独为hello mui准备的个性化css,可以覆盖标准mui的css定义; * 在实际项目开发时,建议为App单独写一个css文件,从而实现项目的自定义皮肤功能; *  * */.mui-plus.mui-android header.mui-bar{    display: none;}.mui-plus.mui-android .mui-bar-nav~.mui-content{    padding: 0;}

(2)mui.min.css自己网上找吧,压缩太厉害,而且这里我不确定作用,页面是我同事帮我画的。
(3)suggestion.css内容:

* {    margin: 0;    padding: 0;}li {    list-style: none;}/*头部导航*/.mui-bar {    background-color: rgb(255, 255, 255);    box-shadow: none;    height: 52px;    border-bottom: 1px solid rgba(216,215,215,0.3);}.totalbody {    width: 100%;    overflow: hidden;}.main,.left,.right {    float: left;    height: 50px;}.main {    width: 100%;}.left {    border-radius: 50%;    margin-left: -100%;    margin-top: 12px;}.left img {    vertical-align: middle;    width: 30px;}.right {    width: 30px;    margin-left: -30px;    margin-top: 4px;}.mainin {    text-align: center;    margin-top: 18px;    font-size: 21px;    color: #323232;}/*头部导航结束*/.kuandu {    width: 100%;    height: 52px;}.kuandu1 {    width: 100%;    height: 10px;    background-color: #F0F0F0;}/*投诉建议文本框*/.mui-bar-nav~.mui-content{    padding-top: 0;}.mui-table-view-cell{    padding: 0;}/*去掉滚动条*/textarea{    height: 300px;    border: none;}/*提交表单*/button {    width: 93%;    position: relative;    left: 3.5%;    top: 1.5rem;    height: 40px;    border-radius: 5px;    background: linear-gradient(to right, rgba(0, 163, 204, 1), rgba(0, 206, 150, 1));    color: rgb(255, 255, 255);    font-size: 17px;    margin-bottom: 4rem;    box-shadow: none;    border: none;}

JS部分:
(1)gaolu.js这个我也记不清了,是一个外链我发现延迟过大就直接复制后变为本地JS的,gaolu是我爱人名字,哈哈,sorry啊,命名规范…可以的话,可以私我,我发你文件。
(2)jquery.form.js内容:
`/*!
* jQuery Form Plugin
* version: 3.15 (09-SEP-2012)
* @requires jQuery v1.3.2 or later
*
* Examples and documentation at: http://malsup.com/jquery/form/
* Project repository: https://github.com/malsup/form
* Dual licensed under the MIT and GPL licenses:
* http://malsup.github.com/mit-license.txt
* http://malsup.github.com/gpl-license-v2.txt
*/
/global ActiveXObject alert /
;(function($) {
“use strict”;

/*
Usage Note:
———–
Do not use both ajaxSubmit and ajaxForm on the same form. These
functions are mutually exclusive. Use ajaxSubmit if you want
to bind your own submit handler to the form. For example,

$(document).ready(function() {    $('#myForm').on('submit', function(e) {        e.preventDefault(); // <-- important        $(this).ajaxSubmit({            target: '#output'        });    });});Use ajaxForm when you want the plugin to manage all the event bindingfor you.  For example,$(document).ready(function() {    $('#myForm').ajaxForm({        target: '#output'    });});You can also use ajaxForm with delegation (requires jQuery v1.7+), so theform does not have to exist when you invoke ajaxForm:$('#myForm').ajaxForm({    delegation: true,    target: '#output'});When using ajaxForm, the ajaxSubmit function will be invoked for youat the appropriate time.

*/

/**
* Feature detection
*/
var feature = {};
feature.fileapi = $(“”).get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;

/**
* ajaxSubmit() provides a mechanism for immediately submitting
* an HTML form using AJAX.
*/
$.fn.ajaxSubmit = function(options) {
/jshint scripturl:true /

// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)if (!this.length) {    log('ajaxSubmit: skipping submit process - no element selected');    return this;}var method, action, url, $form = this;if (typeof options == 'function') {    options = { success: options };}method = this.attr('method');action = this.attr('action');url = (typeof action === 'string') ? $.trim(action) : '';url = url || window.location.href || '';if (url) {    // clean url (don't include hash vaue)    url = (url.match(/^([^#]+)/)||[])[1];}options = $.extend(true, {    url:  url,    success: $.ajaxSettings.success,    type: method || 'GET',    iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'}, options);// hook for manipulating the form data before it is extracted;// convenient for use with rich editors like tinyMCE or FCKEditorvar veto = {};this.trigger('form-pre-serialize', [this, options, veto]);if (veto.veto) {    log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');    return this;}// provide opportunity to alter form data before it is serializedif (options.beforeSerialize && options.beforeSerialize(this, options) === false) {    log('ajaxSubmit: submit aborted via beforeSerialize callback');    return this;}var traditional = options.traditional;if ( traditional === undefined ) {    traditional = $.ajaxSettings.traditional;}var elements = [];var qx, a = this.formToArray(options.semantic, elements);if (options.data) {    options.extraData = options.data;    qx = $.param(options.data, traditional);}// give pre-submit callback an opportunity to abort the submitif (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {    log('ajaxSubmit: submit aborted via beforeSubmit callback');    return this;}// fire vetoable 'validate' eventthis.trigger('form-submit-validate', [a, this, options, veto]);if (veto.veto) {    log('ajaxSubmit: submit vetoed via form-submit-validate trigger');    return this;}var q = $.param(a, traditional);if (qx) {    q = ( q ? (q + '&' + qx) : qx );}    if (options.type.toUpperCase() == 'GET') {    options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;    options.data = null;  // data is null for 'get'}else {    options.data = q; // data is the query string for 'post'}var callbacks = [];if (options.resetForm) {    callbacks.push(function() { $form.resetForm(); });}if (options.clearForm) {    callbacks.push(function() { $form.clearForm(options.includeHidden); });}// perform a load on the target only if dataType is not providedif (!options.dataType && options.target) {    var oldSuccess = options.success || function(){};    callbacks.push(function(data) {        var fn = options.replaceTarget ? 'replaceWith' : 'html';        $(options.target)[fn](data).each(oldSuccess, arguments);    });}else if (options.success) {    callbacks.push(options.success);}options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg    var context = options.context || this ;    // jQuery 1.4+ supports scope context     for (var i=0, max=callbacks.length; i < max; i++) {        callbacks[i].apply(context, [data, status, xhr || $form, $form]);    }};// are there files to upload?var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)var hasFileInputs = fileInputs.length > 0;var mp = 'multipart/form-data';var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);var fileAPI = feature.fileapi && feature.formdata;log("fileAPI :" + fileAPI);var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;// options.iframe allows user to force iframe mode// 06-NOV-09: now defaulting to iframe mode if file input is detectedif (options.iframe !== false && (options.iframe || shouldUseFrame)) {    // hack to fix Safari hang (thanks to Tim Molendijk for this)    // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d    if (options.closeKeepAlive) {        $.get(options.closeKeepAlive, function() {            fileUploadIframe(a);        });    }      else {        fileUploadIframe(a);      }}else if ((hasFileInputs || multipart) && fileAPI) {    fileUploadXhr(a);}else {    $.ajax(options);}// clear element arrayfor (var k=0; k < elements.length; k++)    elements[k] = null;// fire 'notify' eventthis.trigger('form-submit-notify', [this, options]);return this;// utility fn for deep serializationfunction deepSerialize(extraData){    var serialized = $.param(extraData).split('&');    var len = serialized.length;    var result = {};    var i, part;    for (i=0; i < len; i++) {        part = serialized[i].split('=');        result[decodeURIComponent(part[0])] = decodeURIComponent(part[1]);    }    return result;} // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)function fileUploadXhr(a) {    var formdata = new FormData();    for (var i=0; i < a.length; i++) {        formdata.append(a[i].name, a[i].value);    }    if (options.extraData) {        var serializedData = deepSerialize(options.extraData);        for (var p in serializedData)            if (serializedData.hasOwnProperty(p))                formdata.append(p, serializedData[p]);    }    options.data = null;    var s = $.extend(true, {}, $.ajaxSettings, options, {        contentType: false,        processData: false,        cache: false,        type: 'POST'    });    if (options.uploadProgress) {        // workaround because jqXHR does not expose upload property        s.xhr = function() {            var xhr = jQuery.ajaxSettings.xhr();            if (xhr.upload) {                xhr.upload.onprogress = function(event) {                    var percent = 0;                    var position = event.loaded || event.position; /*event.position is deprecated*/                    var total = event.total;                    if (event.lengthComputable) {                        percent = Math.ceil(position / total * 100);                    }                    options.uploadProgress(event, position, total, percent);                };            }            return xhr;        };    }    s.data = null;        var beforeSend = s.beforeSend;        s.beforeSend = function(xhr, o) {            o.data = formdata;            if(beforeSend)                beforeSend.call(this, xhr, o);    };    $.ajax(s);}// private function for handling file uploads (hat tip to YAHOO!)function fileUploadIframe(a) {    var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;    var useProp = !!$.fn.prop;    if ($(':input[name=submit],:input[id=submit]', form).length) {        // if there is an input with a name or id of 'submit' then we won't be        // able to invoke the submit fn on the form (at least not x-browser)        alert('Error: Form elements must not have name or id of "submit".');        return;    }    if (a) {        // ensure that every serialized input is still enabled        for (i=0; i < elements.length; i++) {            el = $(elements[i]);            if ( useProp )                el.prop('disabled', false);            else                el.removeAttr('disabled');        }    }    s = $.extend(true, {}, $.ajaxSettings, options);    s.context = s.context || s;    id = 'jqFormIO' + (new Date().getTime());    if (s.iframeTarget) {        $io = $(s.iframeTarget);        n = $io.attr('name');        if (!n)             $io.attr('name', id);        else            id = n;    }    else {        $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });    }    io = $io[0];    xhr = { // mock object        aborted: 0,        responseText: null,        responseXML: null,        status: 0,        statusText: 'n/a',        getAllResponseHeaders: function() {},        getResponseHeader: function() {},        setRequestHeader: function() {},        abort: function(status) {            var e = (status === 'timeout' ? 'timeout' : 'aborted');            log('aborting upload... ' + e);            this.aborted = 1;            // #214            if (io.contentWindow.document.execCommand) {                try { // #214                    io.contentWindow.document.execCommand('Stop');                } catch(ignore) {}            }            $io.attr('src', s.iframeSrc); // abort op in progress            xhr.error = e;            if (s.error)                s.error.call(s.context, xhr, e, status);            if (g)                $.event.trigger("ajaxError", [xhr, s, e]);            if (s.complete)                s.complete.call(s.context, xhr, e);        }    };    g = s.global;    // trigger ajax global events so that activity/block indicators work like normal    if (g && 0 === $.active++) {        $.event.trigger("ajaxStart");    }    if (g) {        $.event.trigger("ajaxSend", [xhr, s]);    }    if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {        if (s.global) {            $.active--;        }        return;    }    if (xhr.aborted) {        return;    }    // add submitting element to data if we know it    sub = form.clk;    if (sub) {        n = sub.name;        if (n && !sub.disabled) {            s.extraData = s.extraData || {};            s.extraData[n] = sub.value;            if (sub.type == "image") {                s.extraData[n+'.x'] = form.clk_x;                s.extraData[n+'.y'] = form.clk_y;            }        }    }    var CLIENT_TIMEOUT_ABORT = 1;    var SERVER_ABORT = 2;    function getDoc(frame) {        var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;        return doc;    }    // Rails CSRF hack (thanks to Yvan Barthelemy)    var csrf_token = $('meta[name=csrf-token]').attr('content');    var csrf_param = $('meta[name=csrf-param]').attr('content');    if (csrf_param && csrf_token) {        s.extraData = s.extraData || {};        s.extraData[csrf_param] = csrf_token;    }    // take a breath so that pending repaints get some cpu time before the upload starts    function doSubmit() {        // make sure form attrs are set        var t = $form.attr('target'), a = $form.attr('action');        // update form attrs in IE friendly way        form.setAttribute('target',id);        if (!method) {            form.setAttribute('method', 'POST');        }        if (a != s.url) {            form.setAttribute('action', s.url);        }        // ie borks in some cases when setting encoding        if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {            $form.attr({                encoding: 'multipart/form-data',                enctype:  'multipart/form-data'            });        }        // support timout        if (s.timeout) {            timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);        }        // look for server aborts        function checkState() {            try {                var state = getDoc(io).readyState;                log('state = ' + state);                if (state && state.toLowerCase() == 'uninitialized')                    setTimeout(checkState,50);            }            catch(e) {                log('Server abort: ' , e, ' (', e.name, ')');                cb(SERVER_ABORT);                if (timeoutHandle)                    clearTimeout(timeoutHandle);                timeoutHandle = undefined;            }        }        // add "extra" data to form if provided in options        var extraInputs = [];        try {            if (s.extraData) {                for (var n in s.extraData) {                    if (s.extraData.hasOwnProperty(n)) {                       // if using the $.param format that allows for multiple values with the same name                       if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {                           extraInputs.push(                           $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)                               .appendTo(form)[0]);                       } else {                           extraInputs.push(                           $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])                               .appendTo(form)[0]);                       }                    }                }            }            if (!s.iframeTarget) {                // add iframe to doc and submit the form                $io.appendTo('body');                if (io.attachEvent)                    io.attachEvent('onload', cb);                else                    io.addEventListener('load', cb, false);            }            setTimeout(checkState,15);            form.submit();        }        finally {            // reset attrs and remove "extra" input elements            form.setAttribute('action',a);            if(t) {                form.setAttribute('target', t);            } else {                $form.removeAttr('target');            }            $(extraInputs).remove();        }    }    if (s.forceSync) {        doSubmit();    }    else {        setTimeout(doSubmit, 10); // this lets dom updates render    }    var data, doc, domCheckCount = 50, callbackProcessed;    function cb(e) {        if (xhr.aborted || callbackProcessed) {            return;        }        try {            doc = getDoc(io);        }        catch(ex) {            log('cannot access response document: ', ex);            e = SERVER_ABORT;        }        if (e === CLIENT_TIMEOUT_ABORT && xhr) {            xhr.abort('timeout');            return;        }        else if (e == SERVER_ABORT && xhr) {            xhr.abort('server abort');            return;        }        if (!doc || doc.location.href == s.iframeSrc) {            // response not received yet            if (!timedOut)                return;        }        if (io.detachEvent)            io.detachEvent('onload', cb);        else                io.removeEventListener('load', cb, false);        var status = 'success', errMsg;        try {            if (timedOut) {                throw 'timeout';            }            var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);            log('isXml='+isXml);            if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {                if (--domCheckCount) {                    // in some browsers (Opera) the iframe DOM is not always traversable when                    // the onload callback fires, so we loop a bit to accommodate                    log('requeing onLoad callback, DOM not available');                    setTimeout(cb, 250);                    return;                }                // let this fall through because server response could be an empty document                //log('Could not access iframe DOM after mutiple tries.');                //throw 'DOMException: not available';            }            //log('response detected');            var docRoot = doc.body ? doc.body : doc.documentElement;            xhr.responseText = docRoot ? docRoot.innerHTML : null;            xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;            if (isXml)                s.dataType = 'xml';            xhr.getResponseHeader = function(header){                var headers = {'content-type': s.dataType};                return headers[header];            };            // support for XHR 'status' & 'statusText' emulation :            if (docRoot) {                xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;                xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;            }            var dt = (s.dataType || '').toLowerCase();            var scr = /(json|script|text)/.test(dt);            if (scr || s.textarea) {                // see if user embedded response in textarea                var ta = doc.getElementsByTagName('textarea')[0];                if (ta) {                    xhr.responseText = ta.value;                    // support for XHR 'status' & 'statusText' emulation :                    xhr.status = Number( ta.getAttribute('status') ) || xhr.status;                    xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;                }                else if (scr) {                    // account for browsers injecting pre around json response                    var pre = doc.getElementsByTagName('pre')[0];                    var b = doc.getElementsByTagName('body')[0];                    if (pre) {                        xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;                    }                    else if (b) {                        xhr.responseText = b.textContent ? b.textContent : b.innerText;                    }                }            }            else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {                xhr.responseXML = toXml(xhr.responseText);            }            try {                data = httpData(xhr, dt, s);            }            catch (e) {                status = 'parsererror';                xhr.error = errMsg = (e || status);            }        }        catch (e) {            log('error caught: ',e);            status = 'error';            xhr.error = errMsg = (e || status);        }        if (xhr.aborted) {            log('upload aborted');            status = null;        }        if (xhr.status) { // we've set xhr.status            status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';        }        // ordering of these callbacks/triggers is odd, but that's how $.ajax does it        if (status === 'success') {            if (s.success)                s.success.call(s.context, data, 'success', xhr);            if (g)                $.event.trigger("ajaxSuccess", [xhr, s]);        }        else if (status) {            if (errMsg === undefined)                errMsg = xhr.statusText;            if (s.error)                s.error.call(s.context, xhr, status, errMsg);            if (g)                $.event.trigger("ajaxError", [xhr, s, errMsg]);        }        if (g)            $.event.trigger("ajaxComplete", [xhr, s]);        if (g && ! --$.active) {            $.event.trigger("ajaxStop");        }        if (s.complete)            s.complete.call(s.context, xhr, status);        callbackProcessed = true;        if (s.timeout)            clearTimeout(timeoutHandle);        // clean up        setTimeout(function() {            if (!s.iframeTarget)                $io.remove();            xhr.responseXML = null;        }, 100);    }    var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)        if (window.ActiveXObject) {            doc = new ActiveXObject('Microsoft.XMLDOM');            doc.async = 'false';            doc.loadXML(s);        }        else {            doc = (new DOMParser()).parseFromString(s, 'text/xml');        }        return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;    };    var parseJSON = $.parseJSON || function(s) {        /*jslint evil:true */        return window['eval']('(' + s + ')');    };    var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4        var ct = xhr.getResponseHeader('content-type') || '',            xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,            data = xml ? xhr.responseXML : xhr.responseText;        if (xml && data.documentElement.nodeName === 'parsererror') {            if ($.error)                $.error('parsererror');        }        if (s && s.dataFilter) {            data = s.dataFilter(data, type);        }        if (typeof data === 'string') {            if (type === 'json' || !type && ct.indexOf('json') >= 0) {                data = parseJSON(data);            } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {                $.globalEval(data);            }        }        return data;    };}

};

/**
* ajaxForm() provides a mechanism for fully automating form submission.
*
* The advantages of using this method instead of ajaxSubmit() are:
*
* 1: This method will include coordinates for elements (if the element
* is used to submit the form).
* 2. This method will include the submit element’s name/value data (for the element that was
* used to submit the form).
* 3. This method binds the submit() method to the form for you.
*
* The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
* passes the options argument along after properly binding events for submit elements and
* the form itself.
*/
.fn.ajaxForm = function(options) {  
    options = options || {};  
    options.delegation = options.delegation &&
.isFunction($.fn.on);

// in jQuery 1.3+ we can fix mistakes with the ready stateif (!options.delegation && this.length === 0) {    var o = { s: this.selector, c: this.context };    if (!$.isReady && o.s) {        log('DOM not ready, queuing ajaxForm');        $(function() {            $(o.s,o.c).ajaxForm(options);        });        return this;    }    // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()    log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));    return this;}if ( options.delegation ) {    $(document)        .off('submit.form-plugin', this.selector, doAjaxSubmit)        .off('click.form-plugin', this.selector, captureSubmittingElement)        .on('submit.form-plugin', this.selector, options, doAjaxSubmit)        .on('click.form-plugin', this.selector, options, captureSubmittingElement);    return this;}return this.ajaxFormUnbind()    .bind('submit.form-plugin', options, doAjaxSubmit)    .bind('click.form-plugin', options, captureSubmittingElement);

};

// private event handlers
function doAjaxSubmit(e) {
/jshint validthis:true /
var options = e.data;
if (!e.isDefaultPrevented()) { // if event has been canceled, don’t proceed
e.preventDefault();
$(this).ajaxSubmit(options);
}
}

function captureSubmittingElement(e) {
/jshint validthis:true /
var target = e.target;
var el=(target);
if (!(el.is(“:submit,input:image”))) {  
        // is this a child element of the submit el?  (ex: a span within a button)  
        var t =
el.closest(‘:submit’);
if (t.length === 0) {
return;
}
target = t[0];
}
var form = this;
form.clk = target;
if (target.type == ‘image’) {
if (e.offsetX !== undefined) {
form.clk_x = e.offsetX;
form.clk_y = e.offsetY;
} else if (typeof .fn.offset == ‘function’) {  
            var offset =
el.offset();
form.clk_x = e.pageX - offset.left;
form.clk_y = e.pageY - offset.top;
} else {
form.clk_x = e.pageX - target.offsetLeft;
form.clk_y = e.pageY - target.offsetTop;
}
}
// clear form vars
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
}

// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
return this.unbind(‘submit.form-plugin click.form-plugin’);
};

/**
* formToArray() gathers form element data into an array of objects that can
* be passed to any of the following ajax functions: .get,.post, or load.
* Each object in the array has both a ‘name’ and ‘value’ property. An example of
* an array for a simple login form might be:
*
* [ { name: ‘username’, value: ‘jresig’ }, { name: ‘password’, value: ‘secret’ } ]
*
* It is this array that is passed to pre-submit callback functions provided to the
* ajaxSubmit() and ajaxForm() methods.
*/
$.fn.formToArray = function(semantic, elements) {
var a = [];
if (this.length === 0) {
return a;
}

var form = this[0];var els = semantic ? form.getElementsByTagName('*') : form.elements;if (!els) {    return a;}var i,j,n,v,el,max,jmax;for(i=0, max=els.length; i < max; i++) {    el = els[i];    n = el.name;    if (!n) {        continue;    }    if (semantic && form.clk && el.type == "image") {        // handle image inputs on the fly when semantic == true        if(!el.disabled && form.clk == el) {            a.push({name: n, value: $(el).val(), type: el.type });            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});        }        continue;    }    v = $.fieldValue(el, true);    if (v && v.constructor == Array) {        if (elements)             elements.push(el);        for(j=0, jmax=v.length; j < jmax; j++) {            a.push({name: n, value: v[j]});        }    }    else if (feature.fileapi && el.type == 'file' && !el.disabled) {        if (elements)             elements.push(el);        var files = el.files;        if (files.length) {            for (j=0; j < files.length; j++) {                a.push({name: n, value: files[j], type: el.type});            }        }        else {            // #180            a.push({ name: n, value: '', type: el.type });        }    }    else if (v !== null && typeof v != 'undefined') {        if (elements)             elements.push(el);        a.push({name: n, value: v, type: el.type, required: el.required});    }}if (!semantic && form.clk) {    // input type=='image' are not found in elements array! handle it here    var $input = $(form.clk), input = $input[0];    n = input.name;    if (n && !input.disabled && input.type == 'image') {        a.push({name: n, value: $input.val()});        a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});    }}return a;

};

/**
* Serializes form data into a ‘submittable’ string. This method will return a string
* in the format: name1=value1&name2=value2
*/
.fn.formSerialize = function(semantic) {  
    //hand off to jQuery.param for proper encoding  
    return
.param(this.formToArray(semantic));
};

/**
* Serializes all field elements in the jQuery object into a query string.
* This method will return a string in the format: name1=value1&name2=value2
*/
.fn.fieldSerialize = function(successful) {  
    var a = [];  
    this.each(function() {  
        var n = this.name;  
        if (!n) {  
            return;  
        }  
        var v =
.fieldValue(this, successful);
if (v && v.constructor == Array) {
for (var i=0,max=v.length; i < max; i++) {
a.push({name: n, value: v[i]});
}
}
else if (v !== null && typeof v != ‘undefined’) {
a.push({name: this.name, value: v});
}
});
//hand off to jQuery.param for proper encoding
return $.param(a);
};

/**
* Returns the value(s) of the element in the matched set. For example, consider the following form:
*
*
*
*
*
*
*
*
*
*
* var v = (:text).fieldValue();//ifnovaluesareenteredintothetextinputsv==[,]//ifvaluesenteredintothetextinputsarefooandbarv==[foo,bar]varv=(‘:checkbox’).fieldValue();
* // if neither checkbox is checked
* v === undefined
* // if both checkboxes are checked
* v == [‘B1’, ‘B2’]
*
* var v = $(‘:radio’).fieldValue();
* // if neither radio is checked
* v === undefined
* // if first radio is checked
* v == [‘C1’]
*
* The successful argument controls whether or not the field element must be ‘successful’
* (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
* The default value of the successful argument is true. If this value is false the value(s)
* for each element is returned.
*
* Note: This method always returns an array. If no valid value can be determined the
* array will be empty, otherwise it will contain one or more values.
*/
.fn.fieldValue = function(successful) {  
    for (var val=[], i=0, max=this.length; i < max; i++) {  
        var el = this[i];  
        var v =
.fieldValue(el, successful);
if (v === null || typeof v == ‘undefined’ || (v.constructor == Array && !v.length)) {
continue;
}
if (v.constructor == Array)
$.merge(val, v);
else
val.push(v);
}
return val;
};

/**
* Returns the value of the field element.
*/
$.fieldValue = function(el, successful) {
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
if (successful === undefined) {
successful = true;
}

if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||    (t == 'checkbox' || t == 'radio') && !el.checked ||    (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||    tag == 'select' && el.selectedIndex == -1)) {        return null;}if (tag == 'select') {    var index = el.selectedIndex;    if (index < 0) {        return null;    }    var a = [], ops = el.options;    var one = (t == 'select-one');    var max = (one ? index+1 : ops.length);    for(var i=(one ? index : 0); i < max; i++) {        var op = ops[i];        if (op.selected) {            var v = op.value;            if (!v) { // extra pain for IE...                v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;            }            if (one) {                return v;            }            a.push(v);        }    }    return a;}return $(el).val();

};

/**
* Clears the form data. Takes the following actions on the form’s input fields:
* - input text fields will have their ‘value’ property set to the empty string
* - select elements will have their ‘selectedIndex’ property set to -1
* - checkbox and radio inputs will have their ‘checked’ property set to false
* - inputs of type submit, button, reset, and hidden will not be effected
* - button elements will not be effected
*/
.fn.clearForm = function(includeHidden) {  
    return this.each(function() {
(‘input,select,textarea’, this).clearFields(includeHidden);
});
};

/**
* Clears the selected form elements.
*/
.fn.clearFields=.fn.clearInputs = function(includeHidden) {
var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)/i; // ‘hidden’ is not in this list  
    return this.each(function() {  
        var t = this.type, tag = this.tagName.toLowerCase();  
        if (re.test(t) || tag == ‘textarea’) {  
            this.value = ”;  
        }  
        else if (t == ‘checkbox’ || t == ‘radio’) {  
            this.checked = false;  
        }  
        else if (tag == ‘select’) {  
            this.selectedIndex = -1;  
        }  
        else if (includeHidden) {  
            // includeHidden can be the value true, or it can be a selector string  
            // indicating a special test; for example:  
            //
(‘#myForm’).clearForm(‘.special:hidden’)
// the above would clean hidden inputs that have the class of ‘special’
if ( (includeHidden === true && /hidden/.test(t)) ||
(typeof includeHidden == ‘string’ && $(this).is(includeHidden)) )
this.value = ”;
}
});
};

/**
* Resets the form data. Causes all form elements to be reset to their original value.
*/
$.fn.resetForm = function() {
return this.each(function() {
// guard against an input with the name of ‘reset’
// note that IE reports the reset function as an ‘object’
if (typeof this.reset == ‘function’ || (typeof this.reset == ‘object’ && !this.reset.nodeType)) {
this.reset();
}
});
};

/**
* Enables or disables any matching elements.
*/
$.fn.enable = function(b) {
if (b === undefined) {
b = true;
}
return this.each(function() {
this.disabled = !b;
});
};

/**
* Checks/unchecks any matching checkboxes or radio buttons and
* selects/deselects and matching option elements.
*/
.fn.selected = function(select) {  
    if (select === undefined) {  
        select = true;  
    }  
    return this.each(function() {  
        var t = this.type;  
        if (t == ‘checkbox’ || t == ‘radio’) {  
            this.checked = select;  
        }  
        else if (this.tagName.toLowerCase() == ‘option’) {  
            var
sel = (this).parent(‘select’);  
            if (select &&
sel[0] && sel[0].type == ‘select-one’) {  
                // deselect all other options
sel.find(‘option’).selected(false);
}
this.selected = select;
}
});
};

// expose debug var
$.fn.ajaxSubmit.debug = false;

// helper fn for console logging
function log() {
if (!$.fn.ajaxSubmit.debug)
return;
var msg = ‘[jquery.form] ’ + Array.prototype.join.call(arguments,”);
if (window.console && window.console.log) {
window.console.log(msg);
}
else if (window.opera && window.opera.postError) {
window.opera.postError(msg);
}
}

})(jQuery);
`
(3)jquery-1.8.2.js、mui.min.js、jquery-1.11.0.min.js都是可以网上下载的,其中jquery-1.11.0.min.js只是jquery-1.8.2.js的升级版本,可以其一即可。

总结:
以上就是为TP5上传图片功能的介绍,我还是有很多不明白的地方,因为TP5环境不是我配的啊,只能不断理解这个过程,还是不能理解到精髓。

原创粉丝点击