《JavaScript 源碼分析》之 jquery.unobtrusive-ajax.js

  1 /*!
  2 ** Unobtrusive Ajax support library for jQuery
  3 ** Copyright (C) Microsoft Corporation. All rights reserved.
  4 */
  5  
  6 /*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 */
  7 /*global window: false, jQuery: false */
  8 /*
  9 data-ajax=true //開啓綁定
 10  
 11 data-ajax-mode//更新的形式 BEFORE插入到對象以前 AFTER插入到對象以後 爲空就是覆蓋
 12 data-ajax-update//更新的對象
 13 data-ajax-confirm//設置一個肯定取消彈出框的文字,沒有則不設置
 14 data-ajax-loading//顯示loading的對象
 15 data-ajax-loading-duration//持續時間 默認是0
 16 data-ajax-method//提交方式
 17 data-ajax-url//提交url
 18 data-ajax-begin//ajax前觸發的函數或者一段程序
 19 data-ajax-complete//完成後,此時尚未加載返回的數據,請求成功或失敗時均調用
 20 data-ajax-success//成功,加載完成的數據
 21 data-ajax-failure//失敗
 22  
 23 */
 24  
 25 (function ($) {
 26     var data_click = "unobtrusiveAjaxClick",
 27         data_validation = "unobtrusiveValidation";
 28     //第二核心,判斷是否函數,不是則構造一個匿名函數
 29     function getFunction(code, argNames) {
 30         var fn = window, parts = (code || "").split(".");
 31         while (fn && parts.length) {
 32             fn = fn[parts.shift()];
 33         }//查找函數名有時候是命名空間好比xxx.xxx
 34         if (typeof (fn) === "function") {
 35             return fn;
 36         }
 37         argNames.push(code);
 38         //若是不是函數對象則本身構造一個並返回,吊!
 39         return Function.constructor.apply(null, argNames);
 40     }
 41  
 42     function isMethodProxySafe(method) {
 43         return method === "GET" || method === "POST";
 44     }
 45     //能夠添加各類提交方式,應該是爲Web Api作的補充
 46     function asyncOnBeforeSend(xhr, method) {
 47         if (!isMethodProxySafe(method)) {
 48             xhr.setRequestHeader("X-HTTP-Method-Override", method);
 49         }
 50         //注:X-HTTP-Method-Override是一個非標準的HTTP報頭。
 51         //這是爲不能發送某些HTTP請求類型(如PUT或DELETE)的客戶端而設計的
 52     }
 53     //完成後的
 54     function asyncOnSuccess(element, data, contentType) {
 55         var mode;
 56  
 57         if (contentType.indexOf("application/x-javascript") !== -1) {  // jQuery already executes JavaScript for us
 58             return;
 59         }
 60  
 61         mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase();
 62         $(element.getAttribute("data-ajax-update")).each(function (i, update) {
 63             var top;
 64  
 65             switch (mode) {
 66             case "BEFORE":
 67                 top = update.firstChild;
 68                 $("<div />").html(data).contents().each(function () {
 69                     update.insertBefore(this, top);
 70                 });
 71                 break;
 72             case "AFTER":
 73                 $("<div />").html(data).contents().each(function () {
 74                     update.appendChild(this);
 75                 });
 76                 break;
 77             default:
 78                 $(update).html(data);
 79                 break;
 80             }
 81         });
 82     }
 83     //主要函數
 84     //綁定的對象和參數
 85     function asyncRequest(element, options) {
 86         var confirm, loading, method, duration;
 87  
 88         confirm = element.getAttribute("data-ajax-confirm");
 89         if (confirm && !window.confirm(confirm)) {
 90             return;
 91         }
 92  
 93         loading = $(element.getAttribute("data-ajax-loading"));//
 94         duration = element.getAttribute("data-ajax-loading-duration") || 0;//默認是0
 95  
 96         $.extend(options, {
 97             type: element.getAttribute("data-ajax-method") || undefined,
 98             url: element.getAttribute("data-ajax-url") || undefined,
 99             beforeSend: function (xhr) {//ajax前觸發,此處的xhr將在下面用apply傳遞出去
100                 var result;
101                 asyncOnBeforeSend(xhr, method);//判斷是否添加特種的提交方式
102                 result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);//argument:替換函數對象的其中一個屬性對象,存儲參數。這裏是將原先的參數傳遞出去,吊!
103                 if (result !== false) {
104                     loading.show(duration);
105                 }
106                 return result;
107             },
108             complete: function () {
109                 loading.hide(duration);
110                 getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments);
111             },
112             success: function (data, status, xhr) {
113                 asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html");
114                 getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments);
115             },
116             error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"])
117         });
118  
119         options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" });
120  
121         method = options.type.toUpperCase();//大寫
122         if (!isMethodProxySafe(method)) {
123             options.type = "POST";
124             options.data.push({ name: "X-HTTP-Method-Override", value: method });
125         }
126         //最後都是調用jquery的ajax
127         $.ajax(options);
128     }
129  
130     function validate(form) {
131         //能夠取消驗證
132         var validationInfo = $(form).data(data_validation);
133         return !validationInfo || !validationInfo.validate || validationInfo.validate();
134     }
135  
136     $(document).on("click", "a[data-ajax=true]", function (evt) {
137         evt.preventDefault();
138         asyncRequest(this, {
139             url: this.href,
140             type: "GET",
141             data: []
142         });
143     });
144  
145     $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {//這個不經常使用
146         var name = evt.target.name,
147             $target = $(evt.target),
148             form = $target.parents("form")[0],
149             offset = $target.offset();
150  
151         $(form).data(data_click, [
152             { name: name + ".x", value: Math.round(evt.pageX - offset.left) },
153             { name: name + ".y", value: Math.round(evt.pageY - offset.top) }
154         ]);
155  
156         setTimeout(function () {
157             $(form).removeData(data_click);
158         }, 0);
159     });
160  
161     $(document).on("click", "form[data-ajax=true] :submit", function (evt) {
162         var name = evt.target.name,
163             form = $(evt.target).parents("form")[0];
164  
165         $(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []);
166  
167         setTimeout(function () {
168             $(form).removeData(data_click);
169         }, 0);
170     });
171  
172     $(document).on("submit", "form[data-ajax=true]", function (evt) {
173         var clickInfo = $(this).data(data_click) || [];
174         evt.preventDefault();
175         if (!validate(this)) {
176             return;
177         }
178         asyncRequest(this, {
179             url: this.action,
180             type: this.method || "GET",
181             data: clickInfo.concat($(this).serializeArray())//寫得好,序列化表單並拼接,之後的ajax均可以這樣,方便啊
182         });
183     });
184 }(jQuery));
相關文章
相關標籤/搜索