0 %

jQuery事件处理详解

2026-08-31 13:03:38

事件处理概述

事件处理是Web开发的核心部分,它允许网页对用户的交互做出响应。jQuery简化了事件处理,提供了跨浏览器兼容的解决方案。

鼠标事件

click - 点击事件

dblclick - 双击事件

mouseenter - 鼠标进入

mouseleave - 鼠标离开

mousemove - 鼠标移动

键盘事件

keydown - 键按下

keyup - 键释放

keypress - 键按下(字符键)

表单事件

focus - 获得焦点

blur - 失去焦点

change - 值改变

submit - 表单提交

窗口事件

load - 加载完成

resize - 调整大小

scroll - 滚动事件

重要概念

事件绑定: 将事件处理函数附加到元素

事件对象: 事件发生时创建的包含事件信息的对象

事件冒泡: 事件从目标元素向上传播到文档根元素

事件委托: 将事件处理程序附加到父元素,处理子元素的事件

事件命名空间: 为事件添加命名空间以便管理

事件绑定方法

jQuery提供了多种事件绑定方法,每种方法都有其适用场景。

on() 方法

jQuery 1.7+ 推荐的事件绑定方法,功能最强大,支持所有事件类型。

// 基本语法

$(selector).on(events[, selector][, data], handler)

// 绑定单个事件

$(selector).on("click", function() {})

// 绑定多个事件

$(selector).on("click mouseenter", function() {})

// 带事件委托

$(parent).on("click", childSelector, function() {})

// 传递数据

$(selector).on("click", {key: value}, function(event) {})

示例:

// 绑定点击事件

$("#button").on("click", function() {

alert("按钮被点击了!");

});

// 绑定多个事件

$("#element").on("mouseenter mouseleave", function(event) {

if (event.type === "mouseenter") {

$(this).css("background-color", "yellow");

} else {

$(this).css("background-color", "white");

}

});

// 事件委托(处理动态添加的元素)

$("#list").on("click", "li", function() {

alert("列表项被点击: " + $(this).text());

});

// 传递数据给事件处理函数

$("#button").on("click", {name: "张三", age: 25}, function(event) {

console.log("数据:", event.data); // {name: "张三", age: 25}

});

// 使用命名空间

$("#element").on("click.myNamespace", function() {

console.log("带命名空间的点击事件");

});

// 一次性事件

$("#button").one("click", function() {

alert("这个按钮只能点击一次!");

});

on() 方法的优势

统一的事件绑定API

支持事件委托

支持事件命名空间

可以传递数据给处理函数

支持一次性事件(通过one()方法)

off() 方法

移除通过 on() 方法绑定的事件处理程序。

// 移除所有事件处理程序

$(selector).off()

// 移除特定类型的事件

$(selector).off("click")

// 移除特定处理函数

$(selector).off("click", handler)

// 移除特定命名空间的事件

$(selector).off(".myNamespace")

// 移除事件委托

$(parent).off("click", childSelector)

示例:

// 定义事件处理函数

function handleClick() {

console.log("按钮被点击");

}

// 绑定事件

$("#button").on("click", handleClick);

// 移除事件

$("#button").off("click", handleClick);

// 绑定多个事件

$("#element").on("click mouseenter", function() {

console.log("事件触发");

});

// 移除所有click事件

$("#element").off("click");

// 移除所有事件

$("#element").off();

// 使用命名空间

$("#element").on("click.myNamespace", function() {

console.log("命名空间事件");

});

// 移除特定命名空间的事件

$("#element").off(".myNamespace");

// 事件委托的移除

$("#list").on("click", "li", function() {

console.log("列表项点击");

});

// 移除事件委托

$("#list").off("click", "li");

// 移除特定处理函数的事件委托

function handleListItemClick() {

console.log("列表项点击");

}

$("#list").on("click", "li", handleListItemClick);

$("#list").off("click", "li", handleListItemClick);

trigger() 方法

触发绑定到元素的事件处理程序。

// 触发事件

$(selector).trigger(eventType[, extraParameters])

// 触发自定义事件

$(selector).trigger("customEvent")

// 传递额外参数

$(selector).trigger("click", [param1, param2])

示例:

// 绑定点击事件

$("#button").on("click", function(event, param1, param2) {

console.log("按钮被点击", param1, param2);

});

// 触发点击事件

$("#button").trigger("click");

// 触发事件并传递参数

$("#button").trigger("click", ["参数1", "参数2"]);

// 触发自定义事件

$("#element").on("myCustomEvent", function() {

console.log("自定义事件被触发");

});

$("#element").trigger("myCustomEvent");

// 触发多个事件

$("#element").on("event1 event2", function(event) {

console.log(event.type + " 被触发");

});

$("#element").trigger("event1 event2");

// 触发表单提交事件

$("#form").trigger("submit");

// 触发带命名空间的事件

$("#element").on("click.myNamespace", function() {

console.log("命名空间事件");

});

$("#element").trigger("click.myNamespace");

快捷方法

jQuery为常用事件提供了快捷方法,语法更简洁。

// 点击事件

$(selector).click(handler)

// 鼠标进入事件

$(selector).mouseenter(handler)

// 键盘按下事件

$(selector).keydown(handler)

// 聚焦事件

$(selector).focus(handler)

// 加载事件

$(window).load(handler)

示例:

// 快捷方法绑定事件

$("#button").click(function() {

alert("按钮被点击");

});

$("#input").focus(function() {

$(this).css("border-color", "blue");

});

$("#input").blur(function() {

$(this).css("border-color", "#ccc");

});

$("#element").mouseenter(function() {

$(this).css("background-color", "yellow");

}).mouseleave(function() {

$(this).css("background-color", "white");

});

// 快捷方法触发事件

$("#button").click(); // 触发点击事件

$("#input").focus(); // 触发聚焦事件

// 快捷方法移除事件

$("#button").off("click"); // 只能这样移除,没有.unclick()方法

// 注意:快捷方法内部也是调用on()方法

// 以下两行代码是等价的:

$("#button").click(function() {});

$("#button").on("click", function() {});

事件绑定方法对比

方法

描述

版本

推荐度

on()

统一的事件绑定方法,功能最全

1.7+

★★★★★

off()

移除通过on()绑定的事件

1.7+

★★★★★

bind()

旧版事件绑定方法(已过时)

1.0-3.0

★☆☆☆☆

unbind()

旧版事件移除方法(已过时)

1.0-3.0

★☆☆☆☆

delegate()

旧版事件委托方法(已过时)

1.4.2-3.0

★☆☆☆☆

undelegate()

旧版事件委托移除(已过时)

1.4.2-3.0

★☆☆☆☆

快捷方法

click(), mouseenter()等

1.0+

★★★★☆

鼠标事件

鼠标事件在用户使用鼠标与元素交互时触发。

click

点击事件(按下并释放鼠标按钮)

$("#element").click(function() {

console.log("元素被点击");

});

dblclick

双击事件

$("#element").dblclick(function() {

console.log("元素被双击");

});

mousedown

鼠标按钮按下

$("#element").mousedown(function(event) {

console.log("按钮按下:", event.which);

});

mouseup

鼠标按钮释放

$("#element").mouseup(function() {

console.log("按钮释放");

});

mouseenter

鼠标进入元素区域

$("#element").mouseenter(function() {

$(this).addClass("hover");

});

mouseleave

鼠标离开元素区域

$("#element").mouseleave(function() {

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

});

mouseover

鼠标移动到元素上(会冒泡)

$("#element").mouseover(function() {

console.log("mouseover");

});

mouseout

鼠标移出元素(会冒泡)

$("#element").mouseout(function() {

console.log("mouseout");

});

mousemove

鼠标在元素上移动

$("#element").mousemove(function(event) {

console.log("位置:", event.pageX, event.pageY);

});

contextmenu

右键菜单事件

$("#element").contextmenu(function(event) {

event.preventDefault(); // 阻止默认右键菜单

showCustomMenu();

});

鼠标事件综合示例

展示鼠标事件的常见用法和事件对象属性。

// 鼠标事件综合示例

$("#demo-element")

// 点击事件

.on("click", function(event) {

console.log("点击事件");

console.log("鼠标按钮:", event.which); // 1=左键, 2=中键, 3=右键

console.log("坐标:", event.pageX, event.pageY);

console.log("目标元素:", event.target.tagName);

})

// 双击事件

.on("dblclick", function() {

console.log("双击事件");

$(this).toggleClass("highlight");

})

// 鼠标进入/离开

.on("mouseenter mouseleave", function(event) {

if (event.type === "mouseenter") {

$(this).css("border-color", "#3498db");

} else {

$(this).css("border-color", "#ddd");

}

})

// 鼠标移动

.on("mousemove", function(event) {

$("#coords").text(event.pageX + ", " + event.pageY);

})

// 鼠标按下/释放

.on("mousedown mouseup", function(event) {

if (event.type === "mousedown") {

$(this).css("background-color", "#e74c3c");

} else {

$(this).css("background-color", "#3498db");

}

console.log("按钮:", event.which);

})

// 右键菜单

.on("contextmenu", function(event) {

event.preventDefault();

alert("自定义右键菜单");

return false;

});

// 获取鼠标位置

$(document).on("mousemove", function(event) {

// event.pageX/Y: 相对于文档的坐标

// event.clientX/Y: 相对于视口的坐标

// event.screenX/Y: 相对于屏幕的坐标

console.log("文档坐标:", event.pageX, event.pageY);

console.log("视口坐标:", event.clientX, event.clientY);

console.log("屏幕坐标:", event.screenX, event.screenY);

});

// 鼠标事件对象属性示例

$("#element").on("click", function(event) {

console.log("事件类型:", event.type); // "click"

console.log("时间戳:", event.timeStamp); // 事件发生的时间戳

console.log("目标元素:", event.target); // 触发事件的元素

console.log("当前元素:", event.currentTarget); // 绑定事件处理程序的元素

console.log("是否按下了Shift键:", event.shiftKey);

console.log("是否按下了Ctrl键:", event.ctrlKey);

console.log("是否按下了Alt键:", event.altKey);

console.log("是否按下了Meta键:", event.metaKey);

console.log("鼠标按钮:", event.button); // 0=左键, 1=中键, 2=右键

console.log("相关元素:", event.relatedTarget); // 对于mouseenter/mouseleave事件

});

鼠标事件演示:

在此区域移动、点击鼠标

事件日志:

清空日志

mouseenter/mouseleave vs mouseover/mouseout

特性

mouseenter/mouseleave

mouseover/mouseout

事件冒泡

不会冒泡

会冒泡

触发频率

进入/离开元素时触发一次

进入/离开元素及其子元素时都会触发

推荐场景

鼠标悬停效果

需要事件冒泡的场景

jQuery版本

1.0+

1.0+

示例

$("#parent").mouseenter(function() {

// 只在鼠标进入父元素时触发

});

$("#parent").mouseover(function() {

// 鼠标进入父元素或子元素都会触发

});

键盘事件

键盘事件在用户按下或释放键盘按键时触发。

keydown

键按下时触发(任何键)

$("#input").keydown(function(event) {

console.log("键按下:", event.key);

});

keyup

键释放时触发

$("#input").keyup(function(event) {

console.log("键释放:", event.key);

});

keypress

字符键按下时触发

$("#input").keypress(function(event) {

console.log("字符键:", event.which);

});

键盘事件综合示例

展示键盘事件的常见用法和事件对象属性。

// 键盘事件综合示例

$("#text-input").on({

// keydown - 键按下

keydown: function(event) {

console.log("keydown - 键码:", event.keyCode);

console.log("键:", event.key);

console.log("是否Ctrl键:", event.ctrlKey);

// 检测特定按键

if (event.keyCode === 13) { // Enter键

console.log("Enter键被按下");

event.preventDefault(); // 阻止默认行为

}

if (event.keyCode === 27) { // ESC键

console.log("ESC键被按下");

$(this).blur();

}

// 组合键检测

if (event.ctrlKey && event.keyCode === 83) { // Ctrl+S

event.preventDefault();

saveContent();

}

},

// keyup - 键释放

keyup: function(event) {

console.log("keyup - 键:", event.key);

// 实时显示输入长度

var length = $(this).val().length;

$("#char-count").text(length);

},

// keypress - 字符键按下

keypress: function(event) {

console.log("keypress - 字符码:", event.which);

// 限制只能输入数字

if (!/[0-9]/.test(String.fromCharCode(event.which))) {

event.preventDefault();

}

}

});

// 全局键盘事件

$(document).on("keydown", function(event) {

// 快捷键支持

switch(event.keyCode) {

case 37: // 左箭头

navigateLeft();

break;

case 39: // 右箭头

navigateRight();

break;

case 38: // 上箭头

navigateUp();

break;

case 40: // 下箭头

navigateDown();

break;

}

});

// 键盘事件对象属性

$("#input").on("keydown", function(event) {

console.log("事件类型:", event.type); // "keydown"

console.log("键码:", event.keyCode); // 按键的键码

console.log("字符码:", event.which); // 字符码(已弃用,但jQuery标准化)

console.log("键:", event.key); // 按键的字符串表示(推荐)

console.log("代码:", event.code); // 物理按键代码

console.log("是否重复:", event.repeat); // 是否按住不放

console.log("是否Shift键:", event.shiftKey);

console.log("是否Ctrl键:", event.ctrlKey);

console.log("是否Alt键:", event.altKey);

console.log("是否Meta键:", event.metaKey);

console.log("是否大写锁定:", event.capsLock);

console.log("是否数字锁定:", event.numLock);

// 阻止默认行为

if (event.key === "Escape") {

event.preventDefault();

$(this).val("");

}

});

// 常用键码

var keyCodes = {

ENTER: 13,

ESC: 27,

SPACE: 32,

LEFT: 37,

UP: 38,

RIGHT: 39,

DOWN: 40,

TAB: 9,

BACKSPACE: 8,

DELETE: 46,

HOME: 36,

END: 35,

PAGE_UP: 33,

PAGE_DOWN: 34,

F1: 112,

F12: 123

};

// 检测组合键

$(document).on("keydown", function(event) {

// Ctrl + C

if (event.ctrlKey && event.key === "c") {

console.log("复制");

}

// Ctrl + V

if (event.ctrlKey && event.key === "v") {

console.log("粘贴");

}

// Ctrl + Z

if (event.ctrlKey && event.key === "z") {

console.log("撤销");

event.preventDefault();

}

// Alt + 键

if (event.altKey && event.key === "s") {

console.log("Alt+S 保存");

event.preventDefault();

}

});

键盘事件演示:

字符数: 0

最后按键: 无

键码: -

事件日志:

清空日志

键盘事件对比

事件

触发时机

支持的键

推荐用途

keydown

键按下时

所有键

检测功能键、快捷键

keyup

键释放时

所有键

完成输入、检测键释放

keypress

字符键按下时

字符键(a-z, 0-9等)

字符输入处理(已弃用)

表单事件

表单事件在表单元素与用户交互时触发。

focus

元素获得焦点时触发

$("input").focus(function() {

$(this).addClass("focused");

});

blur

元素失去焦点时触发

$("input").blur(function() {

validateField(this);

});

change

元素值改变并失去焦点时触发

$("select").change(function() {

updateSelection($(this).val());

});

input

元素值改变时立即触发

$("textarea").on("input", function() {

updateCharCount($(this).val());

});

submit

表单提交时触发

$("form").submit(function(event) {

if (!validateForm()) {

event.preventDefault();

}

});

select

文本被选择时触发

$("input[type='text']").select(function() {

console.log("文本被选择");

});

表单事件综合示例

展示表单事件的常见用法和表单验证。

// 表单事件综合示例

$("#myForm").on({

// 提交事件

submit: function(event) {

event.preventDefault(); // 阻止默认提交

if (validateForm()) {

// 验证通过,手动提交

console.log("表单提交:", $(this).serialize());

// Ajax提交

$.ajax({

url: $(this).attr("action"),

method: $(this).attr("method"),

data: $(this).serialize(),

success: function(response) {

console.log("提交成功:", response);

}

});

} else {

console.log("表单验证失败");

}

},

// 重置事件

reset: function() {

console.log("表单被重置");

$(".error-message").hide();

}

});

// 输入框事件

$("#username")

// 获得焦点

.focus(function() {

$(this).css("border-color", "#3498db");

$("#username-help").show();

})

// 失去焦点

.blur(function() {

$(this).css("border-color", "#ddd");

$("#username-help").hide();

// 验证用户名

validateUsername($(this).val());

})

// 输入时实时验证

.on("input", function() {

var value = $(this).val();

$("#username-length").text(value.length);

if (value.length > 0 && value.length < 3) {

showError($(this), "用户名至少3个字符");

} else {

clearError($(this));

}

})

// 值改变(失去焦点后)

.change(function() {

console.log("用户名改变为:", $(this).val());

});

// 下拉框事件

$("#country")

.change(function() {

var country = $(this).val();

console.log("选择的国家:", country);

// 动态加载城市

loadCities(country);

});

// 复选框事件

$("input[type='checkbox']")

.change(function() {

var isChecked = $(this).prop("checked");

console.log("复选框状态:", isChecked);

// 更新选中计数

var checkedCount = $("input[type='checkbox']:checked").length;

$("#selected-count").text(checkedCount);

});

// 单选框事件

$("input[type='radio']")

.change(function() {

var value = $(this).val();

console.log("选择的值:", value);

});

// 表单验证函数

function validateForm() {

var isValid = true;

// 验证用户名

if ($("#username").val().trim() === "") {

showError($("#username"), "用户名不能为空");

isValid = false;

}

// 验证邮箱

var email = $("#email").val();

var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

if (!emailRegex.test(email)) {

showError($("#email"), "邮箱格式不正确");

isValid = false;

}

// 验证密码

var password = $("#password").val();

if (password.length < 6) {

showError($("#password"), "密码至少6个字符");

isValid = false;

}

return isValid;

}

function showError($element, message) {

$element.css("border-color", "#e74c3c");

$element.next(".error-message").remove();

$element.after('' + message + '');

}

function clearError($element) {

$element.css("border-color", "#ddd");

$element.next(".error-message").remove();

}

// 获取表单数据

$("#submit-btn").click(function() {

// 序列化表单数据

var formData = $("#myForm").serialize();

console.log("表单数据:", formData);

// 序列化为数组

var formArray = $("#myForm").serializeArray();

console.log("表单数组:", formArray);

// 获取特定字段值

var username = $("#username").val();

var email = $("#email").val();

var newsletter = $("#newsletter").prop("checked");

// 获取复选框值(多选)

var hobbies = [];

$("input[name='hobbies']:checked").each(function() {

hobbies.push($(this).val());

});

});

表单事件演示:

用户名:

用户名长度: 0

邮箱:

国家:

请选择

中国

美国

日本

兴趣:

阅读

运动

音乐

提交

重置

事件日志:

清空日志

窗口事件

窗口事件在浏览器窗口状态改变时触发。

load

页面完全加载后触发

$(window).load(function() {

console.log("页面完全加载");

});

resize

窗口大小改变时触发

$(window).resize(function() {

console.log("窗口大小:", $(this).width());

});

scroll

窗口滚动时触发

$(window).scroll(function() {

console.log("滚动位置:", $(this).scrollTop());

});

unload

页面卸载时触发(已弃用)

$(window).on("unload", function() {

// 清理工作

});

beforeunload

页面卸载前触发

$(window).on("beforeunload", function() {

return "确定离开页面吗?";

});

窗口事件综合示例

展示窗口事件的常见用法和响应式设计。

// 窗口事件综合示例

$(window)

// 页面加载完成

.on("load", function() {

console.log("页面加载完成");

// 初始化操作

initPage();

// 隐藏加载动画

$("#loading").fadeOut();

})

// 窗口大小改变

.on("resize", function() {

var width = $(this).width();

var height = $(this).height();

console.log("窗口尺寸:", width + "x" + height);

// 响应式设计

if (width < 768) {

$("body").addClass("mobile").removeClass("desktop");

} else {

$("body").addClass("desktop").removeClass("mobile");

}

// 调整布局

adjustLayout(width);

})

// 窗口滚动

.on("scroll", function() {

var scrollTop = $(this).scrollTop();

var windowHeight = $(this).height();

var documentHeight = $(document).height();

console.log("滚动位置:", scrollTop);

// 滚动到顶部按钮

if (scrollTop > 300) {

$("#back-to-top").fadeIn();

} else {

$("#back-to-top").fadeOut();

}

// 无限滚动

if (scrollTop + windowHeight >= documentHeight - 100) {

loadMoreContent();

}

// 视差滚动效果

$(".parallax").css("transform", "translateY(" + scrollTop * 0.5 + "px)");

// 固定导航栏

if (scrollTop > $("#header").height()) {

$("#navbar").addClass("fixed");

} else {

$("#navbar").removeClass("fixed");

}

});

// 页面加载状态

$(document).ready(function() {

console.log("DOM准备就绪");

// DOM操作可以在这里进行

$("#content").html("页面已加载");

});

// 注意:$(document).ready() vs $(window).load()

// ready: DOM加载完成,图片等资源可能还没加载

// load: 所有资源(图片、样式等)都加载完成

// 页面卸载前

$(window).on("beforeunload", function(event) {

// 如果有未保存的数据

if (hasUnsavedChanges()) {

var message = "您有未保存的更改,确定要离开吗?";

event.returnValue = message; // 标准方法

return message; // 兼容旧浏览器

}

});

// 页面卸载

$(window).on("unload", function() {

// 清理工作(注意:限制很多)

// 可以发送一个同步的Ajax请求

// 但更推荐使用visibilitychange事件

});

// 页面可见性API

$(document).on("visibilitychange", function() {

if (document.hidden) {

console.log("页面被隐藏");

// 暂停视频、动画等

} else {

console.log("页面可见");

// 恢复视频、动画等

}

});

// 获取窗口信息

function getWindowInfo() {

return {

width: $(window).width(), // 视口宽度

height: $(window).height(), // 视口高度

scrollTop: $(window).scrollTop(), // 垂直滚动位置

scrollLeft: $(window).scrollLeft(), // 水平滚动位置

screenWidth: screen.width, // 屏幕宽度

screenHeight: screen.height, // 屏幕高度

devicePixelRatio: window.devicePixelRatio // 设备像素比

};

}

// 响应式断点检测

function checkBreakpoint() {

var width = $(window).width();

if (width >= 1200) {

return "xl"; // 特大屏幕

} else if (width >= 992) {

return "lg"; // 大屏幕

} else if (width >= 768) {

return "md"; // 中等屏幕

} else if (width >= 576) {

return "sm"; // 小屏幕

} else {

return "xs"; // 超小屏幕

}

}

// 监听断点变化

var currentBreakpoint = checkBreakpoint();

$(window).on("resize", function() {

var newBreakpoint = checkBreakpoint();

if (newBreakpoint !== currentBreakpoint) {

console.log("断点变化:", currentBreakpoint, "->", newBreakpoint);

currentBreakpoint = newBreakpoint;

// 执行断点相关的操作

onBreakpointChange(newBreakpoint);

}

});

窗口事件演示:

窗口信息

宽度: -px

高度: -px

滚动位置: -px

屏幕尺寸: -

断点: -

滚动此区域查看滚动事件

加载中...

继续滚动...

事件日志:

清空日志

触摸事件

触摸事件在触摸屏设备上与元素交互时触发。

touchstart

触摸开始时触发

$("#element").on("touchstart", function(event) {

console.log("触摸开始");

});

touchmove

触摸移动时触发

$("#element").on("touchmove", function(event) {

event.preventDefault();

});

touchend

触摸结束时触发

$("#element").on("touchend", function(event) {

console.log("触摸结束");

});

touchcancel

触摸被取消时触发

$("#element").on("touchcancel", function(event) {

console.log("触摸取消");

});

触摸事件综合示例

展示触摸事件的常见用法和移动端手势识别。

// 触摸事件综合示例

var touchStartX = 0;

var touchStartY = 0;

var touchEndX = 0;

var touchEndY = 0;

$("#touch-element")

// 触摸开始

.on("touchstart", function(event) {

event.preventDefault();

var touch = event.originalEvent.touches[0];

touchStartX = touch.pageX;

touchStartY = touch.pageY;

console.log("触摸开始:", touchStartX, touchStartY);

$(this).addClass("touching");

// 记录触摸时间

$(this).data("touchStartTime", Date.now());

})

// 触摸移动

.on("touchmove", function(event) {

event.preventDefault();

var touch = event.originalEvent.touches[0];

var currentX = touch.pageX;

var currentY = touch.pageY;

console.log("触摸移动:", currentX, currentY);

// 计算移动距离

var deltaX = currentX - touchStartX;

var deltaY = currentY - touchStartY;

// 拖拽效果

$(this).css({

transform: "translate(" + deltaX + "px, " + deltaY + "px)"

});

})

// 触摸结束

.on("touchend", function(event) {

event.preventDefault();

var touch = event.originalEvent.changedTouches[0];

touchEndX = touch.pageX;

touchEndY = touch.pageY;

console.log("触摸结束:", touchEndX, touchEndY);

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

// 检测手势

detectGesture();

// 恢复位置

$(this).css({

transform: "translate(0, 0)",

transition: "transform 0.3s"

});

// 移除过渡效果

setTimeout(function() {

$("#touch-element").css("transition", "none");

}, 300);

})

// 触摸取消

.on("touchcancel", function(event) {

console.log("触摸取消");

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

});

// 手势识别函数

function detectGesture() {

var deltaX = touchEndX - touchStartX;

var deltaY = touchEndY - touchStartY;

var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

var duration = Date.now() - $("#touch-element").data("touchStartTime");

console.log("手势参数:", {

deltaX: deltaX,

deltaY: deltaY,

distance: distance,

duration: duration

});

// 滑动检测

if (Math.abs(deltaX) > 50 && Math.abs(deltaY) < 30) {

if (deltaX > 0) {

console.log("向右滑动");

swipeRight();

} else {

console.log("向左滑动");

swipeLeft();

}

}

// 垂直滑动

if (Math.abs(deltaY) > 50 && Math.abs(deltaX) < 30) {

if (deltaY > 0) {

console.log("向下滑动");

swipeDown();

} else {

console.log("向上滑动");

swipeUp();

}

}

// 轻触检测(快速触摸)

if (distance < 10 && duration < 300) {

console.log("轻触");

handleTap();

}

// 长按检测

if (duration > 1000) {

console.log("长按");

handleLongPress();

}

}

// 多点触控

$("#multi-touch").on("touchstart", function(event) {

var touches = event.originalEvent.touches;

console.log("触摸点数:", touches.length);

if (touches.length === 2) {

// 双指手势

console.log("双指触摸");

var touch1 = touches[0];

var touch2 = touches[1];

// 计算初始距离

var initialDistance = getDistance(

touch1.pageX, touch1.pageY,

touch2.pageX, touch2.pageY

);

$(this).data("initialDistance", initialDistance);

}

});

$("#multi-touch").on("touchmove", function(event) {

var touches = event.originalEvent.touches;

if (touches.length === 2) {

event.preventDefault();

var touch1 = touches[0];

var touch2 = touches[1];

// 计算当前距离

var currentDistance = getDistance(

touch1.pageX, touch1.pageY,

touch2.pageX, touch2.pageY

);

var initialDistance = $(this).data("initialDistance");

var scale = currentDistance / initialDistance;

console.log("缩放比例:", scale);

// 应用缩放

$(this).css("transform", "scale(" + scale + ")");

}

});

function getDistance(x1, y1, x2, y2) {

var dx = x2 - x1;

var dy = y2 - y1;

return Math.sqrt(dx * dx + dy * dy);

}

// 移动端点击延迟处理

// 使用fastclick库或以下方法

$("#mobile-button").on("touchstart click", function(event) {

// 阻止触摸事件后的click事件

if (event.type === "touchstart") {

$(this).data("touchStarted", true);

} else if (event.type === "click" && $(this).data("touchStarted")) {

event.preventDefault();

event.stopPropagation();

$(this).removeData("touchStarted");

return false;

}

// 处理点击逻辑

handleButtonClick();

});

// 检测设备是否支持触摸

function isTouchDevice() {

return 'ontouchstart' in window ||

navigator.maxTouchPoints > 0 ||

navigator.msMaxTouchPoints > 0;

}

if (isTouchDevice()) {

$("body").addClass("touch-device");

console.log("触摸设备");

} else {

$("body").addClass("no-touch");

console.log("非触摸设备");

}

触摸事件演示:

在此区域触摸/点击

(在移动设备或模拟触摸的设备上效果更好)

开始位置: -

结束位置: -

手势: -

触摸点数: 0

设备类型: 检测中...

事件日志:

清空日志

移动端开发建议

同时处理触摸和鼠标事件以确保兼容性

使用event.preventDefault()防止触摸时的默认行为(如滚动)

考虑点击延迟问题,可使用FastClick等库

为触摸事件提供视觉反馈

测试不同尺寸的触摸设备和不同操作系统

事件对象

事件对象包含事件相关的所有信息,在事件处理函数中作为参数传递。

事件对象详解

jQuery事件对象是对原生事件对象的封装,提供跨浏览器兼容的属性。

// 事件处理函数接收事件对象

$(selector).on("click", function(event) {

// 使用事件对象

console.log(event.type);

})

事件对象常用属性:

属性

描述

示例

type

事件类型(如 "click")

event.type

target

触发事件的元素

event.target

currentTarget

当前处理事件的元素

event.currentTarget

relatedTarget

相关元素(如mouseenter的离开元素)

event.relatedTarget

pageX/pageY

鼠标相对于文档的坐标

event.pageX

clientX/clientY

鼠标相对于视口的坐标

event.clientX

screenX/screenY

鼠标相对于屏幕的坐标

event.screenX

which

鼠标按钮或键盘键码

event.which

key/keyCode

键盘按键信息

event.key

shiftKey

是否按下了Shift键

event.shiftKey

ctrlKey

是否按下了Ctrl键

event.ctrlKey

altKey

是否按下了Alt键

event.altKey

metaKey

是否按下了Meta键

event.metaKey

timeStamp

事件发生的时间戳

event.timeStamp

data

通过on()方法传递的数据

event.data

result

上一个事件处理函数的返回值

event.result

originalEvent

原始的事件对象

event.originalEvent

事件对象方法:

方法

描述

示例

preventDefault()

阻止事件的默认行为

event.preventDefault()

stopPropagation()

阻止事件冒泡

event.stopPropagation()

stopImmediatePropagation()

阻止事件冒泡并阻止同类型其他处理函数执行

event.stopImmediatePropagation()

isDefaultPrevented()

检查是否调用了preventDefault()

event.isDefaultPrevented()

isPropagationStopped()

检查是否调用了stopPropagation()

event.isPropagationStopped()

// 事件对象使用示例

$("#element").on("click", function(event) {

// 获取事件信息

console.log("事件类型:", event.type);

console.log("目标元素:", event.target.tagName);

console.log("当前元素:", event.currentTarget.tagName);

console.log("鼠标坐标:", event.pageX, event.pageY);

console.log("时间戳:", event.timeStamp);

// 检查按键状态

if (event.shiftKey) {

console.log("按下了Shift键");

}

if (event.ctrlKey) {

console.log("按下了Ctrl键");

}

// 阻止默认行为

event.preventDefault();

// 阻止事件冒泡

event.stopPropagation();

// 检查方法是否已被调用

console.log("默认行为已阻止?", event.isDefaultPrevented());

console.log("事件冒泡已阻止?", event.isPropagationStopped());

// 访问原始事件对象

console.log("原始事件:", event.originalEvent);

// 返回结果(可供后续事件处理函数访问)

return "处理完成";

});

// 链式事件处理

$("#element")

.on("click", function(event) {

console.log("第一个处理函数");

// 这个返回值可以在event.result中访问

return "第一个返回值";

})

.on("click", function(event) {

console.log("第二个处理函数");

console.log("上一个函数的返回值:", event.result); // "第一个返回值"

return "第二个返回值";

});

// 使用事件数据

$("#button").on("click", {user: "张三", action: "提交"}, function(event) {

console.log("用户:", event.data.user); // "张三"

console.log("操作:", event.data.action); // "提交"

});

// 鼠标事件对象

$("#element").on("mousedown", function(event) {

console.log("鼠标按钮:", event.which); // 1=左键, 2=中键, 3=右键

console.log("按钮:", event.button); // 同上

});

// 键盘事件对象

$("#input").on("keydown", function(event) {

console.log("键码:", event.keyCode);

console.log("键:", event.key);

console.log("代码:", event.code);

console.log("是否重复:", event.repeat);

});

事件对象演示:

点击我查看事件对象信息

事件对象属性:

测试preventDefault()

测试stopPropagation()

事件委托

事件委托是将事件处理程序附加到父元素,利用事件冒泡处理子元素的事件。

事件委托详解

事件委托可以提高性能,特别是对于动态添加的元素。

// 基本语法

$(parentSelector).on(eventType, childSelector, handler)

// 示例

$("#list").on("click", "li", function() {

console.log("列表项被点击");

})

为什么使用事件委托:

// 传统方式 - 直接绑定(不推荐用于动态元素)

$("li").click(function() {

console.log("列表项点击");

});

// 问题:动态添加的li元素不会有点击事件

$("#list").append("新项目"); // 这个新li没有点击事件

// 解决方案1 - 每次添加元素后重新绑定(性能差)

function addListItem(text) {

var $li = $("").text(text);

$("#list").append($li);

$li.click(function() { // 为每个新元素绑定事件

console.log("点击:", text);

});

}

// 解决方案2 - 事件委托(推荐)

$("#list").on("click", "li", function() {

console.log("点击:", $(this).text());

});

// 现在动态添加的li元素也会触发事件

$("#list").append("新项目"); // 这个新li也有点击事件

事件委托的优势:

// 1. 处理动态添加的元素

$("#dynamic-list").on("click", "li.item", function() {

// 即使li.item是动态添加的,也会触发事件

console.log("动态项目被点击");

});

// 动态添加元素

setInterval(function() {

$("#dynamic-list").append('新项目' + Date.now() + '');

}, 1000);

// 2. 减少事件处理程序数量

// 传统方式:为1000个元素绑定1000个事件处理程序

$("td").click(function() { // 性能差

console.log("单元格点击");

});

// 事件委托:只绑定1个事件处理程序

$("#table").on("click", "td", function() { // 性能好

console.log("单元格点击");

});

// 3. 简化事件管理

$("#container").on({

click: function(event) {

var $target = $(event.target);

// 根据目标元素执行不同操作

if ($target.is("button.delete")) {

deleteItem($target.closest(".item"));

} else if ($target.is("button.edit")) {

editItem($target.closest(".item"));

} else if ($target.is(".item")) {

selectItem($target);

}

},

mouseenter: function(event) {

if ($(event.target).is(".item")) {

$(event.target).addClass("hover");

}

},

mouseleave: function(event) {

if ($(event.target).is(".item")) {

$(event.target).removeClass("hover");

}

}

}, ".item, button"); // 只代理.item和button元素的事件

// 4. 内存管理更简单

// 移除元素时不需要特别处理事件

$(".item").remove(); // 事件处理程序仍然在#container上

// 如果要移除所有事件,只需:

$("#container").off();

事件委托示例:

// 表格行操作

$("#data-table").on("click", "td", function(event) {

event.stopPropagation(); // 阻止事件冒泡到tr

var $td = $(this);

var columnIndex = $td.index();

var rowIndex = $td.closest("tr").index();

console.log("点击单元格:", rowIndex, columnIndex);

// 根据不同列执行不同操作

if (columnIndex === 0) {

toggleCheckbox($td);

} else if (columnIndex === 1) {

editCell($td);

} else if (columnIndex === 2) {

deleteRow($td.closest("tr"));

}

});

// 列表操作

$("#todo-list").on({

click: function(event) {

var $target = $(event.target);

if ($target.is(".delete-btn")) {

// 删除项目

$target.closest(".todo-item").remove();

} else if ($target.is(".edit-btn")) {

// 编辑项目

editTodoItem($target.closest(".todo-item"));

} else if ($target.is(".todo-item")) {

// 切换完成状态

$target.toggleClass("completed");

}

},

dblclick: function(event) {

if ($(event.target).is(".todo-text")) {

// 双击文本编辑

editTodoText($(event.target));

}

}

}, ".todo-item, .delete-btn, .edit-btn, .todo-text");

// 表单动态字段

$("#dynamic-form").on({

focus: function() {

$(this).addClass("focused");

},

blur: function() {

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

validateField($(this));

},

change: function() {

updateFormState();

}

}, "input, select, textarea"); // 代理所有表单元素

// 动态添加表单字段

$("#add-field").click(function() {

var fieldId = "field-" + Date.now();

$("#dynamic-form").append(

'' +

' ' +

' 删除' +

''

);

});

// 删除动态字段(也需要事件委托)

$("#dynamic-form").on("click", ".remove-field", function() {

$(this).closest(".form-group").remove();

updateFormState();

});

// 性能对比示例

console.time("直接绑定");

for (var i = 0; i < 1000; i++) {

$("项目" + i + "")

.appendTo("#container")

.click(function() { // 为每个元素绑定事件

console.log("点击");

});

}

console.timeEnd("直接绑定"); // 较慢

console.time("事件委托");

$("#container").empty();

for (var i = 0; i < 1000; i++) {

$("项目" + i + "").appendTo("#container");

}

$("#container").on("click", ".item", function() { // 只绑定一次

console.log("点击");

});

console.timeEnd("事件委托"); // 较快

事件委托演示:

添加列表项

删除第一项

添加100项

项目1 删除

项目2 删除

项目3 删除

列表项数量: 3

点击计数: 0

事件日志:

事件委托的注意事项

事件委托利用事件冒泡,如果事件不冒泡(如focus、blur),需要使用focusin/focusout

过度使用事件委托可能导致事件处理逻辑复杂

对于简单、静态的元素,直接绑定可能更清晰

事件委托的目标选择器应尽可能具体,避免性能问题

使用event.stopPropagation()要谨慎,可能影响其他事件处理

事件流

事件流描述事件在DOM树中传播的顺序。

事件冒泡与捕获

DOM事件流包括三个阶段:捕获阶段、目标阶段、冒泡阶段。

捕获阶段

文档 → body → div

目标阶段

button

冒泡阶段

div → body → 文档

// 事件流演示

// 默认情况下,事件处理在冒泡阶段执行

$("#child").click(function(event) {

console.log("子元素 - 目标阶段");

});

$("#parent").click(function(event) {

console.log("父元素 - 冒泡阶段");

});

$("#grandparent").click(function(event) {

console.log("祖父元素 - 冒泡阶段");

});

$(document).click(function(event) {

console.log("文档 - 冒泡阶段");

});

// 点击按钮时输出顺序:

// 1. 子元素 - 目标阶段

// 2. 父元素 - 冒泡阶段

// 3. 祖父元素 - 冒泡阶段

// 4. 文档 - 冒泡阶段

// 使用捕获阶段

// jQuery默认不支持捕获阶段,需要使用原生addEventListener

document.getElementById("grandparent").addEventListener("click", function(event) {

console.log("祖父元素 - 捕获阶段");

}, true); // true表示在捕获阶段处理

document.getElementById("parent").addEventListener("click", function(event) {

console.log("父元素 - 捕获阶段");

}, true);

// 现在点击按钮时输出顺序:

// 1. 祖父元素 - 捕获阶段

// 2. 父元素 - 捕获阶段

// 3. 子元素 - 目标阶段(jQuery)

// 4. 父元素 - 冒泡阶段(jQuery)

// 5. 祖父元素 - 冒泡阶段(jQuery)

// 6. 文档 - 冒泡阶段(jQuery)

// 阻止事件冒泡

$("#child").click(function(event) {

console.log("子元素点击");

event.stopPropagation(); // 阻止事件冒泡

// 现在只有这个处理函数会执行

});

$("#parent").click(function(event) {

console.log("这个不会执行,因为事件冒泡被阻止了");

});

// 阻止默认行为

$("a").click(function(event) {

event.preventDefault(); // 阻止链接跳转

console.log("链接被点击,但不会跳转");

});

// 同时阻止默认行为和冒泡

$("a").click(function(event) {

event.preventDefault();

event.stopPropagation();

// 或者使用 return false

// return false; // 等同于上面两行

});

// 事件委托中的事件流

$("#grandparent").on("click", "#child", function(event) {

console.log("事件委托处理");

// 事件仍然会冒泡到#grandparent

});

// 检查事件阶段

document.getElementById("child").addEventListener("click", function(event) {

console.log("事件阶段:", event.eventPhase);

// 1: 捕获阶段

// 2: 目标阶段

// 3: 冒泡阶段

}, true);

// 事件委托和事件流的结合

$("#container").on("click", function(event) {

console.log("容器点击,目标:", event.target.tagName);

// 根据event.target决定如何处理

if ($(event.target).is("button")) {

console.log("点击了按钮");

} else if ($(event.target).is("input")) {

console.log("点击了输入框");

}

});

// 事件流可视化

function logEventFlow(event) {

var phase;

switch(event.eventPhase) {

case Event.CAPTURING_PHASE: phase = "捕获"; break;

case Event.AT_TARGET: phase = "目标"; break;

case Event.BUBBLING_PHASE: phase = "冒泡"; break;

}

console.log(event.currentTarget.id + " - " + phase + "阶段");

}

// 为所有元素添加事件监听

$("#grandparent, #parent, #child").each(function() {

this.addEventListener("click", logEventFlow, true); // 捕获阶段

this.addEventListener("click", logEventFlow, false); // 冒泡阶段

});

事件流演示:

文档

body

div#grandparent

div#parent

button#child

点击我

阻止事件冒泡

阻止立即传播

事件流日志:

清空日志

自定义事件

自定义事件允许创建和触发自己的事件类型。

创建和触发自定义事件

自定义事件可以实现组件间的松耦合通信。

// 绑定自定义事件

$(selector).on("customEvent", handler)

// 触发自定义事件

$(selector).trigger("customEvent"[, extraParameters])

// 使用命名空间

$(selector).on("customEvent.namespace", handler)

// 创建带数据的事件

var event = $.Event("customEvent", {data: value})

基本自定义事件:

// 创建自定义事件

$("#element").on("myCustomEvent", function(event, param1, param2) {

console.log("自定义事件触发", param1, param2);

});

// 触发自定义事件

$("#element").trigger("myCustomEvent", ["参数1", "参数2"]);

// 带命名空间的自定义事件

$("#element").on("myEvent.namespace1", function() {

console.log("命名空间1的事件");

});

$("#element").on("myEvent.namespace2", function() {

console.log("命名空间2的事件");

});

// 触发特定命名空间的事件

$("#element").trigger("myEvent.namespace1");

// 移除特定命名空间的事件

$("#element").off(".namespace1");

// 创建自定义事件对象

var customEvent = $.Event("customEvent", {

pageX: 100,

pageY: 200,

data: {key: "value"}

});

// 触发带自定义数据的事件

$("#element").trigger(customEvent);

// 在事件处理函数中访问自定义数据

$("#element").on("customEvent", function(event) {

console.log("自定义数据:", event.data); // {key: "value"}

console.log("页面坐标:", event.pageX, event.pageY); // 100, 200

});

自定义事件应用场景:

// 1. 组件间通信

// 购物车组件

var ShoppingCart = {

init: function() {

this.bindEvents();

},

bindEvents: function() {

// 监听商品添加事件

$(document).on("productAdded", function(event, product) {

ShoppingCart.addProduct(product);

});

// 监听商品移除事件

$(document).on("productRemoved", function(event, productId) {

ShoppingCart.removeProduct(productId);

});

},

addProduct: function(product) {

console.log("添加商品:", product);

// 更新购物车UI

this.updateUI();

// 触发购物车更新事件

$(document).trigger("cartUpdated", [this.getCartItems()]);

},

removeProduct: function(productId) {

console.log("移除商品:", productId);

// 更新购物车UI

this.updateUI();

// 触发购物车更新事件

$(document).trigger("cartUpdated", [this.getCartItems()]);

},

updateUI: function() {

// 更新购物车显示

},

getCartItems: function() {

// 返回购物车商品列表

return [];

}

};

// 商品列表组件

$(".add-to-cart").click(function() {

var product = {

id: $(this).data("id"),

name: $(this).data("name"),

price: $(this).data("price")

};

// 触发商品添加事件

$(document).trigger("productAdded", [product]);

});

// 2. 状态变化通知

var ApplicationState = {

currentUser: null,

login: function(user) {

this.currentUser = user;

// 触发登录事件

$(document).trigger("userLoggedIn", [user]);

},

logout: function() {

var oldUser = this.currentUser;

this.currentUser = null;

// 触发登出事件

$(document).trigger("userLoggedOut", [oldUser]);

}

};

// 监听登录状态变化

$(document).on("userLoggedIn", function(event, user) {

console.log("用户登录:", user.name);

updateUIForLoggedInUser(user);

});

$(document).on("userLoggedOut", function(event, user) {

console.log("用户登出:", user.name);

updateUIForLoggedOutUser();

});

// 3. 异步操作完成通知

function loadUserData(userId) {

// 模拟异步加载

setTimeout(function() {

var userData = {

id: userId,

name: "张三",

email: "zhangsan@example.com"

};

// 数据加载完成,触发事件

$(document).trigger("userDataLoaded", [userData]);

}, 1000);

}

// 监听数据加载完成

$(document).on("userDataLoaded", function(event, userData) {

console.log("用户数据加载完成:", userData);

renderUserProfile(userData);

});

// 开始加载数据

loadUserData(123);

// 4. 表单验证事件

$("#registration-form").on("submit", function(event) {

event.preventDefault();

var formData = $(this).serializeArray();

var errors = validateFormData(formData);

if (errors.length === 0) {

// 表单验证通过,触发事件

$(this).trigger("formValid", [formData]);

} else {

// 表单验证失败,触发事件

$(this).trigger("formInvalid", [errors]);

}

});

// 监听表单验证结果

$("#registration-form")

.on("formValid", function(event, formData) {

console.log("表单验证通过,提交数据");

submitForm(formData);

})

.on("formInvalid", function(event, errors) {

console.log("表单验证失败:", errors);

displayErrors(errors);

});

// 5. 自定义事件命名空间管理

// 为不同模块使用不同命名空间

var UserModule = {

namespace: "userModule",

init: function() {

this.bindEvents();

},

bindEvents: function() {

$(document).on("login." + this.namespace, this.onLogin.bind(this));

$(document).on("logout." + this.namespace, this.onLogout.bind(this));

},

onLogin: function(event, user) {

console.log("用户模块: 用户登录", user);

},

onLogout: function(event, user) {

console.log("用户模块: 用户登出", user);

},

destroy: function() {

// 清理事件

$(document).off("." + this.namespace);

}

};

var CartModule = {

namespace: "cartModule",

init: function() {

this.bindEvents();

},

bindEvents: function() {

$(document).on("productAdded." + this.namespace, this.onProductAdded.bind(this));

},

onProductAdded: function(event, product) {

console.log("购物车模块: 商品添加", product);

},

destroy: function() {

// 清理事件

$(document).off("." + this.namespace);

}

};

// 初始化模块

UserModule.init();

CartModule.init();

// 触发事件(所有模块都会收到)

$(document).trigger("login", [{id: 1, name: "张三"}]);

$(document).trigger("productAdded", [{id: 101, name: "商品A"}]);

// 销毁特定模块

UserModule.destroy(); // 只移除用户模块的事件

自定义事件演示:

触发自定义事件

触发命名空间事件

触发带数据的事件

添加事件处理程序

移除事件处理程序

移除所有自定义事件

自定义事件日志:

清空日志

综合演示

综合演示各种事件处理技术。

事件处理综合演示

交互式演示面板

鼠标事件区域

在此区域交互

等待交互...

重置区域

交互次数: 0

事件计数器

点击

0

鼠标移动

0

按键

0

输入

0

重置计数器

动态列表(事件委托)

添加

示例项目1 ×

示例项目2 ×

项目数量: 2

事件控制面板

启用鼠标事件

启用键盘事件

启用事件日志

触发所有事件

移除所有事件

综合事件日志

导出日志

清空日志

日志条目: 0

事件处理总结

事件绑定: 使用 on() 方法绑定事件,off() 方法移除事件

事件类型: 鼠标事件、键盘事件、表单事件、窗口事件、触摸事件

事件对象: 包含事件所有信息,可使用 preventDefault() 和 stopPropagation()

事件委托: 使用 $(parent).on(event, childSelector, handler) 处理动态元素

事件流: 事件传播的三个阶段:捕获、目标、冒泡

自定义事件: 使用 trigger() 触发自定义事件,实现组件间通信

最佳实践: 使用事件委托提高性能,合理使用事件命名空间,注意内存管理

上一章: DOM 操作与修改

下一章: jQuery 动画与效果

Posted in 奇遇簿
Copyright © 2088 幻斗之墟最新活动_仙侠MMO官网 All Rights Reserved.
友情链接