jQuery表单处理

jQuery提供了强大的表单处理功能,可以简化表单操作、验证、提交等流程,提升用户体验和开发效率。

1. 表单基础

jQuery提供了一系列方法来选择和操作表单元素。

表单元素操作:
操作按钮:
操作结果将显示在这里...

1.1 表单选择器

jQuery提供了专门的表单选择器:


// 基本表单元素选择器
$(":input")          // 选择所有input、textarea、select和button元素
$(":text")           // 选择所有type="text"的input元素
$(":password")       // 选择所有type="password"的input元素
$(":radio")          // 选择所有单选框
$(":checkbox")       // 选择所有复选框
$(":submit")         // 选择所有提交按钮
$(":reset")          // 选择所有重置按钮
$(":button")         // 选择所有按钮
$(":image")          // 选择所有图片按钮
$(":file")           // 选择所有文件上传控件
$(":hidden")         // 选择所有隐藏元素(包括type="hidden")
$(":selected")       // 选择所有选中的option元素
$(":checked")        // 选择所有选中的复选框和单选框
$(":enabled")        // 选择所有启用的元素
$(":disabled")       // 选择所有禁用的元素
$(":focus")          // 选择当前聚焦的元素

// 组合使用
$("form :input")                     // 选择表单内所有输入元素
$("form :text:enabled")              // 选择表单内所有启用的文本框
$("#myForm input[type='text']")      // 选择指定类型的输入框
$("input[name='username']")          // 根据name属性选择
$("input:not(:disabled)")            // 选择没有禁用的输入框

// 实用示例
// 选择所有必填字段
$("input[required], select[required], textarea[required]")

// 选择可见的表单元素
$(":input:visible")

// 选择特定表单内的元素
$("#loginForm :input")

// 选择第一个表单元素
$("form:first :input:first")

// 选择最后一个表单元素
$("form:last :input:last")
                            

1.2 获取和设置表单值


// 获取文本框值
const username = $("#username").val();        // 获取值
$("#username").val("新用户名");               // 设置值

// 获取和设置密码框
const password = $("#password").val();
$("#password").val("新密码");

// 获取和设置文本区域
const message = $("#message").val();
$("#message").val("新的消息内容");

// 获取和设置下拉框
const city = $("#city").val();                // 获取选中的值
$("#city").val("sh");                         // 设置选中值

// 获取和设置单选按钮
const gender = $("input[name='gender']:checked").val(); // 获取选中的值
$("input[name='gender'][value='male']").prop("checked", true); // 设置选中

// 获取和设置复选框
// 单个复选框
const isAgree = $("#agree").prop("checked");  // 获取是否选中
$("#agree").prop("checked", true);            // 设置选中

// 多个复选框 - 获取选中的值
const hobbies = [];
$("input[name='hobbies']:checked").each(function() {
    hobbies.push($(this).val());
});

// 多个复选框 - 设置选中
$("input[name='hobbies'][value='reading']").prop("checked", true);
$("input[name='hobbies'][value='music']").prop("checked", true);

// 批量设置表单值
function setFormValues(data) {
    $.each(data, function(key, value) {
        const $element = $(`[name="${key}"]`);

        if($element.is(":checkbox")) {
            // 处理复选框
            if(Array.isArray(value)) {
                $element.prop("checked", false);
                value.forEach(val => {
                    $(`[name="${key}"][value="${val}"]`).prop("checked", true);
                });
            }
        } else if($element.is(":radio")) {
            // 处理单选按钮
            $(`[name="${key}"][value="${value}"]`).prop("checked", true);
        } else if($element.is("select")) {
            // 处理下拉框
            $element.val(value);
        } else {
            // 处理文本框等
            $element.val(value);
        }
    });
}

// 示例:设置用户数据
const userData = {
    username: "张三",
    email: "zhangsan@example.com",
    gender: "male",
    city: "sh",
    hobbies: ["reading", "sports"]
};

setFormValues(userData);

// 批量获取表单值
function getFormValues(selector) {
    const data = {};

    $(selector).find(":input").each(function() {
        const $this = $(this);
        const name = $this.attr("name");

        if(!name) return;

        if($this.is(":checkbox")) {
            // 复选框:存储为数组
            if(!data[name]) data[name] = [];
            if($this.is(":checked")) {
                data[name].push($this.val());
            }
        } else if($this.is(":radio")) {
            // 单选按钮:只有选中的才存储
            if($this.is(":checked")) {
                data[name] = $this.val();
            }
        } else if($this.is("select[multiple]")) {
            // 多选下拉框
            data[name] = $this.val() || [];
        } else {
            // 其他输入框
            data[name] = $this.val();
        }
    });

    return data;
}

// 使用示例
const formData = getFormValues("#userForm");
console.log(formData);
                            

1.3 表单序列化


// 基本序列化
const serialized = $("#myForm").serialize();
// 结果: "username=张三&email=zhangsan%40example.com&city=sh"

// 序列化为数组
const serializedArray = $("#myForm").serializeArray();
// 结果: [
//   {name: "username", value: "张三"},
//   {name: "email", value: "zhangsan@example.com"},
//   {name: "city", value: "sh"}
// ]

// 转换为对象
function serializeObject(formSelector) {
    const array = $(formSelector).serializeArray();
    const obj = {};

    $.each(array, function() {
        if(obj[this.name] !== undefined) {
            if(!Array.isArray(obj[this.name])) {
                obj[this.name] = [obj[this.name]];
            }
            obj[this.name].push(this.value);
        } else {
            obj[this.name] = this.value;
        }
    });

    return obj;
}

// 包含文件上传的序列化
// 注意:serialize()不包含文件输入,需要使用FormData
const formData = new FormData($("#myForm")[0]);

// 手动构建FormData
function buildFormData(formSelector) {
    const formData = new FormData();
    const $form = $(formSelector);

    // 添加普通字段
    $form.find(":input").not(":file").each(function() {
        const $this = $(this);
        const name = $this.attr("name");

        if(!name) return;

        if($this.is(":checkbox") || $this.is(":radio")) {
            if($this.is(":checked")) {
                formData.append(name, $this.val());
            }
        } else if($this.is("select[multiple]")) {
            const values = $this.val() || [];
            values.forEach(value => {
                formData.append(name, value);
            });
        } else {
            formData.append(name, $this.val());
        }
    });

    // 添加文件
    $form.find("input[type='file']").each(function() {
        const $this = $(this);
        const name = $this.attr("name");
        const files = $this[0].files;

        if(files.length > 0) {
            for(let i = 0; i < files.length; i++) {
                formData.append(name, files[i]);
            }
        }
    });

    return formData;
}

// 序列化特定字段
function serializeSelectedFields(fieldSelectors) {
    const data = {};

    $(fieldSelectors).each(function() {
        const $this = $(this);
        const name = $this.attr("name");

        if(!name) return;

        if($this.is(":checkbox") || $this.is(":radio")) {
            if($this.is(":checked")) {
                data[name] = $this.val();
            }
        } else if($this.is("select[multiple]")) {
            data[name] = $this.val() || [];
        } else {
            data[name] = $this.val();
        }
    });

    return data;
}
                            

2. 表单事件

表单事件处理是表单交互的核心,jQuery提供了丰富的事件处理方法。

表单事件演示:
已输入 0 个字符(最多500)
事件日志:
事件日志:

2.1 表单焦点事件


// focus - 获取焦点时触发
$("#username").focus(function() {
    $(this).css("border-color", "#4CAF50");
    $(this).next(".hint").show();
});

// blur - 失去焦点时触发
$("#username").blur(function() {
    $(this).css("border-color", "#ccc");
    validateUsername($(this).val());
});

// 自动聚焦第一个字段
$(document).ready(function() {
    $("form:first :input:visible:enabled:first").focus();
});

// 回车键跳转到下一个字段
$(".tab-input").keydown(function(e) {
    if(e.keyCode === 13) { // 回车键
        e.preventDefault();
        const inputs = $(".tab-input");
        const index = inputs.index(this) + 1;
        if(index < inputs.length) {
            inputs.eq(index).focus();
        }
    }
});

// 自定义焦点样式
$(":input").focus(function() {
    $(this).addClass("focus-highlight");
}).blur(function() {
    $(this).removeClass("focus-highlight");
});

// 实时显示焦点状态
$(":input").on("focus blur", function(e) {
    const status = e.type === "focus" ? "获得焦点" : "失去焦点";
    console.log($(this).attr("name") + " " + status);
});
                            

2.2 表单输入事件


// input - 输入时实时触发
$("#search").on("input", function() {
    const query = $(this).val();
    searchSuggestions(query);
});

// change - 值改变且失去焦点后触发
$("#country").change(function() {
    const country = $(this).val();
    loadCities(country);
});

// keydown/keyup - 键盘事件
$("#message").keydown(function(e) {
    // 限制最大长度
    const maxLength = 500;
    const currentLength = $(this).val().length;

    if(currentLength >= maxLength && e.keyCode !== 8 && e.keyCode !== 46) {
        e.preventDefault(); // 阻止输入
        showMessage("已达到最大长度限制");
    }
}).keyup(function() {
    // 实时统计字数
    const length = $(this).val().length;
    $("#char-count").text(length);
});

// 实时验证邮箱格式
$("#email").on("input", function() {
    const email = $(this).val();
    const isValid = validateEmail(email);

    if(email && !isValid) {
        $(this).addClass("is-invalid");
        $("#email-error").text("邮箱格式不正确");
    } else {
        $(this).removeClass("is-invalid");
        $("#email-error").text("");
    }
});

// 密码强度实时检查
$("#password").on("input", function() {
    const password = $(this).val();
    const strength = checkPasswordStrength(password);

    updatePasswordStrengthIndicator(strength);
});

// 价格计算实时更新
$("#quantity, #price").on("input", function() {
    const quantity = parseInt($("#quantity").val()) || 0;
    const price = parseFloat($("#price").val()) || 0;
    const total = quantity * price;

    $("#total").val(total.toFixed(2));
});

// 表单字段联动
$("#province").change(function() {
    const provinceId = $(this).val();
    if(provinceId) {
        loadCities(provinceId);
    } else {
        $("#city").empty().append('');
    }
});

$("#city").change(function() {
    const cityId = $(this).val();
    if(cityId) {
        loadDistricts(cityId);
    }
});
                            

2.3 表单提交事件


// submit - 表单提交时触发
$("#myForm").submit(function(e) {
    e.preventDefault(); // 阻止默认提交行为

    // 表单验证
    if(!validateForm()) {
        return false;
    }

    // 获取表单数据
    const formData = $(this).serialize();

    // 显示加载状态
    showLoading();

    // 提交表单
    $.post($(this).attr("action"), formData)
        .done(function(response) {
            if(response.success) {
                showSuccess("提交成功!");
                resetForm();
            } else {
                showError(response.message);
            }
        })
        .fail(function() {
            showError("提交失败,请重试");
        })
        .always(function() {
            hideLoading();
        });
});

// 阻止表单提交(条件性)
$("#orderForm").submit(function(e) {
    if(!confirm("确认提交订单吗?")) {
        e.preventDefault();
        return false;
    }
});

// 提交前验证
$("#registerForm").submit(function(e) {
    const errors = [];

    // 验证用户名
    if(!$("#username").val()) {
        errors.push("用户名不能为空");
    }

    // 验证邮箱
    if(!validateEmail($("#email").val())) {
        errors.push("邮箱格式不正确");
    }

    // 验证密码
    if($("#password").val().length < 6) {
        errors.push("密码至少6位");
    }

    // 如果有错误
    if(errors.length > 0) {
        e.preventDefault();
        showErrors(errors);
        return false;
    }
});

// 多个提交按钮处理
$("#saveDraft").click(function() {
    $("#action").val("draft");
    $("#articleForm").submit();
});

$("#publish").click(function() {
    $("#action").val("publish");
    $("#articleForm").submit();
});

// 防止重复提交
let isSubmitting = false;

$("#myForm").submit(function(e) {
    if(isSubmitting) {
        e.preventDefault();
        return false;
    }

    isSubmitting = true;
    $("#submitBtn").prop("disabled", true).text("提交中...");

    // 3秒后自动重置提交状态(防止请求失败导致按钮一直禁用)
    setTimeout(function() {
        isSubmitting = false;
        $("#submitBtn").prop("disabled", false).text("提交");
    }, 3000);
});

// 文件上传表单提交
$("#uploadForm").submit(function(e) {
    e.preventDefault();

    const formData = new FormData(this);

    $.ajax({
        url: $(this).attr("action"),
        type: "POST",
        data: formData,
        processData: false,
        contentType: false,
        xhr: function() {
            const xhr = new XMLHttpRequest();

            // 上传进度
            xhr.upload.addEventListener("progress", function(e) {
                if(e.lengthComputable) {
                    const percent = (e.loaded / e.total) * 100;
                    $("#progress").width(percent + "%");
                }
            });

            return xhr;
        },
        success: function(response) {
            showSuccess("上传成功!");
        }
    });
});
                            

2.4 表单重置和取消


// reset - 表单重置时触发
$("#myForm").on("reset", function() {
    if(!confirm("确定要重置表单吗?所有输入的数据都将丢失。")) {
        return false;
    }

    // 重置后执行其他操作
    clearValidationErrors();
    resetCustomFields();
});

// 手动重置表单
$("#resetBtn").click(function() {
    if(confirm("确定要重置表单吗?")) {
        $("#myForm")[0].reset(); // 原生方法
        // 或
        $("#myForm").trigger("reset");
    }
});

// 自定义重置逻辑
function customReset(formSelector) {
    const $form = $(formSelector);

    // 清空所有输入框
    $form.find(":input").each(function() {
        const $this = $(this);

        if($this.is(":checkbox, :radio")) {
            $this.prop("checked", false);
        } else if($this.is("select")) {
            $this.prop("selectedIndex", 0);
        } else {
            $this.val("");
        }
    });

    // 清除验证状态
    $form.find(".is-invalid").removeClass("is-invalid");
    $form.find(".error-message").remove();

    // 重置自定义组件
    resetCustomComponents();

    // 聚焦第一个字段
    $form.find(":input:visible:enabled:first").focus();
}

// 取消按钮处理
$("#cancelBtn").click(function() {
    if(hasUnsavedChanges()) {
        if(!confirm("有未保存的更改,确定要取消吗?")) {
            return false;
        }
    }

    // 返回上一页或关闭窗口
    if(window.history.length > 1) {
        window.history.back();
    } else {
        window.location.href = "/dashboard";
    }
});

// 自动保存草稿
let saveTimer;

function startAutoSave() {
    saveTimer = setInterval(function() {
        if(hasChanges()) {
            saveDraft();
        }
    }, 30000); // 每30秒自动保存
}

// 离开页面前提示保存
$(window).on("beforeunload", function() {
    if(hasUnsavedChanges()) {
        return "有未保存的更改,确定要离开吗?";
    }
});

// 防止误操作离开
function preventAccidentalLeave() {
    let hasChanges = false;

    $("#myForm :input").on("input change", function() {
        hasChanges = true;
    });

    $("#saveBtn").click(function() {
        hasChanges = false;
    });

    $(window).on("beforeunload", function() {
        if(hasChanges) {
            return "您有未保存的更改,确定要离开吗?";
        }
    });
}
                            

3. 表单验证

表单验证是确保数据正确性的重要环节,jQuery提供了灵活的验证方案。

注册表单验证:
用户名必须是3-20位字母、数字或下划线
请输入有效的邮箱地址
密码必须至少6位,包含字母和数字
两次输入的密码不一致
年龄必须在18-100之间
必须同意服务条款
验证规则说明:
当前验证规则:
  • 用户名:3-20位字母、数字或下划线
  • 邮箱:必须符合邮箱格式
  • 密码:至少6位,包含字母和数字
  • 确认密码:必须与密码一致
  • 年龄:18-100之间(可选)
  • 服务条款:必须同意
验证状态:
等待验证...

3.1 基础验证方法


// 验证是否为空
function isEmpty(value) {
    return !value || value.trim() === "";
}

// 验证邮箱格式
function validateEmail(email) {
    const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return re.test(email);
}

// 验证手机号
function validatePhone(phone) {
    const re = /^1[3-9]\d{9}$/; // 中国手机号
    return re.test(phone);
}

// 验证身份证号
function validateIDCard(idCard) {
    const re = /(^\d{15}$)|(^\d{17}(\d|X|x)$)/;
    return re.test(idCard);
}

// 验证URL
function validateURL(url) {
    const re = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;
    return re.test(url);
}

// 验证密码强度
function validatePassword(password) {
    // 至少8位,包含大小写字母和数字
    const re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
    return re.test(password);
}

// 验证用户名
function validateUsername(username) {
    // 3-20位字母、数字或下划线
    const re = /^[a-zA-Z0-9_]{3,20}$/;
    return re.test(username);
}

// 验证数字范围
function validateNumberRange(value, min, max) {
    const num = parseFloat(value);
    return !isNaN(num) && num >= min && num <= max;
}

// 验证字符串长度
function validateLength(value, min, max) {
    const length = value.length;
    return length >= min && length <= max;
}
                            

3.2 实时验证


// 用户名实时验证
$("#username").on("input", function() {
    const username = $(this).val();
    const $feedback = $(this).next(".invalid-feedback");

    if(isEmpty(username)) {
        showError($(this), "用户名不能为空");
    } else if(!validateUsername(username)) {
        showError($(this), "用户名必须是3-20位字母、数字或下划线");
    } else {
        showSuccess($(this));

        // 检查用户名是否已存在
        checkUsernameAvailability(username);
    }
});

// 邮箱实时验证
$("#email").on("input", debounce(function() {
    const email = $(this).val();

    if(isEmpty(email)) {
        showError($(this), "邮箱不能为空");
    } else if(!validateEmail(email)) {
        showError($(this), "邮箱格式不正确");
    } else {
        showSuccess($(this));
    }
}, 500));

// 密码强度实时显示
$("#password").on("input", function() {
    const password = $(this).val();
    const strength = checkPasswordStrength(password);

    updateStrengthIndicator(strength);
});

function checkPasswordStrength(password) {
    let strength = 0;

    // 长度至少8位
    if(password.length >= 8) strength++;

    // 包含小写字母
    if(/[a-z]/.test(password)) strength++;

    // 包含大写字母
    if(/[A-Z]/.test(password)) strength++;

    // 包含数字
    if(/\d/.test(password)) strength++;

    // 包含特殊字符
    if(/[^a-zA-Z0-9]/.test(password)) strength++;

    return strength;
}

function updateStrengthIndicator(strength) {
    const $indicator = $("#password-strength");
    const $text = $("#password-strength-text");

    $indicator.removeClass().addClass("strength-" + strength);

    const texts = ["非常弱", "弱", "一般", "强", "非常强"];
    $text.text(texts[strength] || "");
}

// 确认密码实时验证
$("#confirm-password").on("input", function() {
    const password = $("#password").val();
    const confirmPassword = $(this).val();

    if(isEmpty(confirmPassword)) {
        showError($(this), "请确认密码");
    } else if(password !== confirmPassword) {
        showError($(this), "两次输入的密码不一致");
    } else {
        showSuccess($(this));
    }
});

// 显示验证状态
function showError($element, message) {
    $element.addClass("is-invalid");
    let $feedback = $element.next(".invalid-feedback");

    if(!$feedback.length) {
        $feedback = $('
'); $element.after($feedback); } $feedback.text(message); } function showSuccess($element) { $element.removeClass("is-invalid"); $element.addClass("is-valid"); }

3.3 表单整体验证


// 表单验证器类
class FormValidator {
    constructor(formSelector) {
        this.$form = $(formSelector);
        this.rules = {};
        this.messages = {};
        this.errors = [];

        this.init();
    }

    init() {
        // 收集验证规则
        this.collectRules();

        // 绑定事件
        this.bindEvents();
    }

    collectRules() {
        this.$form.find("[data-validate]").each((index, element) => {
            const $element = $(element);
            const name = $element.attr("name");
            const rules = $element.data("validate").split("|");

            this.rules[name] = rules;
            this.messages[name] = {};

            rules.forEach(rule => {
                const message = $element.data(`${rule}-msg`);
                if(message) {
                    this.messages[name][rule] = message;
                }
            });
        });
    }

    bindEvents() {
        // 实时验证
        this.$form.on("input", "[data-validate]", (e) => {
            this.validateField($(e.target));
        });

        // 提交验证
        this.$form.on("submit", (e) => {
            if(!this.validateAll()) {
                e.preventDefault();
                this.displayErrors();
            }
        });
    }

    validateField($element) {
        const name = $element.attr("name");
        const value = $element.val();
        const rules = this.rules[name] || [];

        let isValid = true;

        rules.forEach(rule => {
            if(!this.validateRule(rule, value, $element)) {
                isValid = false;
                this.showFieldError($element, rule);
            } else {
                this.clearFieldError($element);
            }
        });

        return isValid;
    }

    validateRule(rule, value, $element) {
        switch(rule) {
            case "required":
                return !this.isEmpty(value);
            case "email":
                return this.validateEmail(value);
            case "phone":
                return this.validatePhone(value);
            case "min":
                const min = $element.data("min");
                return value.length >= min;
            case "max":
                const max = $element.data("max");
                return value.length <= max;
            case "confirmed":
                const confirmField = $element.data("confirm");
                const confirmValue = $(`[name="${confirmField}"]`).val();
                return value === confirmValue;
            default:
                return true;
        }
    }

    validateAll() {
        this.errors = [];
        let isValid = true;

        Object.keys(this.rules).forEach(name => {
            const $element = $(`[name="${name}"]`);
            if(!this.validateField($element)) {
                isValid = false;
                this.errors.push({
                    field: name,
                    element: $element,
                    message: this.getErrorMessage(name)
                });
            }
        });

        return isValid;
    }

    displayErrors() {
        // 清空之前的错误
        $(".validation-error").remove();

        // 显示所有错误
        if(this.errors.length > 0) {
            let errorHtml = '
'; errorHtml += '
请修正以下错误:
    '; this.errors.forEach(error => { errorHtml += `
  • ${error.message}
  • `; error.element.addClass("is-invalid"); }); errorHtml += '
'; this.$form.prepend(errorHtml); this.errors[0].element.focus(); } } // 辅助方法 isEmpty(value) { return !value || value.trim() === ""; } validateEmail(email) { const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return re.test(email); } validatePhone(phone) { const re = /^1[3-9]\d{9}$/; return re.test(phone); } getErrorMessage(fieldName) { const fieldMessages = this.messages[fieldName] || {}; return fieldMessages.required || "请填写此字段"; } showFieldError($element, rule) { const message = this.getFieldErrorMessage($element, rule); $element.addClass("is-invalid"); let $feedback = $element.next(".invalid-feedback"); if(!$feedback.length) { $feedback = $('
'); $element.after($feedback); } $feedback.text(message); } clearFieldError($element) { $element.removeClass("is-invalid").addClass("is-valid"); $element.next(".invalid-feedback").remove(); } getFieldErrorMessage($element, rule) { const customMessage = $element.data(`${rule}-msg`); if(customMessage) return customMessage; const defaultMessages = { required: "此字段为必填项", email: "请输入有效的邮箱地址", phone: "请输入有效的手机号", min: "长度不能小于${min}个字符", max: "长度不能超过${max}个字符", confirmed: "两次输入不一致" }; let message = defaultMessages[rule] || "验证失败"; // 替换占位符 if(rule === "min" || rule === "max") { const value = $element.data(rule); message = message.replace(`\${${rule}}`, value); } return message; } } // 使用验证器 const validator = new FormValidator("#myForm"); // HTML示例

4. 表单提交

表单提交是表单处理的最终环节,jQuery提供了灵活的提交方式。

联系表单:
提交状态:
提交状态将显示在这里
提交选项:

4.1 传统表单提交


// 传统表单提交(同步)
$("#traditional-form").submit(function(e) {
    // 表单验证
    if(!validateForm(this)) {
        e.preventDefault();
        return false;
    }

    // 提交前确认
    if(!confirm("确定要提交吗?")) {
        e.preventDefault();
        return false;
    }

    // 显示提交状态
    $("#submit-btn").prop("disabled", true).text("提交中...");

    // 表单会自动提交到action指定的地址
});

// 手动提交表单
$("#manual-submit").click(function() {
    // 方式1:触发submit事件
    $("#myForm").submit();

    // 方式2:使用原生submit方法(不会触发submit事件)
    // $("#myForm")[0].submit();
});

// 多按钮表单提交
$("#save-btn").click(function() {
    // 设置隐藏字段标识操作类型
    $("#action-type").val("save");
    $("#myForm").submit();
});

$("#submit-btn").click(function() {
    $("#action-type").val("submit");
    $("#myForm").submit();
});

$("#delete-btn").click(function() {
    if(confirm("确定要删除吗?")) {
        $("#action-type").val("delete");
        $("#myForm").submit();
    }
});

// 表单提交前的处理
$("#order-form").submit(function(e) {
    // 计算总价
    const quantity = parseInt($("#quantity").val()) || 0;
    const price = parseFloat($("#price").val()) || 0;
    const total = quantity * price;

    // 设置隐藏字段
    $("#total-price").val(total.toFixed(2));

    // 格式化数据
    const now = new Date();
    $("#submit-time").val(now.toISOString());

    // 添加用户代理信息
    $("#user-agent").val(navigator.userAgent);

    // 继续提交
    return true;
});
                            

4.2 AJAX表单提交


// 基本AJAX表单提交
$("#ajax-form").submit(function(e) {
    e.preventDefault();

    // 获取表单数据
    const formData = $(this).serialize();

    // 显示加载状态
    showLoading();

    // 发送AJAX请求
    $.ajax({
        url: $(this).attr("action"),
        type: "POST",
        data: formData,
        dataType: "json",
        success: function(response) {
            handleSuccess(response);
        },
        error: function(xhr, status, error) {
            handleError(xhr);
        },
        complete: function() {
            hideLoading();
        }
    });
});

// 使用FormData(支持文件上传)
$("#upload-form").submit(function(e) {
    e.preventDefault();

    const formData = new FormData(this);

    $.ajax({
        url: $(this).attr("action"),
        type: "POST",
        data: formData,
        processData: false,
        contentType: false,
        xhr: function() {
            const xhr = new XMLHttpRequest();

            // 上传进度
            xhr.upload.addEventListener("progress", function(e) {
                if(e.lengthComputable) {
                    const percent = Math.round((e.loaded / e.total) * 100);
                    updateProgress(percent);
                }
            });

            return xhr;
        },
        success: function(response) {
            showSuccess("上传成功!");
        },
        error: function() {
            showError("上传失败,请重试");
        }
    });
});

// 批量提交多个表单
function submitMultipleForms(formSelectors) {
    const promises = [];

    formSelectors.forEach(selector => {
        const promise = submitForm(selector);
        promises.push(promise);
    });

    // 等待所有表单提交完成
    $.when.apply($, promises)
        .done(function() {
            showSuccess("所有表单提交成功!");
        })
        .fail(function() {
            showError("部分表单提交失败");
        });
}

function submitForm(selector) {
    return $.ajax({
        url: $(selector).attr("action"),
        type: "POST",
        data: $(selector).serialize()
    });
}

// 重试机制
class FormSubmitter {
    constructor(formSelector, options = {}) {
        this.$form = $(formSelector);
        this.options = $.extend({
            maxRetries: 3,
            retryDelay: 1000,
            timeout: 30000
        }, options);

        this.retryCount = 0;
        this.init();
    }

    init() {
        this.$form.on("submit", this.handleSubmit.bind(this));
    }

    handleSubmit(e) {
        e.preventDefault();

        if(this.isSubmitting) {
            return false;
        }

        this.isSubmitting = true;
        this.retryCount = 0;

        this.submit();
        return false;
    }

    submit() {
        const formData = this.$form.serialize();

        $.ajax({
            url: this.$form.attr("action"),
            type: "POST",
            data: formData,
            timeout: this.options.timeout,
            success: this.handleSuccess.bind(this),
            error: this.handleError.bind(this)
        });
    }

    handleSuccess(response) {
        this.isSubmitting = false;

        if(response.success) {
            this.showSuccess(response.message);
            this.$form[0].reset();
        } else {
            this.showError(response.message || "提交失败");
        }
    }

    handleError(xhr, status, error) {
        this.retryCount++;

        if(this.retryCount <= this.options.maxRetries) {
            this.showRetryMessage();
            setTimeout(this.submit.bind(this), this.options.retryDelay);
        } else {
            this.isSubmitting = false;
            this.showError("提交失败,请检查网络连接后重试");
        }
    }

    showRetryMessage() {
        const message = `提交失败,正在重试... (${this.retryCount}/${this.options.maxRetries})`;
        this.updateStatus(message, "warning");
    }

    showSuccess(message) {
        this.updateStatus(message, "success");
    }

    showError(message) {
        this.updateStatus(message, "danger");
    }

    updateStatus(message, type) {
        const $status = this.$form.find(".submit-status");
        const alertClass = `alert alert-${type}`;

        if(!$status.length) {
            $status = $('
'); this.$form.append($status); } $status.html(`
${message}
`); } } // 使用重试提交器 const submitter = new FormSubmitter("#myForm", { maxRetries: 3, retryDelay: 2000, timeout: 10000 });

4.3 表单提交优化


// 防止重复提交
function preventDuplicateSubmit(formSelector) {
    let isSubmitting = false;

    $(formSelector).submit(function(e) {
        if(isSubmitting) {
            e.preventDefault();
            return false;
        }

        isSubmitting = true;

        // 禁用提交按钮
        $(this).find(":submit").prop("disabled", true);

        // 显示提交状态
        showSubmittingState();

        // 超时自动重置(防止请求失败导致按钮一直禁用)
        setTimeout(function() {
            isSubmitting = false;
            $(formSelector).find(":submit").prop("disabled", false);
            hideSubmittingState();
        }, 10000); // 10秒后重置

        return true;
    });
}

// 提交队列
class SubmitQueue {
    constructor() {
        this.queue = [];
        this.processing = false;
    }

    add(formData, callback) {
        this.queue.push({ formData, callback });

        if(!this.processing) {
            this.process();
        }
    }

    process() {
        if(this.queue.length === 0) {
            this.processing = false;
            return;
        }

        this.processing = true;
        const { formData, callback } = this.queue.shift();

        $.ajax({
            url: "/api/submit",
            type: "POST",
            data: formData,
            success: (response) => {
                if(callback) callback(null, response);
                this.process();
            },
            error: (xhr) => {
                if(callback) callback(xhr);
                this.process();
            }
        });
    }
}

// 使用提交队列
const submitQueue = new SubmitQueue();

$("#myForm").submit(function(e) {
    e.preventDefault();

    const formData = $(this).serialize();

    submitQueue.add(formData, function(error, response) {
        if(error) {
            showError("提交失败");
        } else {
            showSuccess("提交成功");
        }
    });
});

// 提交节流
function createThrottledSubmit(selector, delay = 1000) {
    let lastSubmitTime = 0;
    let timer = null;

    $(selector).submit(function(e) {
        e.preventDefault();

        const now = Date.now();

        if(now - lastSubmitTime < delay) {
            // 如果距离上次提交时间太短,延迟执行
            clearTimeout(timer);
            timer = setTimeout(() => {
                doSubmit(this);
                lastSubmitTime = Date.now();
            }, delay - (now - lastSubmitTime));

            return false;
        }

        doSubmit(this);
        lastSubmitTime = now;
        return false;
    });

    function doSubmit(form) {
        const formData = $(form).serialize();

        $.ajax({
            url: $(form).attr("action"),
            type: "POST",
            data: formData,
            success: function(response) {
                // 处理成功响应
            }
        });
    }
}

// 离线提交支持
class OfflineSubmit {
    constructor(formSelector, storageKey = "pending_submissions") {
        this.$form = $(formSelector);
        this.storageKey = storageKey;
        this.pendingSubmissions = this.loadPendingSubmissions();

        this.init();
    }

    init() {
        // 监听在线状态
        window.addEventListener("online", this.handleOnline.bind(this));

        // 表单提交处理
        this.$form.submit(this.handleSubmit.bind(this));
    }

    handleSubmit(e) {
        e.preventDefault();

        const formData = this.$form.serialize();

        if(navigator.onLine) {
            // 在线状态直接提交
            this.submitOnline(formData);
        } else {
            // 离线状态保存到本地
            this.saveOffline(formData);
        }
    }

    submitOnline(formData) {
        $.ajax({
            url: this.$form.attr("action"),
            type: "POST",
            data: formData,
            success: (response) => {
                if(response.success) {
                    this.showSuccess("提交成功");
                    this.$form[0].reset();
                }
            }
        });
    }

    saveOffline(formData) {
        const submission = {
            data: formData,
            timestamp: new Date().getTime(),
            url: this.$form.attr("action")
        };

        this.pendingSubmissions.push(submission);
        this.savePendingSubmissions();

        this.showInfo("网络离线,提交已保存到本地。连接网络后将自动提交。");
        this.$form[0].reset();
    }

    handleOnline() {
        if(this.pendingSubmissions.length > 0) {
            this.processPendingSubmissions();
        }
    }

    processPendingSubmissions() {
        const successful = [];

        // 逐个提交待处理的数据
        const promises = this.pendingSubmissions.map((submission, index) => {
            return $.ajax({
                url: submission.url,
                type: "POST",
                data: submission.data
            }).then(() => {
                successful.push(index);
            });
        });

        // 所有请求完成后,移除已成功的
        $.when.apply($, promises).then(() => {
            this.pendingSubmissions = this.pendingSubmissions.filter((_, index) => {
                return !successful.includes(index);
            });
            this.savePendingSubmissions();

            if(successful.length > 0) {
                this.showSuccess(`${successful.length}条离线提交已同步`);
            }
        });
    }

    loadPendingSubmissions() {
        const data = localStorage.getItem(this.storageKey);
        return data ? JSON.parse(data) : [];
    }

    savePendingSubmissions() {
        localStorage.setItem(this.storageKey, JSON.stringify(this.pendingSubmissions));
    }
}

// 使用离线提交
const offlineSubmit = new OfflineSubmit("#myForm");
                            

5. 表单插件

使用jQuery表单插件可以快速实现复杂功能,提高开发效率。

5.1 常用表单插件介绍

插件名称 功能描述 引入方式
jQuery Validation 表单验证插件,功能强大,支持自定义规则 <script src="jquery.validate.js"></script>
Bootstrap Validator 基于Bootstrap的表单验证插件 <script src="bootstrap-validator.js"></script>
Select2 增强的下拉选择框,支持搜索、多选等功能 <script src="select2.min.js"></script>
jQuery Mask 输入框掩码插件,用于格式化输入 <script src="jquery.mask.min.js"></script>
jQuery Form AJAX表单提交插件,支持文件上传 <script src="jquery.form.js"></script>
Datepicker 日期选择器插件 <script src="bootstrap-datepicker.js"></script>

5.2 jQuery Validation 插件示例


// 引入jQuery Validation插件
// <script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.5/dist/jquery.validate.min.js"></script>

// 基本使用
$("#myForm").validate({
    rules: {
        username: {
            required: true,
            minlength: 3,
            maxlength: 20
        },
        email: {
            required: true,
            email: true
        },
        password: {
            required: true,
            minlength: 6
        },
        confirm_password: {
            required: true,
            equalTo: "#password"
        }
    },
    messages: {
        username: {
            required: "请输入用户名",
            minlength: "用户名至少3个字符",
            maxlength: "用户名最多20个字符"
        },
        email: {
            required: "请输入邮箱地址",
            email: "请输入有效的邮箱地址"
        },
        password: {
            required: "请输入密码",
            minlength: "密码至少6位"
        },
        confirm_password: {
            required: "请确认密码",
            equalTo: "两次输入的密码不一致"
        }
    },
    submitHandler: function(form) {
        // 验证通过后执行
        $.ajax({
            url: $(form).attr("action"),
            type: "POST",
            data: $(form).serialize(),
            success: function(response) {
                if(response.success) {
                    alert("提交成功!");
                    form.reset();
                }
            }
        });
    },
    errorPlacement: function(error, element) {
        // 自定义错误信息位置
        error.addClass("invalid-feedback");
        element.addClass("is-invalid");

        if(element.parent(".input-group").length) {
            error.insertAfter(element.parent());
        } else {
            error.insertAfter(element);
        }
    },
    highlight: function(element) {
        // 高亮显示错误字段
        $(element).addClass("is-invalid");
    },
    unhighlight: function(element) {
        // 移除错误高亮
        $(element).removeClass("is-invalid");
    }
});

// 自定义验证规则
$.validator.addMethod("phoneCN", function(value, element) {
    return this.optional(element) || /^1[3-9]\d{9}$/.test(value);
}, "请输入有效的手机号码");

$.validator.addMethod("chinese", function(value, element) {
    return this.optional(element) || /^[\u4e00-\u9fa5]+$/.test(value);
}, "请输入中文");

// 使用自定义规则
$("#myForm").validate({
    rules: {
        mobile: {
            required: true,
            phoneCN: true
        },
        realname: {
            required: true,
            chinese: true
        }
    }
});

// 动态添加/移除验证规则
const validator = $("#myForm").validate();
validator.destroy(); // 销毁验证器

// 重新初始化
$("#myForm").validate({
    rules: {
        // 新规则
    }
});
                            

5.3 Select2 插件示例


// 基本使用
$("#single-select").select2({
    placeholder: "请选择",
    allowClear: true
});

// 多选模式
$("#multi-select").select2({
    placeholder: "请选择(可多选)",
    allowClear: true,
    multiple: true,
    maximumSelectionLength: 3 // 最多选择3个
});

// 远程数据源
$("#remote-select").select2({
    placeholder: "搜索并选择",
    allowClear: true,
    ajax: {
        url: "/api/search",
        dataType: "json",
        delay: 250,
        data: function(params) {
            return {
                q: params.term, // 搜索关键词
                page: params.page || 1
            };
        },
        processResults: function(data, params) {
            params.page = params.page || 1;

            return {
                results: data.items,
                pagination: {
                    more: (params.page * 10) < data.total_count
                }
            };
        },
        cache: true
    },
    minimumInputLength: 2 // 至少输入2个字符才开始搜索
});

// 模板定制
$("#custom-select").select2({
    templateResult: formatResult,
    templateSelection: formatSelection
});

function formatResult(item) {
    if(!item.id) {
        return item.text;
    }

    const $result = $(
        '' +
        '' +
        item.text +
        '' + item.email + '' +
        ''
    );

    return $result;
}

function formatSelection(item) {
    return item.text;
}

// 事件处理
$("#mySelect").on("select2:select", function(e) {
    const data = e.params.data;
    console.log("选择了:", data);
});

$("#mySelect").on("select2:open", function() {
    console.log("下拉框打开了");
});

$("#mySelect").on("select2:close", function() {
    console.log("下拉框关闭了");
});

// 动态更新选项
function updateSelectOptions() {
    const newData = [
        {id: 1, text: "选项1"},
        {id: 2, text: "选项2"},
        {id: 3, text: "选项3"}
    ];

    $("#mySelect").empty().select2({
        data: newData
    });
}

// 获取和设置值
const selectedValues = $("#multi-select").val(); // 获取值
$("#multi-select").val(["1", "2"]).trigger("change"); // 设置值
                            
表单处理最佳实践:
  • ✓ 使用事件委托提高性能
  • ✓ 实现实时验证提升用户体验
  • ✓ 防止表单重复提交
  • ✓ 提供清晰的错误提示
  • ✓ 支持键盘操作和快捷键
  • ✓ 实现表单数据持久化(草稿保存)
  • ✓ 使用插件简化复杂功能
  • ✓ 优化移动端表单体验
  • ✓ 实现无障碍访问
  • ✓ 进行彻底的兼容性测试

jQuery表单处理方法速查表

方法/属性 描述 示例
.val() 获取或设置表单元素的值 $("#input").val()
.serialize() 序列化表单为查询字符串 $("form").serialize()
.serializeArray() 序列化表单为数组 $("form").serializeArray()
.submit() 提交表单或绑定提交事件 $("form").submit()
.reset() 重置表单 $("form")[0].reset()
.focus() 设置焦点或绑定焦点事件 $("#input").focus()
.blur() 失去焦点或绑定失去焦点事件 $("#input").blur()
.change() 值改变事件 $("select").change()
.prop('checked') 获取或设置复选框/单选框状态 $("#checkbox").prop('checked')
:input 表单元素选择器 $("form :input")
:checked 选中状态选择器 $("input:checked")
:selected 选中选项选择器 $("option:selected")

实战练习:订单表单系统

创建一个完整的订单表单系统,包含以下功能:

订单表单:
按住Ctrl键多选
订单详情:
订单摘要
商品总额: ¥0
包装费: ¥0
优惠折扣: 0
总计: ¥0
价格实时计算,修改表单内容会自动更新
操作日志:
操作日志将显示在这里...