1. eventoverview
event is user and 网页交互时发生 动作, such as点击鼠标, 按 under 键盘, move鼠标etc.. JavaScript 可以througheventprocessing来response这些user交互.
eventprocessing is JavaScript inimplementation交互functions coremechanism, 它使网页able to响application户 operation并做出相应 反应.
2. commoneventclass型
JavaScript support many 种class型 event, 以 under is 一些common eventclass型:
2.1 鼠标event
click - 鼠标点击元素时触发
dblclick - 鼠标双击元素时触发
mouseover - 鼠标指针move to 元素 on 时触发
mouseout - 鼠标指针离开元素时触发
mousemove - 鼠标指针 in 元素 on move时触发
mousedown - 鼠标按钮 in 元素 on 按 under 时触发
mouseup - 鼠标按钮 in 元素 on 释放时触发
2.2 键盘event
keydown - 键盘按键按 under 时触发
keyup - 键盘按键释放时触发
keypress - 键盘按键按 under 并释放时触发 (已废弃)
2.3 表单event
submit - 表单submitting时触发
change - 表单元素 值发生变化时触发
input - 表单元素输入时触发
focus - 表单元素获得焦点时触发
blur - 表单元素失去焦点时触发
2.4 documentation/窗口event
load - 页面 or resource加载completion时触发
unload - 页面卸载时触发
resize - 窗口 big small 改变时触发
scroll - 页面滚动时触发
DOMContentLoaded - DOM 加载completion时触发
3. event监听器
event监听器 is amechanism, 用于监听specific event并 in event发生时执行相应 processingfunction.
3.1 添加event监听器
// 获取元素
const button = document.getElementById('myButton');
// 添加event监听器
button.addEventListener('click', function() {
console.log('按钮被点击了!');
});
// using命名function
function handleClick() {
console.log('按钮被点击了 (命名function) !');
}
button.addEventListener('click', handleClick);
// using箭头function
button.addEventListener('click', () => {
console.log('按钮被点击了 (箭头function) !');
});
3.2 移除event监听器
// 获取元素
const button = document.getElementById('myButton');
// 定义eventprocessingfunction
function handleClick() {
console.log('按钮被点击了!');
}
// 添加event监听器
button.addEventListener('click', handleClick);
// 移除event监听器
button.removeEventListener('click', handleClick);
// 注意: 匿名function无法被移除
button.addEventListener('click', function() {
console.log('这个监听器无法被移除!');
});
// under 面 code不会生效
button.removeEventListener('click', function() {
console.log('这个监听器无法被移除!');
});
3.3 event监听器 第三个parameter
// 获取元素
const button = document.getElementById('myButton');
// 添加event监听器, 第三个parameter控制event 捕获/冒泡阶段
button.addEventListener('click', handleClick, {
capture: false, // is 否 in 捕获阶段触发
once: false, // is 否只触发一次
passive: false // is 否不阻止默认behavior
});
// example: 只触发一次 event监听器
button.addEventListener('click', function() {
console.log('这个监听器只会触发一次!');
}, { once: true });
4. eventobject
当event触发时, 浏览器会creation一个eventobject (Event Object) , 并将其serving asparameter传递给eventprocessingfunction. eventobjectpackage含了 and event相关 information.
// 获取元素
const button = document.getElementById('myButton');
// 添加event监听器
button.addEventListener('click', function(event) {
console.log('eventobject:', event);
console.log('eventclass型:', event.type);
console.log('触发event 元素:', event.target);
console.log('当 before processingevent 元素:', event.currentTarget);
console.log('鼠标点击 X坐标:', event.clientX);
console.log('鼠标点击 Y坐标:', event.clientY);
console.log(' is 否按 under 了Ctrl键:', event.ctrlKey);
console.log(' is 否按 under 了Shift键:', event.shiftKey);
console.log(' is 否按 under 了Alt键:', event.altKey);
});
4.1 eventobject 常用method
// 阻止默认behavior
event.preventDefault();
// 阻止event冒泡
event.stopPropagation();
// 阻止event 进一步捕获 or 冒泡, 并阻止任何otherevent监听器被调用
event.stopImmediatePropagation();
// 获取event 目标元素
event.target;
// 获取当 before processingevent 元素
event.currentTarget;
5. event传播
event传播 is 指event from 触发元素向 DOM tree other部分传播 过程. event传播分 for 三个阶段:
5.1 捕获阶段 (Capture Phase)
event from documentation根node向 under 传播 to 目标元素.
5.2 目标阶段 (Target Phase)
event to 达目标元素.
5.3 冒泡阶段 (Bubbling Phase)
event from 目标元素向 on 传播回documentation根node.
// HTML structure
//
// 获取元素
const outer = document.getElementById('outer');
const middle = document.getElementById('middle');
const inner = document.getElementById('inner');
// 添加捕获阶段 监听器
outer.addEventListener('click', function() {
console.log('Outer - 捕获阶段');
}, { capture: true });
middle.addEventListener('click', function() {
console.log('Middle - 捕获阶段');
}, { capture: true });
inner.addEventListener('click', function() {
console.log('Inner - 捕获阶段');
}, { capture: true });
// 添加冒泡阶段 监听器
outer.addEventListener('click', function() {
console.log('Outer - 冒泡阶段');
}, { capture: false });
middle.addEventListener('click', function() {
console.log('Middle - 冒泡阶段');
}, { capture: false });
inner.addEventListener('click', function() {
console.log('Inner - 冒泡阶段');
}, { capture: false });
// 点击 inner 元素时 输出顺序:
// Outer - 捕获阶段
// Middle - 捕获阶段
// Inner - 捕获阶段
// Inner - 冒泡阶段
// Middle - 冒泡阶段
// Outer - 冒泡阶段
6. event委托
event委托 is aeventprocessing模式, 它利用event冒泡 features, 将event监听器添加 to 父元素 on , 而不 is 每个子元素 on . 当子元素触发event时, event会冒泡 to 父元素, 父元素 event监听器可以processing这些event.
event委托 优点:
reducingevent监听器 数量, improvingperformance
可以processing动态添加 子元素 event
简化codestructure
// HTML structure
//
// project 1 delete
// project 2 delete
// project 3 delete
//
// 获取父元素
const todoList = document.getElementById('todo-list');
// 添加event委托
todoList.addEventListener('click', function(event) {
// check点击 元素 is 否 is delete按钮
if (event.target.classList.contains('delete')) {
// 获取 for 应 list项
const listItem = event.target.closest('li');
if (listItem) {
listItem.remove();
console.log('delete了project');
}
}
});
// 动态添加 new 项
function addTodoItem(text) {
const li = document.createElement('li');
li.textContent = text;
const deleteButton = document.createElement('button');
deleteButton.textContent = 'delete';
deleteButton.className = 'delete';
li.appendChild(deleteButton);
todoList.appendChild(li);
}
// 添加 new 项
addTodoItem('project 4');
addTodoItem('project 5');
// new 添加 项也会responsedeleteevent, 因 for event委托 in 父元素 on
7. eventprocessingtechniques
7.1 in 联eventprocessing器
直接 in HTML 元素in添加eventprocessingcode (不推荐) .
点击我
点击我
7.2 DOM propertyeventprocessing器
through JavaScript 设置元素 eventproperty (不推荐) .
// 获取元素
const button = document.getElementById('myButton');
// 设置eventproperty
button.onclick = function() {
console.log('按钮被点击了!');
};
// 注意: 这种方式只能添加一个eventprocessing器
button.onclick = function() {
console.log('这会覆盖之 before 点击eventprocessing器!');
};
7.3 event监听器 (推荐)
using addEventListener() method添加event监听器 (推荐) .
// 获取元素
const button = document.getElementById('myButton');
// 添加 many 个event监听器
button.addEventListener('click', function() {
console.log('第一个点击eventprocessing器');
});
button.addEventListener('click', function() {
console.log('第二个点击eventprocessing器');
});
// 两个processing器都会执行
8. 自定义event
除了浏览器 in 置 event, JavaScript 还允许creation and 触发自定义event.
// creation自定义event
const customEvent = new Event('customEvent', {
bubbles: true, // is 否冒泡
cancelable: true, // is 否可取消
composed: false // is 否可以穿越 Shadow DOM edge界
});
// creation带自定义data event
const customEventWithData = new CustomEvent('customEventWithData', {
bubbles: true,
cancelable: true,
detail: {
message: '这 is 自定义event data',
timestamp: new Date().getTime()
}
});
// 获取元素
const element = document.getElementById('myElement');
// 添加event监听器
element.addEventListener('customEvent', function(event) {
console.log('自定义event被触发了!');
});
element.addEventListener('customEventWithData', function(event) {
console.log('带data 自定义event被触发了!');
console.log('eventdata:', event.detail);
});
// 触发event
element.dispatchEvent(customEvent);
element.dispatchEvent(customEventWithData);
实践case: 交互式graph片library
creation一个交互式graph片library, implementation以 under functions:
显示graph片缩略graph
点击缩略graph时显示 big graph
implementationgraph片 on 一张/ under 一张切换
implementation键盘导航 ( left right 箭头键)
点击 big graph out 部关闭预览
// HTML structure
//
//
//
//
×
//
//
on 一张
//
under 一张
//
//
// graph片data
const images = [
'image1.jpg',
'image2.jpg',
'image3.jpg',
'image4.jpg',
'image5.jpg'
];
// 获取元素
const gallery = document.getElementById('gallery');
const lightbox = document.getElementById('lightbox');
const lightboxImg = document.getElementById('lightbox-img');
const closeBtn = document.querySelector('.close');
const prevBtn = document.querySelector('.prev');
const nextBtn = document.querySelector('.next');
let currentIndex = 0;
// 显示 big graph
function showLightbox(index) {
currentIndex = index;
lightboxImg.src = images[index];
lightbox.style.display = 'block';
}
// 关闭 big graph
function closeLightbox() {
lightbox.style.display = 'none';
}
// 显示 on 一张
function showPrev() {
currentIndex = (currentIndex - 1 + images.length) % images.length;
lightboxImg.src = images[currentIndex];
}
// 显示 under 一张
function showNext() {
currentIndex = (currentIndex + 1) % images.length;
lightboxImg.src = images[currentIndex];
}
// 添加event监听器
// 点击缩略graph
gallery.addEventListener('click', function(event) {
const thumbnail = event.target.closest('.thumbnail');
if (thumbnail) {
const index = parseInt(thumbnail.dataset.index);
showLightbox(index);
}
});
// 关闭按钮
closeBtn.addEventListener('click', closeLightbox);
// on 一张按钮
prevBtn.addEventListener('click', showPrev);
// under 一张按钮
nextBtn.addEventListener('click', showNext);
// 点击 big graph out 部关闭
lightbox.addEventListener('click', function(event) {
if (event.target === lightbox) {
closeLightbox();
}
});
// 键盘导航
window.addEventListener('keydown', function(event) {
if (lightbox.style.display === 'block') {
if (event.key === 'Escape') {
closeLightbox();
} else if (event.key === 'ArrowLeft') {
showPrev();
} else if (event.key === 'ArrowRight') {
showNext();
}
}
});
互动练习: eventprocessing实践
请completion以 under eventprocessingtask:
creation一个计数器, 初始值 for 0
添加 "增加" and "reducing" 按钮
implementation点击按钮时update计数器值
添加键盘support (+ 键增加, - 键reducing)
添加reset按钮
显示operationhistory记录
计数器
0
-
+
reset
提示: using键盘 + and - 键也可以operation计数器