jqeury 复制html,利用 jQuery Clone进行复制操作

最近客串了一把前端,有行复制的功能用 jQuery 来实现了。感觉比以前原生js用 CreateElement 要简单多了,但还是遇到了一些陷阱比如IE7的bug,这里记录下来。先看看 table 的样子:这里3行是一组,按下"Copy"连值复制,按下"Add"只增加行不复制值。calendar 使用的是 jQuery UI 里的 datepicker

下图只是一个简单的demo,没有复杂的样式表:

429f2755dce28b6ab889302dd0bb36dc.gif

为了灵活对应不同的表格,提取了一个共通的 js 来处理,作为使用前提:

1. table 必须有 id;

2. 有 id 的 tr 才会被复制;(tr的id从1开始编号)

3. table 内所有id都必须以 xxx_n 编号function RowCopyUtility(opts) {

// 表格Id

this.tableId = opts.tableId;

// 分组内有多少行

this.rowGroupNumber = opts.rowGroupNumber;

// 一组内Button对应的方法Map(key=Button value, value=对应方法名)

// 所有方法都应以 function (idx) 方式调用

this.buttonHandlers = opts.buttonHandlers;

this._countForRowsGroup = -1;

this._keyForRow = -1;

this.getTargetRowGroup = function(groupIdx) {

var rows = [];

if (groupIdx > 0) {

for(var i=1; i

rows[i-1] = $("#row" + i + "_" + groupIdx);

}

} else {

for(var i=0; i

rows[i] = $("#" + this.tableId + " tr[id]").eq(i);

}

}

return rows;

};

this.addRow = function (groupIdx, needCopyValue) {

if (this._countForRowsGroup == -1) {

this._countForRowsGroup = ($("#" + this.tableId + " tr[id]").length - 1)/this.rowGroupNumber;

this._keyForRow = parseInt($("#" + this.tableId + " tr[id]:not(#row_add):last").attr("id").split("_")[1]) + 1;

}

if (groupIdx == 0) {

var firstRow = $("#" + this.tableId + " tr[id]:first");

var currentIdx = firstRow.attr("id").split("_")[1];

groupIdx = currentIdx;

}

var regForId = new RegExp("^(\\w+_)" + groupIdx + "$");

var regForName = new RegExp("^(\\w+_)" + groupIdx + "$");

var regForRadioId = new RegExp("^(\\w+_)" + groupIdx + "(.*)$");

var targetRows = this.getTargetRowGroup(groupIdx);

// 重要:注意闭包参数的作用域

var idx = this._keyForRow;

for(var i=0; i

// clone target rows

var cloneRow = targetRows[i].clone(false);

var newRowId = cloneRow.attr("id").split("_")[0] + "_" + idx;

cloneRow.attr("id", newRowId);

var radios = [];

cloneRow.find("[id]").each(function() {

var id = $(this).attr("id");

var oldId = id;

var name = $(this).attr("name");

id = id.replace(regForId, "$1" + idx);

$(this).attr("id", id);

var newname = name.replace(regForName, "$1" + idx);

$(this).attr("name", newname);

if ($(this).hasClass("hasDatepicker")) {

$(this).removeClass("hasDatepicker");

}

if ($(this).attr("type") == "checkbox") {

if($(this).next().attr("for") != "") {

$(this).next().attr("for", id);

}

if (!needCopyValue) {

$(this).attr("checked", "");

}

}

else if ($(this).attr("type") == "radio") {

id = id.replace(regForRadioId, "$1" + idx);

$(this).attr("id", id);

var radio = new Object();

radio.id = id;

radio.oldId = oldId;

radio.name = name;

radio.newname = newname;

// IE7's Bug

radio.checked = document.getElementById(oldId).checked;

radios[radios.length] = radio;

if($(this).next().attr("for") != "") {

$(this).next().attr("for", id);

}

if (!needCopyValue) {

$(this).attr("checked", "");

}

}

else if ($(this).attr("tagName") == "SELECT") {

if (needCopyValue) {

$(this).val(document.getElementById(oldId).value);

}

}

else if ($(this).attr("tagName") == "TEXTAREA" ||

$(this).attr("type") == "text" ||

$(this).attr("type") == "hidden") {

if (!needCopyValue) {

$(this).val("");

}

}

});

// insert into document

cloneRow.insertBefore("#" + this.tableId + " tr:last");

// replace name for radio

for(var n=0; n

document.getElementById(radios[n].id).outerHTML =

document.getElementById(radios[n].id).outerHTML.replace(radios[n].name, radios[n].newname);

// IE7's Bug

document.getElementById(radios[n].oldId).checked = radios[n].checked;

}

// Event Handler

var maps = this.buttonHandlers;

cloneRow.find("input:button").each(function() {

var value = $(this).attr("value");

var funcName = maps[value];

if (funcName != undefined) {

var func = null;

func = function() { eval(funcName + "(" + idx + ")"); };

if (func != null) {

$(this).attr("onclick", "");

$(this).unbind("click");

$(this).attr("onclick", "").click(func);

}

}

});

}

this._countForRowsGroup++;

this._keyForRow++;

};

this.copyRow = function(groupIdx) {

this.addRow(groupIdx, true);

};

this.deleteRow = function(groupIdx) {

if (this._countForRowsGroup == -1) {

this._countForRowsGroup = ($("#" + this.tableId + " tr[id]").length - 1)/this.rowGroupNumber;

this._keyForRow = parseInt($("#" + this.tableId + " tr[id]:not(#row_add):last").attr("id").split("_")[1]) + 1;

}

var allRows = $("#" + this.tableId + " tr[id]");

var miniRowsCount = this.rowGroupNumber + 1;

var tbl = $("#" + this.tableId);

if (allRows.length == miniRowsCount) {

tbl.find("input:text").each(function() { $(this).val(""); });

tbl.find("textarea").each(function() { $(this).val(""); });

tbl.find("input:hidden").each(function() { $(this).val(""); });

tbl.find("input:radio").each(function() { $(this).attr("checked", ""); });

tbl.find("input:checkbox").each(function() { $(this).attr("checked", ""); });

tbl.find("select").each(function() { document.getElementById($(this).attr("id")).selectedIndex = 0; });

tbl.find(".fg-common-field-errored").each(function() {

$(this).removeClass("fg-common-field-errored");

});

return;

}

for(var i=1; i

tbl.find("#row" + i + "_" + groupIdx).remove();

}

this._countForRowsGroup--;

};

}

实际遇到的问题与解决办法:

1. jQuery 的 Clone() 方法,就算传入 false,元素的事件依然会被复制过来。(IE测试)

2. attr("name", name); 在IE中,不会直接替换掉,而是生成 submitName 保存。在 IE7 里 radio 会因为 name 相同而出现问题。

3. 在大量的匿名方法中,特别要注意闭包封送参数的作用域。

4. IE7里的Bug:在radio被复制时,原来的元素的选择值就没了。因此在复制前保存了复制源的radio属性,加入document之后再次设定:// replace name for radio

for(var n=0; n

document.getElementById(radios[n].id).outerHTML =

document.getElementById(radios[n].id).outerHTML.replace(radios[n].name, radios[n].newname);

// IE7's Bug

document.getElementById(radios[n].oldId).checked = radios[n].checked;

}

5. jQuery里清除事件单独用 attr("onclick", "") 并不好用;后期用 click(function) 绑定的事件用 unbind("click") 可以移除。if (func != null) {

$(this).attr("onclick", "");

$(this).unbind("click");

$(this).attr("onclick", "").click(func);

}

6. jQuery UI 的 DatePicker 当创建了 datepicker 之后,可以通过 hasClass("hasDatepick") 判断是否存在,否则在复制之后有问题。

(多次复制之后 datepicker settings 会莫名其妙丢失)

7. 其他,剩下就是要注意 jQuery 选择器不要过度使用了,越复杂的表达式效率越低。

顺便推荐看一下:15个值得开发人员关注的jQuery开发技巧和心得

还要说下IE9 的 debug 工具真心不错,提高不少开发效率哦一定要利用。

0118becace6ed7e66408a7da4a57cb3f.gif

就这些,希望能对大家有帮助。最后附上,测试用的 html:

body{font-family:'Open Sans',arial,sans-serif;}

tr{height:30px}

input.button{width:60px}

table.main {

border-width: 2px;

border-spacing: 1px;

border-style: solid;

border-color: gray;

border-collapse: collapse;

background-color: white;

}

table.main th {

border-width: 1px;

padding: 5px;

border-style: inset;

border-color: gray;

background-color: #f0f0f0;

-moz-border-radius: ;

}

table.main td {

border-width: 1px;

padding: 5px;

border-style: inset;

border-color: gray;

background-color: white;

-moz-border-radius: ;

}

var rowUtil = new RowCopyUtility(

{

tableId: "tab1",

rowGroupNumber: 3,

buttonHandlers: {"Copy":"copyRows", "Delete":"deleteRows", "calendar":"showDatepicker", "some button":"someButtonClick"}

}

);

function showDatepicker(idx) {

var textId = "#calendar_" + idx;

if (!$(textId).hasClass("hasDatepicker")) {

var text = $(textId).datepicker({

showOn : "calendar",

dateFormat : "yy/mm/dd"

});

}

$(textId).datepicker('show');

}

function addRows() {

rowUtil.addRow(0, false);

}

function copyRows(idx) {

rowUtil.copyRow(idx);

}

function deleteRows(idx) {

rowUtil.deleteRow(idx);

}

function someButtonClick(idx) {

alert(idx);

}

Header1Header2Header3Header4
text:

Raido_A

Radio_B

---select---

select option1

select option2

Check_A

Check_B

textarea:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值