这个题目有点让人迷惑,我就简单说明下,比如你要做一个表单数据保存的功能,这个表单(不是<form>,只是代表业务上的概念)可能分4、5步骤,每一个步骤里可能有10-20甚至50个属性,其中有10个属性是列表形式,而且很多select/checkbox/radio/tr等dom对象都是根据业务规则动态生成的,同时后面的步骤的页面根据前些步骤的数据变化。。。==反正就是在javascript做OO建模也相当复杂就是。面对这样的需求,我把我们项目中的设计实现挑一些说下,有待改进处其他筒子请不吝指教。
关于最基本的和必要的oo建模,模块划分,html-js/css-js/event-js分离等就不多讲了,就是类似backbones的那种做法,先把数据、事件、控制、html视图等在组织上区分开,粒度根据需求去定。
我
1. 第一点就是json绑定优于模板渲染
传统上我们做一个crud,update的页面总是和create的页面多少有点不一样,这里的绑定的意思无非就是让样式、视图和数据更分离一点,这样做有个好处就是,不用在jsp/php/**template里面写类似下面的代码:
a)
<select>
{foreach item}
{if val = ***}
selected option append
b)
<input name="" value="<c:out value="${savedVo.myProperty}" />"
c)
<input if val eq ** checked />
尤其是存在一些关联菜单,需要和server动态交互的时候,要做这样的update页面,恐怕除了copy一个create页面外要写n多if/else了
其实可以采用下面做法,原语如下:
// 由数据对象绑定到表单控件集合
bind: function(data, pre, skipFieldLl, _formContext){
if(!data)
return;
pre = pre || 'f_';
for(key in data){
if(skipFieldLl && skipFieldLl.contains(key))
continue;
var val = data[key];
var _target = $("[name='" + pre + key + "']", _formContext);
if(_target.size() == 0)
continue;
// 下拉框如果不是特别说明需要绑定则跳过,因为大多数情况下拉框有联动的事件处理
if(_target[0].nodeName == 'SELECT'){
if(_target.hasClass('bind'))
_target.val(val);
else
continue;
}
// 特殊处理,如果是单选
if(_target.is(':radio')){
_target.filter(function(){
return $(this).val() == val;
}).attr('checked', 'checked');
// 如果是多选,val即是数组
}else if(_target.is(':checkbox')){
_target.filter(function(){
return val.contains($(this).val());
}).attr('checked', 'checked');
// 一般情况就直接赋值
}else{
_target.val(val);
}
}
},
关于关联菜单,可以先赋予第一个触发联动的那个select,然后再trigger('change')
然后被关联的在生成option时候,再判断是否是selected,如下:
// 先正常的去根据上级关联菜单去生成option
**.optionAppend(ll, _sel); var targetVal = formData ? formData['saler_code'] : null; _sel.val(targetVal);
2. 其次是通过约定把主要的数据关联关系确定,可以减少一些类似功能copy代码和dom标示
a) 比如对input[name$=_phone]的对象绑定一个特定的校验的事件;
b) 对input[name^=step1_ownerCode]在页面渲染后去执行val(getFormData('step1', 'ownerCode')),然后attr('disabled', true),表示要显示第一个步骤中录入的ownerCode字段,因为这里只是显示,所以还做做成readonly或disabled,如果ownerCode是一个select,而这里要显示的是option text里的业务有意义的字样,则可以看第三点的做法,一样使用;
c) 对一个tbody里的tr,该tr的td里是input/select,要保存这些数据,只需在tr里有一个有意义的标示就可以了,然后td里的控件值根据index下标去获取,然后再统一命名回来——这只是一个例子,适用的地方还很多,就是不需要大量的id/name等标示每一个或每一组控件,通过相对css选择器即可以达到目的,尤其是当这些控件是根据server端数据有规律动态渲染出来的情况。
3. 在保存表单数据键值对,可以同时保存一份业务字样的键值对
对于一个context(dom操作范围)里的html控件的数据保存,我们传统的做法是一个<form>wrap一下,然后$.param作为ajax的参数。其实我绝对如果只是一般的表单场景(非二进制数据流上传等),可以用一下原语更方面获取对象,然后以json形式传给server端再做数据绑定。
// 由表单控件集合转换成数据对象
params: function(_inputs, pre){
pre = pre || 'f_';
var data = {};
_inputs.each(function(){
// 如果是checkbox or radio
if($(this).is(':checkbox') || $(this).is(':radio')){
if(!$(this).is(':checked'))
return;
}
var val = $(this).val();
// 有可能是select没有option
if(val)
val = val.trim();
// 如果有空格则重新赋值
if(this.nodeName == 'INPUT' || this.nodeName == 'TEXTAREA'){
if(val != $(this).val())
$(this).val(val);
}
var key = $(this).attr('name').substring(pre.length);
// 如果是多选,以数组形式保存
if($(this).is(':checkbox')){
if(!data[key])
data[key] = [];
data[key].push(val);
}else{
data[key] = val;
}
});
return data;
},
其中pre只是命名的一个约定,比如在这个context中,我们只需要name^=f_开头的控件
其中一个是f_saler_code,另一个是f_saler_name,分别就表示业务员编号和姓名。
这里我们只是获取到了控件里的value=""的那部分值,如果完成这一步骤,我们想知道一个radio的value对应的业务字样(如性别M="男"),可以这么做:在动态生成或死代码写这个radio的html时候,我们尽量保持一样的格式,如
<input type="checkbox" value="1" /> A <input type="checkbox" value="2"/> B
这样我们可以在保存一个context控件键值对时候同时保存一份业务字样的副本,代码如下:
getExtData: function(formData){
for(key in formData){
var _target = $("[name='" +pre + key + "']");
if(_target.size() == 0)
continue;
if(_target[0].nodeName == 'SELECT'){
extData[key] = _target.find('option:selected').text();
}else if(_target.is(':radio') || _target.is(':checkbox')){
// 用正则去匹配吧
extData[key] = ***
// 原语如下:
if(_target.is(':radio')){
var index = _target.index(_target.filter(':checked'));
// checkbox/radio和其label都在一个tag里,一个parent
var txt = _target.parent().html().trim();
return ***.getLabelMatched(txt, index);
}else if(_target.is(':checkbox')){
var txt = _target.parent().html().trim();
var ll = [];
_target.each(function(index){
if($(this).is(':checked')){
var label = ***.getLabelMatched(txt, index);
if(label)
ll.push(label);
}
});
if(ll.length > 0)
return ll.join(',');
}
}
}
}
本文介绍了一种优化表单数据处理的方法,通过JSON绑定代替模板渲染,减少代码冗余,并利用约定来简化DOM标识,同时提供了保存表单数据时同步保留业务字样的策略。
2185

被折叠的 条评论
为什么被折叠?



