
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 });
先上一個代碼,主要是雙向綁定的基本概念就是在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>
我們這里推薦使用的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);