插件特点:
1.做动态添加行更便捷;
2.有常用回调函数使得插件更灵活;
3.支持链式调用。
下面直接上代码:
第一步首先引入jQuery,版本别太老就行,我是用的1.8.2的版本;
第二步引入addRowsPlugin.css,代码如下;
/**
* jQuery Add Or Del Rows Plugin Css
* Author: fcl<2438564025@qq.com>
* Author URL: http://www.uhang.com.cn
* Version: 1.0.0
*/
.addRowsTemp{
display: none;
}
第三步引入addRowsPlugin.js,代码如下;
/**
* jQuery Add Or Del Rows Plugin Js
* Author: fcl<2438564025@qq.com>
* Author URL: http://www.uhang.com.cn
* Version: 1.0.0
*/
;(function($){
//开启严格模式(消除代码运行的一些不安全之处,保证代码运行的安全;提高编译器效率,增加运行速度;为未来新版本的Javascript做好铺垫)
"use strict";
/* 错误日志 */
function addRowsPlugin_log(elem, tempCount, itemsCount, error) {
alert("==================错误日志===================\n" +
"【调用插件对象的各项参数】\n" +
" · 元素类型:" + elem.get(0).nodeName + "\n" +
" · 元素ID:" + elem.get(0).id + "\n"+
" · 元素class:" + elem.get(0).className + "\n" +
" · 模板个数:" + tempCount + "\n" +
" · 默认显示行数:" + itemsCount + "\n" +
"【错误原因】\n" +
" · " + error);
console.groupCollapsed("%c调用插件的对象","font-size:20px;color:red;");
console.log($(this));
console.groupEnd();
};
/* 多行添加插件 */
$.fn.addRowsPlugin = function(options){
//默认参数
var defaults = {
temp : ".addRowsTemp", //模板行的class选择器
items : ".addRowsItems", //默认显示行的class选择器
addBtn : ".addBtn", //添加按钮的选择器
delBtn : ".delBtn", //删除按钮的选择器
minCount : 0, //最小行数。默认0,至少有1行,剩余的最后一行可删除;设置为1,则至少有一行,剩余的最后一行不可删除
maxCount : -1, //最大行数。默认-1,行数无限制
message: function (operationType, msg) { return false; }, //operationType:操作类型;msg:提示的文字。行数验证函数,默认false不继续执行添加
AddBefore: function (btn) { return true; }, //btn:点击的添加按钮对象。添加前事件,默认true继续执行添加,如果返回false,则不继续执行添加
DelBefore: function (btn) { return true; }, //btn:点击的删除按钮对象。删除前事件,默认true继续执行删除,如果返回false,则不继续执行删除
AddAfter: function (elem) { }, //elem:返回新增行dom对象。添加后事件
DelAfter: function (elem) { }, //elem:返回剩余行dom对象。删除后事件
UpdateName: function (elem, index) { //elem:所有要更新name的行的dom对象;index:更新行的起始索引号。
elem.each(function (i,n) {
var reg = new RegExp('\\[(.+?)\\]',"g");//正则全局匹配[]
$.each($(n).find("[name]"), function(j , e) {
$(e).attr("name",$(e).attr("name").replace(reg,"["+(index+i)+"]"));
});
});
} //更新name函数
};
//操作类型
var operationTypeEnum = {
Add: "add",//添加
Del:"del"//删除
};
var options = $.extend(defaults,options); //传入的参数覆盖默认参数
$.each(this, function(i, n) {//对元素遍历绑定执行内容
var $container = $(n);//缓存调用插件的当前元素this(适应多个调用该插件的情况)
var $temp = $container.find(options.temp);//模板对象
//检测插件异常
if($temp.length!=1){
addRowsPlugin_log($container, $temp.length, $container.find(options.items).length, "插件未找到或找到多个模板");
return;
}else if(!($container.find(options.items).length>=options.minCount)){
addRowsPlugin_log($container, $temp.length, $container.find(options.items).length, "默认显示行数小于最小行数限制");
return;
}
//删除模板class标记,添加具体行class标记
$temp.removeClass(options.temp.substring(1, options.temp.length)).addClass(options.items.substring(1, options.items.length));
var tempHTML = $temp.prop("outerHTML");//模板html字符串
//删除模板dom
$temp.remove();
//添加行事件 (先移除绑定的事件,主要是避免重复绑定点击事件问题)
$container.off("click",options.addBtn).on("click",options.addBtn, function () {
//验证行数
if ($container.find(options.items).length == options.maxCount) {
if (!options.message.call(this, operationTypeEnum.Add, "最多只能添加" + options.maxCount + "行!")) {
return false;
}
}
//添加前执行
if (!options.AddBefore.call(this, $(this))) {
return false;
}
//当前行
var nowRow = $(this).closest(options.items);
//在当前行后面新增一行
nowRow.after(tempHTML);
//更新name
var _thisIndex = $container.find(options.items).index(nowRow)+1;//当前操作行的索引号+1作为更新行的起始索引号
options.UpdateName.call(this, nowRow.nextAll(options.items), _thisIndex);
//添加后执行
options.AddAfter.call(this, nowRow.next(options.items));
});
//删除行事件
$container.off("click",options.delBtn).on("click",options.delBtn, function () {
//验证行数
var rowCount = $container.find(options.items).length;
if (rowCount == options.minCount) {
if (!options.message.call(this, operationTypeEnum.Del, "最少要有" + options.minCount + "行!")) {
return false;
}
}
//删除前执行
if (!options.DelBefore.call(this, $(this))) {
return false;
}
//当前行
var nowRow = $(this).closest(options.items);
//缓存要更新name的行和起始索引号
var updateRow = nowRow.nextAll(options.items);
var _thisIndex = $container.find(options.items).index(nowRow);//当前操作行的索引号作为更新行的起始索引号
//缓存动态行父级容器
var rowsBox = nowRow.parent();
//删除当前行
nowRow.remove();
//如果删除的是最后一行就新增一行默认行
if(rowCount == 1){
rowsBox.append(tempHTML);
updateRow = rowsBox.find(options.items);
options.AddAfter.call(this, updateRow);//自动新增的默认行也同步添加后事件
}
//更新name
options.UpdateName.call(this, updateRow, _thisIndex);
//删除后执行
options.DelAfter.call(this, $container.find(options.items));
});
});
return $(this); //把节点对象返回去,为了支持链式调用。
}
})(jQuery);
第四步就是html部分了,主要是addRowsTemp标识的模板行和addRowsItems标识的具体行两段;
<body>
<fieldset>
<legend>log:</legend>
<div>
<textarea id="txtMsg" style="width: 100%; height: 100px;"></textarea>
</div>
</fieldset>
<fieldset>
<legend>多行添加实例</legend>
<table class="table" cellpadding="0" cellspacing="0" border="1" style="width: 100%;">
<thead align="center">
<tr>
<th>学号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>院系</th>
<th>班级</th>
<th>操作</th>
</tr>
</thead>
<tbody align="center">
<!--新增行模板加class标记:addRowsTemp-->
<tr height="40px" class="addRowsTemp">
<td>
<!--模板里的表单控件,name属性值中括号中的下标值可以是任意数字或字符串,但是不能为空-->
<input type="text" name="studentList[任意字符串].id"/>
</td>
<td>
<input type="text" name="studentList[999].name"/>
</td>
<td>
<select name="studentList[0].sex" style="width: 173px;">
<option value="">请选择</option>
<option value="男">男</option>
<option value="女">女</option>
</select>
</td>
<td>
<input type="number" min="0" name="studentList[0].age"/>
</td>
<td>
<input type="text" name="studentList[0].yx"/>
</td>
<td>
<input type="text" name="studentList[0].bj"/>
</td>
<td>
<!--添加按钮加class标记:addBtn-->
<button class="addBtn">添加</button>
<!--删除按钮加class标记:delBtn-->
<button class="delBtn">删除</button>
</td>
</tr>
<!--默认显示行加class标记:addRowsItems-->
<tr height="40px" class="addRowsItems">
<td>
<input type="text" name="studentList[0].id"/>
</td>
<td>
<input type="text" name="studentList[0].name"/>
</td>
<td>
<select name="studentList[0].sex" style="width: 173px;">
<option value="">请选择</option>
<option value="男">男</option>
<option value="女">女</option>
</select>
</td>
<td>
<input type="number" min="0" name="studentList[0].age"/>
</td>
<td>
<input type="text" name="studentList[0].yx"/>
</td>
<td>
<input type="text" name="studentList[0].bj"/>
</td>
<td>
<!--添加按钮加class标记:addBtn-->
<button class="addBtn">添加</button>
<!--删除按钮加class标记:delBtn-->
<button class="delBtn">删除</button>
</td>
</tr>
</tbody>
</table>
</fieldset>
</body>
最后一步就是调用插件初始化了
$(document).ready(function(){
var $msg = $("#txtMsg"), line = 1;
//初始化插件
$(".table").addRowsPlugin({
maxCount:10,
AddBefore: function (btn) {
$msg.val($msg.val() + (line++) + " 添加前事件:add" + "\r\n");
$msg.scrollTop($msg[0].scrollHeight);
console.log(btn);
return true;
},
DelBefore: function (btn) {
$msg.val($msg.val() + (line++) + " 删除前事件:del" + "\r\n");
$msg.scrollTop($msg[0].scrollHeight);
console.log(btn);
return true;
},
message: function (operationType, msg) {
$msg.val($msg.val() + (line++) + " 超过最小或最大行数提示函数:" + operationType + " "+ msg + "\r\n");
$msg.scrollTop($msg[0].scrollHeight);
return false;
},
AddAfter: function (elem) {
$msg.val($msg.val() + (line++) + " 添加后事件:add" + "\r\n");
$msg.scrollTop($msg[0].scrollHeight);
console.log(elem);
},
DelAfter: function (elem) {
$msg.val($msg.val() + (line++) + " 删除后事件:del" + "\r\n");
$msg.scrollTop($msg[0].scrollHeight);
console.log(elem);
}
});
});
如果您发现插件有什么bug或者能够完善的地方可以反馈给我,谢谢!