有时候,页面中的输入框之间是互相关联的。最简单的,比如输入一个字段,后面紧跟着的是这个字段对应的比例等等,这里把这些关联的一组输入框称作输入框组。在页面表单中,我们可能需要整体地添加一个输入框组,或者删除一个输入框组,这些都是很常见的功能。
本文以责任部门和责任部门承担的责任比例两个输入框为例介绍如何实现。
效果

如上,点击+会在最后添加一行责任部门和责任比例的输入框组,点击×删除对应的一行输入框组。
思路
其实很简单,利用jquery的dom元素选择器。
添加时我们可以以上图中下面那条水平线为参照(不一定非要是水平线,根据实际情况,选择输入框组最下面的元素为参照就OK),在它之前添加一行输入框组,具体包括一个select元素、一个input元素和一个删除按钮。
而删除时,获得当前删除按钮的父元素,也就是该输入框组的div,将其remove掉即可。
代码
页面初始时,没有输入框组,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <div class="form-group"> <label class="col-sm-3 control-label">责任部门:</label> <div class="col-sm-1"> <button class="btn btn-sm btn-success" type="button" onclick="addTeam()"><span class="glyphicon glyphicon-plus"></span></button> </div> </div>
<div class="form-group"> <label class="col-sm-3 col-sm-offset-3">责任部门</label> <label class="col-sm-3">责任比例(%)</label> </div>
<div id="teamHr" class="form-group"> <label class="col-sm-12 control-label"><hr /></label> </div>
|
可以看到有个3个div,最后一个代表水平线,作为添加输入框组的参照。
也可以看到添加按钮上的onclick属性,为addTeam函数,实现添加输入框组,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| function addTeam() { $("#teamHr").before('\ <div class="form-group" name="addDiv">\ <div class="col-sm-3 col-sm-offset-3">\ <div>\ <select class="form-control" name="teams">\ <option value="BI">BI</option>\ <option value="CC">CC</option>\ <option value="IT">IT</option>\ <option value="OPS">OPS</option>\ <option value="TBD">TBD</option>\ <option value="UED">UED</option>\ </select>\ </div>\ </div>\ <div class="col-sm-3">\ <div class="input-group">\ <input class="form-control" type="text" name="percent" value="100"/>\ <span class="input-group-addon">% </span>\ </div>\ </div>\ <div class="col-sm-1">\ <button class="btn btn-sm btn-danger" type="button" onclick="deleteTeam(this)"><span class="glyphicon glyphicon-remove"></span></button>\ </div>\ </div>'); $('#modifyForm').bootstrapValidator('addField', 'percent', { validators: { notEmpty: { message: '责任比例不能为空' }, numeric: { message: '必须为数字' }, lessThan: { value: 100, inclusive: true, message: '不能大于100' }, greaterThan: { value: 0, inclusive: true, message: '不能小于0' } } }); }
|
添加时用before方法,在水平线前动态添加输入框组的html。
bootstrapValidator是一个前端校验插件,是我给责任比例输入框动态增加校验的,如果不需要删除掉这段代码就好。
添加的输入框组中删除按钮onclick对应的函数,更简单:
1 2 3
| function deleteTeam(ele) { $(ele).parents("div[name='addDiv']").remove(); }
|
以上代码就实现了这个功能了。
下面说一下,这种情况时,表单的序列化。
序列化
因为输入框组可以有多个,所以没有id属性,但是有相同的name属性。序列化时,我们把具有相同name属性的元素使用数组表示就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function serializeForm(form) { var formData = form.serializeArray(); var obj = {}; $.each(formData, function () { if (obj[this.name] !== undefined) { if (!$.isArray(obj[this.name])) { obj[this.name] = [obj[this.name]]; } obj[this.name].push(this.value || ''); } else { obj[this.name] = this.value || ''; } }); return obj; }
|
serializeArray()会把表单所有元素的name和对应的value以KV形式输出,这里转成json形式。
对于同名的元素,使用$.isArray()判断该元素是不是数组,不是则变为数组,并把value加进去。
上面函数返回的是json形式的obj,如果要转为json,再调用JSON.stringify(obj)即可。
关于判断数组
js判断对象是不是数组,之前用if(!obj.push)判断,但并不总是ok,查阅到以下方法。
1.Array.isArray(obj) 调用数组的isArray方法。ES5的新方法可能有浏览器兼容性问题
2.obj instanceof Array
判断对象是否是Array的实例,只对当前页有效,如果有子window则在其中判断不正确
3.Object.prototype.toString.call(obj) ===‘[object Array]’
Object.prototype.toString方法会取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似[object Array]的字符串作为结果,call用来改变toString的this指向为待检测的对象
4.判断对象是否有push等数组的一些方法。(这个方法有兼容问题,但也是一个简单易用的方法)
5.obj.constructor===Array //true 不保险,constructor属性可以随意修改。
有的甚至把以上所有方法用或运算来使用…
后来发现jq有个非常方便的方法$.isArray(),它先用Array.isArray判断,不支持则用Object.prototype.toString.call(obj)===‘[object Array]’,是个很方便的方法,经chrome、firefox、edge、ie10兼容性测试也都ok。