jquery.unobtrusive-ajax.js源码阅读

/*!
** Unobtrusive Ajax support library for jQuery
** Copyright (C) Microsoft Corporation. All rights reserved.
*/

/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
/*global window: false, jQuery: false */
/*
data-ajax=true //开启绑定

data-ajax-mode//更新的形式 BEFORE插入到对象之前 AFTER插入到对象之后 为空就是覆盖
data-ajax-update//更新的对象
data-ajax-confirm//设置一个确定取消弹出框的文字,没有则不设置
data-ajax-loading//显示loading的对象
data-ajax-loading-duration//持续时间 默认是0
data-ajax-method//提交方式
data-ajax-url//提交url
data-ajax-begin//ajax前触发的函数或者一段程序
data-ajax-complete//完成后,此时还没有加载返回的数据,请求成功或失败时均调用
data-ajax-success//成功,加载完成的数据
data-ajax-failure//失败

*/

(function ($) {
    var data_click = "unobtrusiveAjaxClick",
        data_validation = "unobtrusiveValidation";
    //第二核心,判断是否函数,不是则构造一个匿名函数
    function getFunction(code, argNames) {
        var fn = window, parts = (code || "").split(".");
        while (fn && parts.length) {
            fn = fn[parts.shift()];
        }//查找函数名有时候是命名空间比如xxx.xxx
        if (typeof (fn) === "function") {
            return fn;
        }
        argNames.push(code);
        //如果不是函数对象则自己构造一个并返回,吊!
        return Function.constructor.apply(null, argNames);
    }

    function isMethodProxySafe(method) {
        return method === "GET" || method === "POST";
    }
    //可以添加各种提交方式,应该是为Web Api做的补充
    function asyncOnBeforeSend(xhr, method) {
        if (!isMethodProxySafe(method)) {
            xhr.setRequestHeader("X-HTTP-Method-Override", method);
        }
        //注:X-HTTP-Method-Override是一个非标准的HTTP报头。
        //这是为不能发送某些HTTP请求类型(如PUT或DELETE)的客户端而设计的
    }
    //完成后的
    function asyncOnSuccess(element, data, contentType) {
        var mode;

        if (contentType.indexOf("application/x-javascript") !== -1) {  // jQuery already executes JavaScript for us
            return;
        }

        mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
        $(element.getAttribute("data-ajax-update")).each(function (i, update) {
            var top;

            switch (mode) {
            case "BEFORE":
                top = update.firstChild;
                $("<div />").html(data).contents().each(function () {
                    update.insertBefore(this, top);
                });
                break;
            case "AFTER":
                $("<div />").html(data).contents().each(function () {
                    update.appendChild(this);
                });
                break;
            default:
                $(update).html(data);
                break;
            }
        });
    }
    //主要函数
    //绑定的对象和参数
    function asyncRequest(element, options) {
        var confirm, loading, method, duration;

        confirm = element.getAttribute("data-ajax-confirm");
        if (confirm && !window.confirm(confirm)) {
            return;
        }

        loading = $(element.getAttribute("data-ajax-loading"));//
        duration = element.getAttribute("data-ajax-loading-duration") || 0;//默认是0

        $.extend(options, {
            type: element.getAttribute("data-ajax-method") || undefined,
            url: element.getAttribute("data-ajax-url") || undefined,
            beforeSend: function (xhr) {//ajax前触发,此处的xhr将在下面用apply传递出去
                var result;
                asyncOnBeforeSend(xhr, method);//判断是否添加特种的提交方式
                result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);//argument:替换函数对象的其中一个属性对象,存储参数。这里是将原先的参数传递出去,吊!
                if (result !== false) {
                    loading.show(duration);
                }
                return result;
            },
            complete: function () {
                loading.hide(duration);
                getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments);
            },
            success: function (data, status, xhr) {
                asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
                getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments);
            },
            error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
        });

        options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });

        method = options.type.toUpperCase();//大写
        if (!isMethodProxySafe(method)) {
            options.type = "POST";
            options.data.push({ name: "X-HTTP-Method-Override", value: method });
        }
        //最后都是调用jquery的ajax
        $.ajax(options);
    }

    function validate(form) {
        //可以取消验证
        var validationInfo = $(form).data(data_validation);
        return !validationInfo || !validationInfo.validate || validationInfo.validate();
    }

    $(document).on("click", "a[data-ajax=true]", function (evt) {
        evt.preventDefault();
        asyncRequest(this, {
            url: this.href,
            type: "GET",
            data: []
        });
    });

    $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {//这个不常用
        var name = evt.target.name,
            $target = $(evt.target),
            form = $target.parents("form")[0],
            offset = $target.offset();

        $(form).data(data_click, [
            { name: name + ".x", value: Math.round(evt.pageX - offset.left) },
            { name: name + ".y", value: Math.round(evt.pageY - offset.top) }
        ]);

        setTimeout(function () {
            $(form).removeData(data_click);
        }, 0);
    });

    $(document).on("click", "form[data-ajax=true] :submit", function (evt) {
        var name = evt.target.name,
            form = $(evt.target).parents("form")[0];

        $(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []);

        setTimeout(function () {
            $(form).removeData(data_click);
        }, 0);
    });

    $(document).on("submit", "form[data-ajax=true]", function (evt) {
        var clickInfo = $(this).data(data_click) || [];
        evt.preventDefault();
        if (!validate(this)) {
            return;
        }
        asyncRequest(this, {
            url: this.action,
            type: this.method || "GET",
            data: clickInfo.concat($(this).serializeArray())//写得好,序列化表单并拼接,以后的ajax都可以这样,方便啊
        });
    });
}(jQuery));

基本上想注释的都注释了一遍,我反正被这180行的代码折服了。很不错!

时间: 2024-08-26 01:33:42

jquery.unobtrusive-ajax.js源码阅读的相关文章

underscore.js源码阅读(2)

??今天看了下underscore中的restArgs函数和createAssigner函数 123456789101112131415161718192021222324252627 //(http://ariya.ofilabs.com/2013/03/es6-and-rest-parameter.html)// This accumulates the arguments passed into an array, after a given index.// 和ES6中的rest特性相似

Dom7.js 源码阅读备份

在Framework7,其特色的HTML框架,可以创建精美的iOS应用;  她有自己的 DOM7- 一个集成了大部分常用DOM操作的高性能库.你不需要学习任何新的东西,因为她的用法和大名鼎鼎的jQuery几乎是一样的,包括大部分常用的方法和jquery风格的链式调用.去查看了一下dom7.js的源码,发现非常适合学习: 源码如下: /*=========================== Dom7 Library ===========================*/ var Dom7 =

jQuery插件ajaxfileupload.js源码与使用

在网页应用中,一般会用到上传文件或者图片什么的到服务器,那么可以用ajaxfileupload.js,但是在使用ajaxfileupload.js时候,当服务器返回的json带有&符号的时候,返回的data数据里面所有的&被转义成了&.下面的ajaxfileupload.js是经过修改的文件上传库. jQuery.extend({ /** createUploadIframe 创建上传的iframe * @param id 传递当前系统的时间字符串 * @param uri 传入的

关于jQuery的ajax的源码的dataType解读

$.ajax其实底层还是用的XMLHttpRequest,对于加载数据的格式datatype有:xml.text.html.json.jsonp.script. 其中xml.text不需要处理,直接使用原生的responseXML.responseText.对于html.json其实也是用responseText接收的,对于json格式,jquery拿到responseText后会预先用JSON.parse()去格式化一下json数据再传给回调函数. 对于jsonp和script的,其实不走xh

flipsnap.js 源码阅读笔记

这是官网:http://hokaccha.github.io/js-flipsnap/ 1.引入全局命名空间 类似jQuery插件写法   传入window, document,提高内部访问速度: ;(function(window, document, undefined){})(window, window.document)   2.定义全局变量 /* 新建div节点 */ var div = document.createElement('div'); /* 浏览器前缀 */ var p

jQuery插件pagination.js源码解读

pagination的github地址:https://github.com/gbirke/jquery_pagination 公司用的是1.2的版本,所以我就读1.2的了. jQuery.fn.pagination = function(maxentries, opts){ opts = $.extend({ isCurrentInfo: false,//是否显示当前页信息: 当前第1页,共10页 currentCls: '.current-info',//当前页class items_per

jqueryui.position.js源码分析

最近要写前端组件了,狂砍各种组件源码,这里分析一款jqueryui中的posistion插件,注意,它不是jqueryui widget,首先看下源码总体结构图 1.看到$.fn.position 是不是很熟悉?嗯,就是将position方法挂载到原型上,然后控件就可以直接调用了, 2.$.ui.position 这个对象是,用来进行冲突判断的,什么冲突?就是元素与父容器所拥有的空间以及当前可用窗口的控件,默认情形下,如果冲突则采用反转方向的方式显示:对这一点不要惊讶,一切都是为了正常显示而用的

【 js 基础 】【 源码学习 】backbone 源码阅读(三)

最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 google 一下 backbone 源码,也有很多优秀的文章可以用来学习. 我这里主要记录一些偏设计方向的知识点.这篇文章主要讲 backbone.sync 中用到的 Rest 和 CRUD. 首先我们简单了解一下 REST: REST :

【 js 基础 】【 源码学习 】backbone 源码阅读(二)

最近看完了 backbone.js 的源码,这里对于源码的细节就不再赘述了,大家可以 star 我的源码阅读项目(https://github.com/JiayiLi/source-code-study)进行参考交流,有详细的源码注释,以及知识总结,同时 google 一下 backbone 源码,也有很多优秀的文章可以用来学习. 我这里主要记录一些偏设计方向的知识点.这篇文章主要讲 控制反转. 一.控制反转 上篇文章有说到控制反转,但只是简略的举了个例子,在这里我们详细说一下这个知识点,它其实