属性/事件(鼠标键盘)
元素
1. 基础标识与内容属性
| 属性 | 说明 |
|---|---|
id | 元素的唯一标识符 |
className | 元素的 class 属性值(字符串形式) |
classList | DOMTokenList 对象,提供 add/remove/toggle/contains 等方法操作类名 |
tagName / nodeName | 标签名称(大写,如 "DIV") |
innerHTML | 元素内部的 HTML 内容(包含标签) |
outerHTML | 元素自身及其内部的完整 HTML |
textContent | 元素及其后代的纯文本内容(不包含 HTML 标签) |
innerText | 类似 textContent,但会考虑 CSS 样式(如 display:none 的内容不会被获取) |
2. 尺寸与位置属性(几何信息)
| 属性 | 说明 |
|---|---|
offsetWidth / offsetHeight | 元素可见区域的宽高(含 border + padding + scrollbar) |
clientWidth / clientHeight | 内容区域宽高(含 padding,不含 border 和 scrollbar) |
scrollWidth / scrollHeight | 元素内容的实际总宽高(包括溢出不可见的部分) |
offsetTop / offsetLeft | 相对于 offsetParent 的偏移距离 |
clientTop / clientLeft | 边框宽度(上/左边框) |
scrollTop / scrollLeft | 元素滚动条滚动的距离 |
getBoundingClientRect() | 方法,返回相对于视口的精确位置对象 {top, right, bottom, left, width, height, x, y} |
可视窗口
const vw = document.documentElement.clientWidth; // 可视窗口宽度
const vh = document.documentElement.clientHeight; // 可视窗口高度3. 节点关系属性(DOM 树遍历)
| 属性 | 说明 |
|---|---|
parentNode / parentElement | 父节点 / 父元素节点 |
childNodes / children | 所有子节点(含文本/注释) / 仅子元素节点 |
firstChild / firstElementChild | 第一个子节点 / 第一个子元素 |
lastChild / lastElementChild | 最后一个子节点 / 最后一个子元素 |
nextSibling / nextElementSibling | 下一个兄弟节点 / 下一个兄弟元素 |
previousSibling / previousElementSibling | 上一个兄弟节点 / 上一个兄弟元素 |
4. 通用属性访问方法
/* 设置自定义属性 */
元素.setAttribute((属性名), (属性值))
// 设置属性值
element.setAttribute('data-custom', 'value')
// 获取属性值
element.getAttribute('data-custom')
// 判断属性是否存在
element.hasAttribute('disabled')
// 移除属性
element.removeAttribute('class')推荐替代方案: 对于 data-* 自定义属性,优先使用 dataset API,语法更简洁且自动处理驼峰转换:
// 设置(自动转为 data-user-id)
element.dataset.userId = '123';
// 读取
console.log(element.dataset.userId); // "123"⚠️ 注意: setAttribute 的值始终是字符串。如果传入数字或对象,会被隐式转换为字符串。而 dataset 赋值同样也是字符串类型。
5. 插入dom元素
创建与克隆
| 方法 | 说明 |
|---|---|
document.createElement(tag) | 创建元素节点 |
document.createTextNode(text) | 创建文本节点 |
document.createDocumentFragment() | 创建文档片段(内存中的临时容器,批量操作减少重排) |
node.cloneNode(deep) | 克隆节点,deep=true 时递归克隆所有后代 |
插入与追加
传统方法
| 方法 | 说明 |
|---|---|
parent.appendChild(node) | 追加为最后一个子节点 |
parent.insertBefore(new, ref) | 在参考节点之前插入 |
现代方法
| 方法 | 调用对象 | 说明 |
|---|---|---|
append(...nodes) | 父元素 | 末尾追加(支持多节点+字符串) |
prepend(...nodes) | 父元素 | 开头插入(支持多节点+字符串) |
before(...nodes) | 参考节点 | 在参考节点之前插入 |
after(...nodes) | 参考节点 | 在参考节点之后插入 |
创建 + 批量插入:高性能渲染列表
// ✅ 使用 DocumentFragment 避免多次重排
const fragment = document.createDocumentFragment();
['西瓜', '葡萄', '芒果'].forEach(text => {
const li = document.createElement('li');
li.className = 'item';
li.textContent = text;
fragment.appendChild(li);
});
// 一次性插入到末尾(只触发 1 次重排)
document.querySelector('#list').append(fragment);
// 💡 现代写法:before/after/prepend 支持混合传入节点和字符串
const ref = document.querySelector('.item'); // 苹果
ref.before('🍉 ', document.createElement('br')); // 在"苹果"前插入文本+换行替换与移除
| 方法 | 说明 |
|---|---|
parent.replaceChild(new, old) | 传统替换子节点 |
oldNode.replaceWith(...nodes) | ✅ 现代写法,用新节点替换自身 |
parent.removeChild(node) | 传统移除子节点 |
node.remove() | ✅ 现代写法,直接移除自身 |
替换与移除:简洁的现代写法
const oldLi = document.querySelectorAll('.item')[1]; // 香蕉
// ✅ 现代:直接替换自身
oldLi.replaceWith(Object.assign(document.createElement('li'), {
className: 'item',
textContent: '🍌 新香蕉'
}));
// ✅ 现代:直接移除自身(不需要找父元素)
document.querySelector('.item:last-child').remove();
// ❌ 传统写法对比(繁琐)
// parent.replaceChild(newNode, oldNode);
// parent.removeChild(node);const el = document.querySelector('#list');
// 相对于视口的精确位置(弹窗定位、吸顶判断必备)
const rect = el.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);
// 插入dom节点
ul.children[0].before(li); // 在第一个子元素之前插入
ul.prepend(li); // 插入到最前面
ul.append(li); // 插入到最后面
li.after(newLi); // 在 li 之后插入6. 类名操作 (classList)
| 方法 | 说明 |
|---|---|
classList.add(...classes) | 添加一个或多个类 |
classList.remove(...classes) | 移除一个或多个类 |
classList.toggle(class, force?) | 切换类(有则删,无则加;force 可强制加/删) |
classList.contains(class) | 判断是否包含某个类 |
classList.replace(old, new) | 替换类名 |
classList.entries() / forEach() | 遍历所有类名 |
类名操作:告别字符串拼接
const el = document.querySelector('.item');
el.classList.add('active', 'highlight'); // 同时加多个类
el.classList.remove('active'); // 移除
el.classList.toggle('open'); // 有则删,无则加
el.classList.toggle('disabled', false); // 第二个参数强制控制:false=删除,true=添加
el.classList.contains('highlight'); // → true
el.classList.replace('highlight', 'selected'); // 替换类名
// 遍历所有类名
el.classList.forEach(cls => console.log(cls));7. 修改CSS变量、属性值
setProperty?
document.documentElement.style.setProperty() 用于在 <html> 元素上设置 CSS 自定义属性(CSS Variables)或普通内联样式。它是操作全局 CSS 变量最标准的方式。
- 基本语法
element.style.setProperty(propertyName, value, priority);- 属性
| 参数 | 说明 | 示例 |
|---|---|---|
propertyName | CSS 属性名(字符串),自定义属性需带 -- 前缀 | '--theme-color', 'font-size' |
value | 属性值(字符串) | '#ff6600', '16px' |
priority | 可选,优先级 | 'important' 或 ''(默认) |
常见用法示例
const root = document.documentElement;
// ✅ 设置 CSS 自定义属性(最常用)
root.style.setProperty('--primary-color', '#3498db');
root.style.setProperty('--spacing-unit', '8px');
// ✅ 设置带 !important
root.style.setProperty('--danger-color', 'red', 'important');
// ✅ 读取自定义属性(注意:用 getPropertyValue,不是 getProperty)
const color = root.style.getPropertyValue('--primary-color').trim();
// ✅ 删除自定义属性
root.style.removeProperty('--primary-color');- 简单示例
// 如:css变量--vt-old-z: 1; 使用:z-index: var(--vt-old-z, 888);
// 修改 CSS 变量
document.documentElement.style.setProperty('--vt-old-z', '9999');
// 移除该变量,下次读取时就会触发 888
document.documentElement.style.removeProperty('--vt-new-z');
// 或者显式设为 unset,为默认值
document.documentElement.style.setProperty('--vt-new-z', 'unset');window
1. 获取滚动条滚动的距离
1). document.documentElement.scrollTop || document.body.scrollTop 或 document.querySelector("div").scrollTop
2). window.pageYoffset ---> Y轴滚动条
3). window.pageXoffset ---> X轴滚动条
2. window.close() --- 关闭当前页面滚动到某一区域
scrollTo()
window.scrollTo() 是浏览器原生 API,用于将窗口或可滚动元素滚动到指定位置;
当然,scrollTo 不只是 window 的专利,任何有滚动条的元素都能用;
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| top | number | 0 | smooth=平滑动画,instant=瞬间跳转,auto=跟随CSS设置 |
| left | number | 0 | 垂直方向:元素顶部/居中/底部/最近边缘 对齐容器对应位置 |
| behavior | 'auto' | 'smooth' | 'instant' | auto | smooth=平滑动画,instant=瞬间跳转,auto=跟随CSS设置 |
window窗口使用:
window.scrollTo({
top: 500, // 垂直滚动位置(px)
left: 0, // 水平滚动位置(px),可省略
behavior: 'smooth' // 'auto'(默认,瞬间跳转) | 'smooth'(平滑动画)
});dom元素使用:
// 滚动到指定元素的位置(替代 scrollIntoView)
// 当你需要更精确的控制(比如加偏移量)时:
const target = document.querySelector('#section');
const offset = 80; // 例如固定导航栏高度
window.scrollTo({
top: target.getBoundingClientRect().top + window.scrollY - offset,
behavior: 'smooth'
});控制dom元素滚动到可视区域
element.scrollIntoView({ // element 【dom元素】
behavior: 'smooth', // 滚动行为
block: 'start', // 垂直对齐方式
inline: 'nearest' // 水平对齐方式
});提示
scrollIntoView() 是一个 DOM 元素方法,它的作用非常直接:自动滚动页面或容器,让调用它的元素出现在可视区域内。
scrollIntoView() 只能在 DOM 元素(即 Element 节点)上调用!
| 属性 | 可选值 | 说明 |
|---|---|---|
| behavior | 'auto' | 'smooth' | 'instant' | smooth=平滑动画,instant=瞬间跳转,auto=跟随CSS设置 |
| block | 'start' | 'center' | 'end' | 'nearest' | 垂直方向:元素顶部/居中/底部/最近边缘 对齐容器对应位置 |
| inline | 'start' | 'center' | 'end' | 'nearest' | 水平方向:同上 |
鼠标
核心鼠标事件类型
| 事件类型 | 触发时机 | 常用场景 |
|---|---|---|
| 点击类 | ||
| dblclick | 鼠标左键双击触发 | 双击编辑、文件打开 |
| mousedown | 鼠标任意按键按下时触发(左 / 中 / 右) | 拖拽开始、按住操作 |
| mouseup | 鼠标任意按键松开时触发(左 / 中 / 右) | 拖拽结束、释放操作 |
| contextmenu | 鼠标右键单击(触发上下文菜单) | 自定义右键菜单 |
| 移动类 | ||
| mousemove | 鼠标在元素内移动时持续触发 | 拖拽跟踪、鼠标位置监听 |
| mouseover | 鼠标移入元素(含子元素)时触发 | 悬浮提示(会冒泡) |
| mouseenter | 鼠标移入元素(不含子元素)时触发 | 悬浮样式(不冒泡,推荐) |
| mouseout | 鼠标移出元素(含子元素)时触发 | 悬浮恢复(会冒泡) |
| mouseleave | 鼠标移出元素(不含子元素)时触发 | 悬浮恢复(不冒泡,推荐) |
| 滚动类 | ||
| wheel | 鼠标滚轮滚动时触发(上下 / 左右) | 自定义滚动逻辑、防滚动穿透 |
| 其他 | ||
| drag | 元素被拖拽时持续触发 | 拖拽过程跟踪 |
| dragstart | 元素开始被拖拽时触发 | 拖拽初始化 |
| dragend | 元素拖拽结束时触发 | 拖拽收尾 |
| drop | 拖拽元素释放到目标元素时触发 | 拖拽放置逻辑 |
🔑 关键区别
mouseenter/mouseleave 不冒泡;
mouseover/mouseout 会冒泡(子元素触发会传递到父元素)
因此做悬浮交互时优先用 mouseenter/mouseleave。
鼠标事件对象核心属性
| 属性 | 作用 |
|---|---|
e.clientX/e.clientY | 鼠标相对于可视窗口的坐标(不含滚动条偏移) |
e.pageX/e.pageY | 鼠标相对于文档的坐标(含滚动条偏移,常用) |
e.screenX/e.screenY | 鼠标相对于电脑屏幕的坐标 |
e.offsetX/e.offsetY | 鼠标相对于触发元素的内部坐标(元素左上角为 0) |
| e.button | 按下的鼠标按键:0 = 左键,1 = 中键,2 = 右键(mousedown/mouseup 有效) |
e.ctrlKey/e.shiftKey/e.altKey | 按下按键时是否按住 Ctrl/Shift/Alt 键(组合操作) |
| e.target | 触发事件的原始元素(事件冒泡时不变) |
| e.currentTarget | 绑定事件的当前元素(事件冒泡时为当前处理元素) |
| e.preventDefault() | 阻止默认行为(如右键菜单、链接跳转) |
| e.stopPropagation() | 阻止事件冒泡(如子元素点击不触发父元素事件) |
常见示例
获取鼠标位置
<template>
<div id="box" style="width: 300px; height: 200px; border: 1px solid #000;"></div>
<p id="pos"></p>
</template>
<script>
const box = document.getElementById('box');
const pos = document.getElementById('pos');
box.addEventListener('mousemove', (e) => {
pos.innerHTML = `
相对于文档:${e.pageX}, ${e.pageY}<br>
相对于元素:${e.offsetX}, ${e.offsetY}<br>
相对于窗口:${e.clientX}, ${e.clientY}
`;
});
</script>自定义右键菜单
<template>
<div id="customMenu" style="display: none; position: absolute; width: 120px; background: #fff; border: 1px solid #ccc; padding: 5px;">
<div>复制</div>
<div>粘贴</div>
<div>删除</div>
</div>
</template>
<script>
const menu = document.getElementById('customMenu');
// 禁用默认右键菜单
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
// 定位自定义菜单到鼠标位置
menu.style.left = `${e.pageX}px`;
menu.style.top = `${e.pageY}px`;
menu.style.display = 'block';
});
// 点击空白处关闭菜单
document.addEventListener('click', () => {
menu.style.display = 'none';
});
</script>鼠标拖拽元素
核心
mousedown 记录初始位置 → mousemove 计算偏移 → mouseup 停止监听
<template>
<div id="dragBox" style="width: 100px; height: 100px; background: red; position: absolute; cursor: move;"></div>
</template>
<script>
const dragBox = document.getElementById('dragBox');
let isDragging = false;
let startX, startY;
// 按下鼠标:开始拖拽
dragBox.addEventListener('mousedown', (e) => {
isDragging = true;
// 记录鼠标相对于元素的初始位置
startX = e.offsetX;
startY = e.offsetY;
dragBox.style.opacity = '0.8'; // 视觉反馈
});
// 移动鼠标:更新位置(绑定到document,避免鼠标移出元素中断)
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
// 计算元素新位置:鼠标文档坐标 - 初始偏移
const x = e.pageX - startX;
const y = e.pageY - startY;
dragBox.style.left = `${x}px`;
dragBox.style.top = `${y}px`;
});
// 松开鼠标:结束拖拽
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
dragBox.style.opacity = '1';
}
});
</script>监听鼠标滚轮方向
/* 鼠标滚轮事件 */
window.onwheel = (e) => {
if(e.wheelDeltaY > 0){
console.log("往上滚动");
} else {
console.log("往下滚动");
}
}
--------- 或 ---------
document.addEventListener('wheel', (e) => {
// e.deltaY > 0 向下滚动,< 0 向上滚动
if (e.deltaY > 0) {
console.log('滚轮向下');
} else {
console.log('滚轮向上');
}
// 阻止默认滚动(如页面不跟随滚轮滚动)
// e.preventDefault();
});区分左键 / 右键 / 中键点击
document.addEventListener('mousedown', (e) => {
switch(e.button) {
case 0:
console.log('左键按下');
break;
case 1:
console.log('中键按下(滚轮点击)');
break;
case 2:
console.log('右键按下');
break;
}
});注意事项
事件冒泡
提示
click、mousedown 等事件会冒泡到父元素,如需阻止可调用 e.stopPropagation()。
// 示例:子元素点击不触发父元素事件
const parent = document.getElementById('parent');
const child = document.getElementById('child');
parent.addEventListener('click', () => console.log('父元素点击'));
child.addEventListener('click', (e) => {
e.stopPropagation(); // 阻止冒泡
console.log('子元素点击');
});拖拽事件的兼容性
提示
原生拖拽(drag/drop)需给元素设置 draggable="true",且 drop 事件触发前需阻止 dragover 的默认行为:
const dropTarget = document.getElementById('dropTarget');
dropTarget.addEventListener('dragover', (e) => {
e.preventDefault(); // 必须阻止默认行为,否则drop不触发
});
dropTarget.addEventListener('drop', (e) => {
console.log('元素拖入目标');
});鼠标位置的兼容性
提示
pageX/pageY 在 IE 低版本中需兼容(可通过 clientX + document.documentElement.scrollLeft 计算)。
let timer = null;
document.addEventListener('mousemove', (e) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
// 执行复杂逻辑(如更新DOM)
console.log('鼠标位置:', e.pageX, e.pageY);
}, 16); // 约60帧/秒
});性能优化
提示
mousemove 触发频率极高,如需复杂逻辑,可通过「节流」减少触发次数
let timer = null;
document.addEventListener('mousemove', (e) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
// 执行复杂逻辑(如更新DOM)
console.log('鼠标位置:', e.pageX, e.pageY);
}, 16); // 约60帧/秒
});键盘
// 方式1:addEventListener(推荐,支持多事件绑定)
document.addEventListener('keydown', handleKeyDown);
document.addEventListener('keyup', handleKeyUp);
// 方式2:直接赋值(仅能绑定一个事件)
// document.onkeydown = handleKeyDown;
// 事件处理函数
function handleKeyDown(e) {
console.log('按键按下:', {
key: e.key, // 按键名称(如 'a'、'Enter'、'ArrowUp')
code: e.code, // 按键编码(如 'KeyA'、'Enter'、'ArrowUp')
keyCode: e.keyCode,// 按键ASCII码(已废弃,如 65 对应 A,13 对应 Enter)
altKey: e.altKey, // 是否按住 Alt
ctrlKey: e.ctrlKey,// 是否按住 Ctrl
shiftKey: e.shiftKey,// 是否按住 Shift
metaKey: e.metaKey // 是否按住 Windows/Command 键
});
// 阻止默认行为(如禁用回车提交表单、禁用方向键滚动)
// e.preventDefault();
}
function handleKeyUp(e) {
console.log('按键松开:', e.key);
}
// 移除事件监听(需保留函数引用)
// document.removeEventListener('keydown', handleKeyDown);表单
监听滚动条移动事件 ---> scroll
获取焦点 ---> focus
失去焦点 ---> blur
监听表单值发生变化 ---> change