淺談Jquery實現簡單的雙向綁定


 1 var dom = toddyDetailObj.GetDom();  2                     var formObj = dom.find("input,textarea,select");  3 
 4                     formObj.each(function () {  5                         $(this).on("keyup", function () {  6                             if ($(this).attr("name") !== undefined) {  7                                 toddyDetailObj.AddDataObj($(this));  8  }  9  }); 10 
11                         $(this).on("change", function () { 12                             if ($(this).attr("name") !== undefined) { 13                                 toddyDetailObj.AddDataObj($(this)); 14  } 15  }); 16 
17                         $(this).on("blur", function () { 18                             if ($(this).attr("name") !== undefined) { 19                                 toddyDetailObj.AddDataObj($(this)); 20  } 21  }); 22                     });
View Code

先上一個代碼,主要是雙向綁定的基本概念就是在js里面有個緩存的model,當model發生變化,我們的頁面上對應的節點應該發生對應的變化,所以,依據這個點,我們在需要做的在頁面上面打下標識。

 1 <dl class="dl-horizontal" toddy-data="default" style="position:relative;">
 2     <dt><b class="textwarning">*</b>任務ID:</dt>
 3     <dd>
 4         <input type="text" class="w200" name="ReasonID" value=""/>
 5         <em>系統自動生成.</em>
 6     </dd>
 7     <dt><b class="textwarning">*</b>任務名稱:</dt>
 8     <dd>
 9         <input type="text" class=" w200" name="ReasonName" value=""/>
10         <em>可設置該任務的名稱.</em>
11     </dd>
12 
13     <dt><b class="textwarning">*</b>出票時間段:</dt>
14     <dd>
15         <input type="text" class="w150" name="OutTicketTimeStart" value=""/>
16 17         <input type="text" class="w150" name="OutTicketTimeEnd" value=""/>
18         <em>請選擇需要獲取票號狀態的出票時間段</em>
19     </dd>
20     <dt><b class="red">*</b>起飛時間段:</dt>
21     <dd>
22         <span style=" color:#cdcdcd; margin-top:10px;">
23             <input type="text" class=" w150" value=""/>
24 25             <input type="text" class=" w150" value=""/>
26             <em>請選擇需要獲取票號狀態的起飛時間段</em>
27         </span>
28     </dd>
29     <dt>可退款客票狀態:</dt>
30     <dd>
31         <label><input name="nationality[]" type="checkbox" value="VOID">VOID</label>
32         <label><input name="nationality[]" type="checkbox" value="REFUNDED">REFUNDED</label>
33         <label><input name="nationality[]" type="checkbox" value="OPEN FOR USE">OPEN FOR USE</label>
34         <label><input name="nationality[]" type="checkbox" value="SUSPENDE">SUSPENDE</label>
35         <label><input name="nationality[]" type="checkbox" value="EXCHANGED">EXCHANGED</label>
36         <label><input name="nationality[]" type="checkbox" value="USED/FLOWN">USED/FLOWN</label>
37         <label><input name="nationality[]" type="checkbox" value="LIFT/BOARDED">LIFT/BOARDED</label>
38         <label><input name="nationality[]" type="checkbox" value="CHECKED IN">CHECKED IN</label>
39     </dd>
40     <dt>備注:</dt>
41     <dd>
42         <textarea name="Remark" style="width:300px; height:100px;"></textarea>
43     </dd>
44 
45     <dd toddy-data="PersonList">
46         <table width="500" border="0" cellspacing="0" cellpadding="0" class="wintable">
47             <tbody>
48             <tr>
49                 <th align="left"><span>判斷條件</span></th>
50                 <th align="right"><span>操作</span></th>
51             </tr>
52             <tr>
53                 <td align="left"><span>
54               <select class="w180">
55                   <option>買入賣出退票手續費一致</option>
56                   <option>行程單取消或未打印</option>
57               </select>
58               </span></td>
59                 <td align="right"><span>
60               <input type="button" class="add" style="width: 20px;" value="+">
61               </span></td>
62             </tr>
63             <tr>
64                 <td align="left"><span><input type="text" class="w150" name="Condition" value=""/></span></td>
65                 <td align="right"><span>
66               <input type="button" class="reduce" style="width: 20px;" value="-">
67               </span></td>
68             </tr>
69             <tr>
70                 <td align="left"><span><input type="text" class="w150" name="Condition" value=""/></span></td>
71                 <td align="right"><span>
72               <input type="button" class="reduce" style="width: 20px;" value="-">
73               </span></td>
74             </tr>
75             </tbody>
76         </table>
77     </dd>
78 </dl>
View Code

 

我們這里推薦使用的toddy-data來判斷,所以只要在頁面上面寫上這個一個標識這樣的一個標識的概念其實和Angular的想法有點類似,這樣我們在js里面只需要通過查詢這樣的一個標識就可以了。只需要獲取body里面所有的標簽上面有標識的即可,就可以把對應最外層的dom保存下面,后面可以使用,我們一般寫一個公用的方法來獲取。

                /** * 獲取整個DOM,默認獲取第一個 */ GetDom: function () { var domObj = $(config.tagName), dom, num = 0; for (var i = 0; i < domObj.length; i++) { if ($(domObj[i]).attr(tagPrefix + "-data") !== undefined && $(domObj[i]).attr(tagPrefix + "-data") !== "" && num === 0) { dom = $(domObj[i]); num++; } } return dom; }, 

 接下來就是很簡單的給每一個內部的標簽上面的表單含有name的加上keyup事件和blur事件,blur是防止中文輸入法離開的時候不觸發keyup事件,這樣可以保證拿到的是對應的值。接下來就是把對應的值放到對應的json對象里面,可以根據自己的想法來處理。

我這里是根據發現標識的層級確定json格式的。其實一般的頁面也就2層。多的頁面就過於復雜了。這個時候需要使用者自行處理,所以一般會留下一個回調函數。下面貼上js和html。

 1 /**  2  * Created by luocheng on 2015/10/20.  3  */
 4 ;  5 (function ($) {  6  $.extend({  7         toddy: function (data) {  8 
 9             var tagPrefix = "toddy", nowObj, dataTemp = {};  10 
 11             /**  12  * 初始化參數  13  * @type {{callBack: null}}  14              */
 15             var config = {  16                 tagName: "form",  17  data: {},  18                 callBack: null
 19  };  20 
 21             /**  22  * 公布參數  23              */
 24  $.extend(config, data);  25 
 26             /**  27  *  28  * @type {{getDom: getDom}}  29              */
 30             var toddyDetailObj = {  31                 /**  32  * 獲取整個DOM,默認獲取第一個  33                  */
 34                 GetDom: function () {  35                     var domObj = $(config.tagName), dom, num = 0;  36                     for (var i = 0; i < domObj.length; i++) {  37                         if ($(domObj[i]).attr(tagPrefix + "-data") !== undefined && $(domObj[i]).attr(tagPrefix + "-data") !== "" && num === 0) {  38                             dom = $(domObj[i]);  39                             num++;  40  }  41  }  42 
 43                     return dom;  44  },  45                 /**  46  * 同步加載對象  47  * @param obj  48  * @constructor  49                  */
 50                 AddDataObj: function (obj) {  51                     var $this = $(obj), isParent = toddyDetailObj.IsParentDom($this, true);  52                     if (isParent !== "") {  53                         /**  54  * 循環獲取當前對象的所有名稱不為空的表單,不管什么把所有相同名字的放在一起  55                          */
 56                         var name = $this.attr("name"), dataArr = [];  57                         nowObj.find("[name=" + name + "]").each(function () {  58                             if (toddyDetailObj.GetDomValue($(this)) !== "") {  59                                 var dataObj = {};  60                                 dataObj[name] = toddyDetailObj.GetDomValue($(this));  61  dataArr.push(dataObj);  62  }  63  });  64 
 65                         if (isParent.indexOf(".") > -1) {  66                             var isParentArr = isParent.split("."),  67                                 isParentLen = isParentArr.length,  68                                 dataName = isParentArr[isParentLen - 1];  69                             if (dataName !== "") {  70                                 dataTemp[dataName] = dataArr;  71                                 config.data[isParentArr[isParentLen - 2]] = dataTemp;  72                             } else {  73                                 /**  74  * 配置信息有誤提示使用者  75  * @type {string}  76                                  */
 77                                 var tagName = nowObj.get(0).tagName.toLowerCase(),  78                                     alertTip = "<" + tagName + " " + tagPrefix + "-data=\"" + isParent + "\"></" + tagName + ">";  79                                 alert("配置信息有誤!\r\n" + alertTip);  80  }  81                         } else {  82                             config.data[isParent] = dataArr;  83  }  84 
 85                     } else {  86                         if ($this.attr("name") !== undefined) {  87                             var isHaveDataName = toddyDetailObj.IsParentDom($this, false);  88                             if (isHaveDataName !== "" && isHaveDataName.toLowerCase() !== "default") {  89                                 dataTemp[$this.attr("name")] = toddyDetailObj.GetDomValue($this);  90                                 config.data[isHaveDataName] = dataTemp;  91                             } else if (isHaveDataName.toLowerCase() === "default") {  92                                 config.data[$this.attr("name")] = toddyDetailObj.GetDomValue($this);  93  }  94  }  95  }  96 
 97                     /**  98  * 回調函數  99                      */
100                     if (typeof config.callBack === "function") { 101  config.callBack(config.data); 102  } 103  }, 104                 /** 105  * 綁定所有表單對象 106  * @constructor 107                  */
108                 BindEvent: function () { 109                     var dom = toddyDetailObj.GetDom(); 110                     var formObj = dom.find("input,textarea,select"); 111 
112                     formObj.each(function () { 113                         $(this).on("keyup", function () { 114                             if ($(this).attr("name") !== undefined) { 115                                 toddyDetailObj.AddDataObj($(this)); 116  } 117  }); 118 
119                         $(this).on("change", function () { 120                             if ($(this).attr("name") !== undefined) { 121                                 toddyDetailObj.AddDataObj($(this)); 122  } 123  }); 124 
125                         $(this).on("blur", function () { 126                             if ($(this).attr("name") !== undefined) { 127                                 toddyDetailObj.AddDataObj($(this)); 128  } 129  }); 130  }); 131  }, 132                 /** 133  * 判斷是否父級有標識 134  * @param obj 當前對象 135  * @param isMain true標識為子級標簽,false獲取最上級標識名稱 136  * @returns {string} 如果有標識返回標識 137                  */
138                 IsParentDom: function (obj, isMain) { 139                     var parents = $(obj).parents(), num = 0, data = ""; 140                     parents.each(function () { 141                         if ($(this).attr(tagPrefix + "-data") !== undefined) { 142                             if (num === 0) { 143                                 nowObj = $(this); 144                                 data = $(this).attr(tagPrefix + "-data"); 145  } 146                             num++; 147  } 148  }); 149 
150                     if (num <= 1 && isMain) { 151                         data = ""; 152  } 153 
154                     return data; 155  }, 156                 /** 157  * 獲取對應的表單的值 158  * @param obj 159  * @returns {*|defaultGetter} 160  * @constructor 161                  */
162                 GetDomValue: function (obj) { 163                     var startsWith = function (str, starts) { 164 
165                         if (starts === "") { 166                             return true; 167  } 168                         if (str === null || starts === null) { 169                             return false; 170  } 171                         str = String(str); 172                         starts = String(starts); 173                         return str.length >= starts.length && str.slice(0, starts.length) === starts; 174  }; 175 
176                     var endsWith = function (str, ends) { 177 
178                         if (ends === "") { 179                             return true; 180  } 181                         if (str === null || ends === null) { 182                             return false; 183  } 184                         str = String(str); 185                         ends = String(ends); 186                         return str.length >= ends.length && str.slice(str.length - ends.length, str.length) === ends; 187 
188  }; 189 
190                     var contains = function (obj, target) { 191                         var flag = false; 192                         if (obj == null) { 193                             return false; 194  } 195 
196                         if ($.isArray(obj)) { 197                             for (var i = 0; len = obj.length, i < len; i++) { 198                                 if (obj[i] === target) { 199                                     flag = true; 200  } 201  } 202  } 203                         return flag; 204  }; 205 
206                     var getters = { 207                         "SELECT": function () { 208                             return $(obj).val(); 209  }, 210                         "INPUT": function () { 211                             var type = $(obj).attr("type").toLowerCase(); 212                             if (contains(["text", "password"], type)) { 213                                 return $(obj).val(); 214  } 215                             if (contains(["checkbox", "radio"], type)) { 216                                 return $(obj).attr("checked") ? $(obj).val() : null; 217  } 218  }, 219                         "TEXTAREA": function () { 220                             return $(obj).val(); 221  } 222  }; 223 
224                     var defaultGetter = function () { 225                         return $(obj).html(); 226  }; 227 
228                     var elementType = $(obj).get(0).tagName.toUpperCase(); 229                     var getter = getters[elementType] || defaultGetter; 230                     return getter(); 231  }, 232                 dealDomObj: function () { 233                     var dom = toddyDetailObj.GetDom(); 234                     console.log(dom.find("[toddy-data]")); 235                     for (var item in config.data) { 236                         var temp = config.data[item]; 237                         if ($.isArray(temp)) { 238                         } else { 239                             toddyDetailObj.dealDomValue(dom.find("[name='" + item + "']"), temp); 240  } 241  } 242  }, 243 
244                 dealDomValue: function (dom, data) { 245                     var domName = toddyDetailObj.getDomTagName(dom); 246                     var setter = { 247 
248  }; 249 
250 
251  }, 252                 getDomTagName: function (dom) { 253                     var $dom = $(dom); 254                     return $dom.get(0).tagName.toUpperCase(); 255  }, 256                 initEvent: function () { 257                     var dom = $("[" + tagPrefix + "-data]"), flag = true, num = 0, nowObjTemp, isParent = ""; 258                     dom.each(function () { 259                         var data = $(this).attr(tagPrefix + "-data"); 260                         if (data.split(".").length > 2) { 261                             if (num === 0) { 262                                 nowObjTemp = $(this); 263                                 isParent = data; 264  } 265 
266                             flag = false; 267                             num++; 268  } 269  }); 270 
271                     if (flag) { 272  toddyDetailObj.BindEvent(); 273                     } else { 274                         /** 275  * 配置信息有誤提示使用者 276  * @type {string} 277                          */
278                         var tagName = nowObjTemp.get(0).tagName.toLowerCase(), 279                             alertTip = "<" + tagName + " " + tagPrefix + "-data=\"" + isParent + "\"></" + tagName + ">"; 280                         alert("目前我們只支持2級Model,配置信息有誤!\r\n" + alertTip); 281  } 282  } 283  }; 284 
285  toddyDetailObj.initEvent(); 286             return config.data; 287  } 288  }); 289 })(jQuery);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM