jQuery 动态克隆表单的图像验证
jQuery Image Validation For Dynamically Cloned Form
我的 HTML 中有一个表单,当用户点击 #addOne 按钮时,该表单将被克隆并动态附加。对于任何输入错误,表单都已成功验证,我现在面临的唯一问题是它无法正确处理图像。假设我为第一个表单上传了一张图片,效果很好。但是,当我单击#addOne 按钮并为第二个表单上传图像时,问题就出现了。在为第二个表单上传图像之前,它已经在页面上显示了前一个表单中的图像。上传此表单的图像不会更新表单 2。相反,它会更改表单 1 的显示图像。我怎样才能使每个表单显示它自己上传的图像并得到正确验证?这是我的 jsFiddle
HTML
<div class="article_properties">
<form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
<p style="display: inline">Page Number</p>
<div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
<p style="display: inline" class="pageNumber"></p>
</div>
<textarea style="display: none" class="inputNumber" name="pages"></textarea>
<p>Image</p>
<input style="padding: 0px" type="file" name="image" class="pageImg">
<div class="imgContainer">
</div>
<p>Subtitle</p>
<input type="text" name="subtitle">
<p>Text</p>
<textarea name="text" rows="4"></textarea>
<input id="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
<hr style="border: 1px dotted lightgray; margin-bottom: 50px">
</form>
<a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
</a>
</div>
<!--End of article properties div-->
<div id="addOne">
<p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
<p>Finalize my article</p>
</div>
jQuery
var numPagesTemp = 4;
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
//Invoke functions for first form
add_validation_for_forms();
add_image_construction();
//Form validation
function add_validation_for_forms() {
$(".article_properties_form").each(function() {
$(this).validate({
errorElement: 'div',
rules: {
image: {
required: true,
extension: "jpg|jpeg|png",
minImageSize: {
width: 600,
height: 400
}
},
subtitle: {
required: true,
minlength: 2,
maxlength: 25
},
text: {
required: true,
minlength: 35,
maxlength: 275
}
},
messages: {
image: {
required: "This page needs an image",
extension: "You're only allowed to upload jpg or png images."
},
subtitle: {
required: "You have to provide a subtitle for this page!",
minlength: "Your subtitle must be at least 2 characters long",
maxlength: "Your subtitle must be less than 25 characters long"
},
text: {
required: "Please enter text for this page",
minlength: "Your text must be at least 35 characters long",
maxlength: "Your text must be less than 275 characters long"
},
},
});
});
}
//Adding a form
$('#addOne').click(function() {
numPagesTemp--;
var articlePropsTemplate = $('.article_properties_form:last').clone();
articlePropsTemplate.show();
$('.article_properties').append(articlePropsTemplate);
var articlePropsExpand = $('.expand:last').clone();
articlePropsExpand.text("Expand " + numPagesTemp);
articlePropsExpand.hide();
$('.article_properties').append(articlePropsExpand);
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
articlePropsTemplate[0].reset();
add_validation_for_forms();
add_image_construction();
articlePropsTemplate.validate().resetForm();
if (numPagesTemp == 1) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
//Adding Method
$.validator.addMethod('minImageSize', function(value, element, minSize) {
var imageSize = $(element).data('imageSize');
return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
}, function(minSize, element) {
return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
});
//Image Uploading
var $properties_btn = $('properties_btn'),
$imgContainer = $('.imgContainer'),
$pageImg = $('.pageImg');
function add_image_construction() {
$('.pageImg').change(function() {
$pageImg.removeData('imageSize');
$imgContainer.hide().empty();
var file = this.files[0];
if (file.type.match(/image\/.*/)) {
$properties_btn.attr('disabled', true);
var reader = new FileReader();
reader.onload = function() {
var $img = $('<img />').attr({
src: reader.result
});
$img.on('load', function() {
$imgContainer.append($img).show();
$pageImg.data('imageSize', {
width: $img.width(),
height: $img.height()
});
$img.css({
width: '400px',
height: '200px'
});
$properties_btn.attr('disabled', false);
validator.element($pageImg);
});
}
reader.readAsDataURL(file);
} else {
validator.element($pageImg);
}
});
}
I need to use my code
编辑、更新
将 class="properties_btn"
替换为 id="properties_btn"
以防止将重复的 id
附加到 document
;在 change
事件中定义了 validator
。
$(function() {
var numPagesTemp = 4;
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
//Invoke functions for first form
add_validation_for_forms();
add_image_construction();
//Form validation
function add_validation_for_forms() {
$(".article_properties_form").each(function() {
$(this).validate({
errorElement: 'div',
rules: {
image: {
required: true,
extension: "jpg|jpeg|png",
minImageSize: {
width: 600,
height: 400
}
},
subtitle: {
required: true,
minlength: 2,
maxlength: 25
},
text: {
required: true,
minlength: 35,
maxlength: 275
}
},
messages: {
image: {
required: "This page needs an image",
extension: "You're only allowed to upload jpg or png images."
},
subtitle: {
required: "You have to provide a subtitle for this page!",
minlength: "Your subtitle must be at least 2 characters long",
maxlength: "Your subtitle must be less than 25 characters long"
},
text: {
required: "Please enter text for this page",
minlength: "Your text must be at least 35 characters long",
maxlength: "Your text must be less than 275 characters long"
},
},
});
});
}
//Adding a form
$('#addOne').click(function() {
numPagesTemp--;
var articlePropsTemplate = $('.article_properties_form:last')
.clone();
articlePropsTemplate.find("img").remove();
$('.article_properties').append(articlePropsTemplate);
var articlePropsExpand = $('.expand:last').clone();
articlePropsExpand.text("Expand " + numPagesTemp);
articlePropsExpand.hide();
$('.article_properties').append(articlePropsExpand);
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
$("form:last")[0].reset();
add_validation_for_forms();
// add_image_construction();
articlePropsTemplate.validate().resetForm();
if (numPagesTemp == 1) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
//Adding Method
$.validator.addMethod('minImageSize', function(value, element, minSize) {
var imageSize = $(element).data('imageSize');
return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
}, function(minSize, element) {
return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
});
//Image Uploading
// var $properties_btn = $('.properties_btn'),
// $imgContainer = $('.imgContainer'),
// $pageImg = $('.pageImg');
function add_image_construction() {
$(document).on("change", ".pageImg", function(e) {
var form = $(this).closest("form");
var validator = form.validate();
$(this).removeData('imageSize');
form.find('.imgContainer').hide().empty();
var file = this.files[0];
if (file.type.match(/image\/.*/)) {
form.find('.properties_btn').attr('disabled', true);
var reader = new FileReader();
reader.onload = function() {
var $img = $('<img />').attr({
src: reader.result
});
$img.on('load', function() {
form.find('.imgContainer').append($img).show();
$(e.target).data('imageSize', {
width: $img.width(),
height: $img.height()
});
$img.css({
width: '400px',
height: '200px'
});
form.find('.properties_btn').attr('disabled', false);
validator.element(e.target);
});
}
reader.readAsDataURL(file);
} else {
validator.element(e.target);
}
});
}
})
form {
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/additional-methods.min.js"></script>
<div class="article_properties">
<form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
<p style="display: inline">Page Number</p>
<div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
<p style="display: inline" class="pageNumber"></p>
</div>
<textarea style="display: none" class="inputNumber" name="pages"></textarea>
<p>Image</p>
<input style="padding: 0px" type="file" name="image" class="pageImg">
<div class="imgContainer">
</div>
<p>Subtitle</p>
<input type="text" name="subtitle">
<p>Text</p>
<textarea name="text" rows="4"></textarea>
<input class="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
<hr style="border: 1px dotted lightgray; margin-bottom: 50px">
</form>
<a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
</a>
</div>
<!--End of article properties div-->
<div id="addOne">
<p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
<p>Finalize my article</p>
</div>
这是您尝试实现的简化版本,没有验证上传的文件
// maximum number of `form` elements which `document` should contain
var n = 4;
// display `form` index
function handleLabel() {
$("label").html(function(index, html) {
return "form #" + index
})
}
handleLabel();
function processFile() {
// preview uploaded image
$("<img>", {src: URL.createObjectURL(this.files[0])})
.insertAfter(this.nextElementSibling).after("<br>");
}
// handle file upload; delegate event to `document`
$(document).on("change", ":file", processFile);
// append cloned `form` to page
$("button").on("click", function() {
// if less than `n` forms
if ($("form").length < 4) {
// copy last `form` `.outerHTML` instead of using `.clone()`
$($("form:last")[0].outerHTML)
// remove `img` from `html`
.find("img").remove().end()
.insertAfter("form:last");
// update `form` `label` elements
handleLabel();
} else {
// detach `click` event from `button`
// when four `form` elements exist in `document`
$(this).off("click")
}
});
// handle `form` submit event
$(document).on("submit", "form", function(e) {
var img = $(this).find("img")[0];
// check `img` `width`, `height`
if (img.naturalWidth < 600
|| img.naturalHeight < 400) {
e.preventDefault();
this.reset();
alert("invalid img width or height")
}
})
form {
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<form>
<fieldset>
<label></label><br>
<input name="file" type="file" accept=".jpg,.jpeg,.png" required />
<br>
<input type="submit" />
</fieldset>
</form>
<button>
add form
</button>
jsfiddle https://jsfiddle.net/hLjvffpv/5/
克隆时我的建议是:
Never clone elements that have been instrumented.
通过检测,我的意思是他们已经 JavaScript 设置了行为,比如事件处理。
改为执行以下操作:
(1) 在元素被检测之前克隆它们并将克隆保存在变量中。
var $CLONED_FORM = $('.article_properties_form:first').clone();
(2) 提供一个函数来检测要克隆的元素集。
function initializeForm($form, pageNum) {
// Set up form validation here.
// Also attach the change-event handler for the file input here.
}
(3) 为页面上已有的集合调用函数。
$('.article_properties_form').each(function() {
initializeForm($(this), numPagesTemp--);
});
(4) 当你想添加另一组元素时,克隆克隆并添加它,并调用函数就可以了。
$('#addOne').click(function() {
var $newForm = $CLONED_FORM.clone().appendTo('.article_properties').show();
initializeForm($newForm, numPagesTemp--);
if (numPagesTemp == 0) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
您还需要将验证器对象存储在名为 validator
.
的变量中
var validator = $form.validate({
此外,克隆时应避免重复 id
值。您在表单提交按钮上有一个 id
,但似乎不需要它,所以也许您可以删除它。
我的 HTML 中有一个表单,当用户点击 #addOne 按钮时,该表单将被克隆并动态附加。对于任何输入错误,表单都已成功验证,我现在面临的唯一问题是它无法正确处理图像。假设我为第一个表单上传了一张图片,效果很好。但是,当我单击#addOne 按钮并为第二个表单上传图像时,问题就出现了。在为第二个表单上传图像之前,它已经在页面上显示了前一个表单中的图像。上传此表单的图像不会更新表单 2。相反,它会更改表单 1 的显示图像。我怎样才能使每个表单显示它自己上传的图像并得到正确验证?这是我的 jsFiddle
HTML
<div class="article_properties">
<form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
<p style="display: inline">Page Number</p>
<div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
<p style="display: inline" class="pageNumber"></p>
</div>
<textarea style="display: none" class="inputNumber" name="pages"></textarea>
<p>Image</p>
<input style="padding: 0px" type="file" name="image" class="pageImg">
<div class="imgContainer">
</div>
<p>Subtitle</p>
<input type="text" name="subtitle">
<p>Text</p>
<textarea name="text" rows="4"></textarea>
<input id="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
<hr style="border: 1px dotted lightgray; margin-bottom: 50px">
</form>
<a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
</a>
</div>
<!--End of article properties div-->
<div id="addOne">
<p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
<p>Finalize my article</p>
</div>
jQuery
var numPagesTemp = 4;
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
//Invoke functions for first form
add_validation_for_forms();
add_image_construction();
//Form validation
function add_validation_for_forms() {
$(".article_properties_form").each(function() {
$(this).validate({
errorElement: 'div',
rules: {
image: {
required: true,
extension: "jpg|jpeg|png",
minImageSize: {
width: 600,
height: 400
}
},
subtitle: {
required: true,
minlength: 2,
maxlength: 25
},
text: {
required: true,
minlength: 35,
maxlength: 275
}
},
messages: {
image: {
required: "This page needs an image",
extension: "You're only allowed to upload jpg or png images."
},
subtitle: {
required: "You have to provide a subtitle for this page!",
minlength: "Your subtitle must be at least 2 characters long",
maxlength: "Your subtitle must be less than 25 characters long"
},
text: {
required: "Please enter text for this page",
minlength: "Your text must be at least 35 characters long",
maxlength: "Your text must be less than 275 characters long"
},
},
});
});
}
//Adding a form
$('#addOne').click(function() {
numPagesTemp--;
var articlePropsTemplate = $('.article_properties_form:last').clone();
articlePropsTemplate.show();
$('.article_properties').append(articlePropsTemplate);
var articlePropsExpand = $('.expand:last').clone();
articlePropsExpand.text("Expand " + numPagesTemp);
articlePropsExpand.hide();
$('.article_properties').append(articlePropsExpand);
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
articlePropsTemplate[0].reset();
add_validation_for_forms();
add_image_construction();
articlePropsTemplate.validate().resetForm();
if (numPagesTemp == 1) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
//Adding Method
$.validator.addMethod('minImageSize', function(value, element, minSize) {
var imageSize = $(element).data('imageSize');
return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
}, function(minSize, element) {
return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
});
//Image Uploading
var $properties_btn = $('properties_btn'),
$imgContainer = $('.imgContainer'),
$pageImg = $('.pageImg');
function add_image_construction() {
$('.pageImg').change(function() {
$pageImg.removeData('imageSize');
$imgContainer.hide().empty();
var file = this.files[0];
if (file.type.match(/image\/.*/)) {
$properties_btn.attr('disabled', true);
var reader = new FileReader();
reader.onload = function() {
var $img = $('<img />').attr({
src: reader.result
});
$img.on('load', function() {
$imgContainer.append($img).show();
$pageImg.data('imageSize', {
width: $img.width(),
height: $img.height()
});
$img.css({
width: '400px',
height: '200px'
});
$properties_btn.attr('disabled', false);
validator.element($pageImg);
});
}
reader.readAsDataURL(file);
} else {
validator.element($pageImg);
}
});
}
I need to use my code
编辑、更新
将 class="properties_btn"
替换为 id="properties_btn"
以防止将重复的 id
附加到 document
;在 change
事件中定义了 validator
。
$(function() {
var numPagesTemp = 4;
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
//Invoke functions for first form
add_validation_for_forms();
add_image_construction();
//Form validation
function add_validation_for_forms() {
$(".article_properties_form").each(function() {
$(this).validate({
errorElement: 'div',
rules: {
image: {
required: true,
extension: "jpg|jpeg|png",
minImageSize: {
width: 600,
height: 400
}
},
subtitle: {
required: true,
minlength: 2,
maxlength: 25
},
text: {
required: true,
minlength: 35,
maxlength: 275
}
},
messages: {
image: {
required: "This page needs an image",
extension: "You're only allowed to upload jpg or png images."
},
subtitle: {
required: "You have to provide a subtitle for this page!",
minlength: "Your subtitle must be at least 2 characters long",
maxlength: "Your subtitle must be less than 25 characters long"
},
text: {
required: "Please enter text for this page",
minlength: "Your text must be at least 35 characters long",
maxlength: "Your text must be less than 275 characters long"
},
},
});
});
}
//Adding a form
$('#addOne').click(function() {
numPagesTemp--;
var articlePropsTemplate = $('.article_properties_form:last')
.clone();
articlePropsTemplate.find("img").remove();
$('.article_properties').append(articlePropsTemplate);
var articlePropsExpand = $('.expand:last').clone();
articlePropsExpand.text("Expand " + numPagesTemp);
articlePropsExpand.hide();
$('.article_properties').append(articlePropsExpand);
$('.pageNumber:last').text(numPagesTemp);
$('.inputNumber:last').text(numPagesTemp);
$("form:last")[0].reset();
add_validation_for_forms();
// add_image_construction();
articlePropsTemplate.validate().resetForm();
if (numPagesTemp == 1) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
//Adding Method
$.validator.addMethod('minImageSize', function(value, element, minSize) {
var imageSize = $(element).data('imageSize');
return (imageSize) && (imageSize.width >= minSize.width) && (imageSize.height >= minSize.height);
}, function(minSize, element) {
return ($(element).data('imageSize')) ? ("Your image's size must be at least " + minSize.width + "px by " + minSize.height + "px") : "Selected file is not an image.";
});
//Image Uploading
// var $properties_btn = $('.properties_btn'),
// $imgContainer = $('.imgContainer'),
// $pageImg = $('.pageImg');
function add_image_construction() {
$(document).on("change", ".pageImg", function(e) {
var form = $(this).closest("form");
var validator = form.validate();
$(this).removeData('imageSize');
form.find('.imgContainer').hide().empty();
var file = this.files[0];
if (file.type.match(/image\/.*/)) {
form.find('.properties_btn').attr('disabled', true);
var reader = new FileReader();
reader.onload = function() {
var $img = $('<img />').attr({
src: reader.result
});
$img.on('load', function() {
form.find('.imgContainer').append($img).show();
$(e.target).data('imageSize', {
width: $img.width(),
height: $img.height()
});
$img.css({
width: '400px',
height: '200px'
});
form.find('.properties_btn').attr('disabled', false);
validator.element(e.target);
});
}
reader.readAsDataURL(file);
} else {
validator.element(e.target);
}
});
}
})
form {
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/additional-methods.min.js"></script>
<div class="article_properties">
<form class="article_properties_form" action="" method="POST" enctype="multipart/form-data">
<p style="display: inline">Page Number</p>
<div style="background-color: #FF355E; padding: 5px; display: inline; margin-left: 5px">
<p style="display: inline" class="pageNumber"></p>
</div>
<textarea style="display: none" class="inputNumber" name="pages"></textarea>
<p>Image</p>
<input style="padding: 0px" type="file" name="image" class="pageImg">
<div class="imgContainer">
</div>
<p>Subtitle</p>
<input type="text" name="subtitle">
<p>Text</p>
<textarea name="text" rows="4"></textarea>
<input class="properties_btn" type="submit" value="Submit/Update" name="properties_submit">
<hr style="border: 1px dotted lightgray; margin-bottom: 50px">
</form>
<a style="display: none; text-align: center; margin: 50px; font-size: 25px" class="expand" href="#">
</a>
</div>
<!--End of article properties div-->
<div id="addOne">
<p>+Add page</p>
</div>
<div class="nextBtn" style="display: none">
<p>Finalize my article</p>
</div>
这是您尝试实现的简化版本,没有验证上传的文件
// maximum number of `form` elements which `document` should contain
var n = 4;
// display `form` index
function handleLabel() {
$("label").html(function(index, html) {
return "form #" + index
})
}
handleLabel();
function processFile() {
// preview uploaded image
$("<img>", {src: URL.createObjectURL(this.files[0])})
.insertAfter(this.nextElementSibling).after("<br>");
}
// handle file upload; delegate event to `document`
$(document).on("change", ":file", processFile);
// append cloned `form` to page
$("button").on("click", function() {
// if less than `n` forms
if ($("form").length < 4) {
// copy last `form` `.outerHTML` instead of using `.clone()`
$($("form:last")[0].outerHTML)
// remove `img` from `html`
.find("img").remove().end()
.insertAfter("form:last");
// update `form` `label` elements
handleLabel();
} else {
// detach `click` event from `button`
// when four `form` elements exist in `document`
$(this).off("click")
}
});
// handle `form` submit event
$(document).on("submit", "form", function(e) {
var img = $(this).find("img")[0];
// check `img` `width`, `height`
if (img.naturalWidth < 600
|| img.naturalHeight < 400) {
e.preventDefault();
this.reset();
alert("invalid img width or height")
}
})
form {
border: 1px solid blue;
padding: 10px;
margin: 10px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<form>
<fieldset>
<label></label><br>
<input name="file" type="file" accept=".jpg,.jpeg,.png" required />
<br>
<input type="submit" />
</fieldset>
</form>
<button>
add form
</button>
jsfiddle https://jsfiddle.net/hLjvffpv/5/
克隆时我的建议是:
Never clone elements that have been instrumented.
通过检测,我的意思是他们已经 JavaScript 设置了行为,比如事件处理。
改为执行以下操作:
(1) 在元素被检测之前克隆它们并将克隆保存在变量中。
var $CLONED_FORM = $('.article_properties_form:first').clone();
(2) 提供一个函数来检测要克隆的元素集。
function initializeForm($form, pageNum) {
// Set up form validation here.
// Also attach the change-event handler for the file input here.
}
(3) 为页面上已有的集合调用函数。
$('.article_properties_form').each(function() {
initializeForm($(this), numPagesTemp--);
});
(4) 当你想添加另一组元素时,克隆克隆并添加它,并调用函数就可以了。
$('#addOne').click(function() {
var $newForm = $CLONED_FORM.clone().appendTo('.article_properties').show();
initializeForm($newForm, numPagesTemp--);
if (numPagesTemp == 0) {
$('#addOne').hide();
$(".nextBtn").show();
}
});
您还需要将验证器对象存储在名为 validator
.
var validator = $form.validate({
此外,克隆时应避免重复 id
值。您在表单提交按钮上有一个 id
,但似乎不需要它,所以也许您可以删除它。