![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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发生变化,我们的页面上对应的节点应该发生对应的变化,所以,依据这个点,我们在需要做的在页面上面打下标识。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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);