Web API 总结
约 983 字大约 3 分钟
Web API前端
2024-08-13
DOM API
元素选择
// 单个元素
document.getElementById('id');
document.querySelector('.class');
document.querySelector('div > p');
// 多个元素
document.querySelectorAll('p'); // 返回 NodeList
Array.from(document.querySelectorAll('p')).forEach(...);
// 遍历
element.children; // 子元素
element.parentNode; // 父元素
element.nextSibling; // 下一个兄弟节点
element.firstChild; // 第一个子节点DOM 操作
// 创建
const div = document.createElement('div');
const text = document.createTextNode('Hello');
// 添加
parent.appendChild(div);
parent.insertBefore(newNode, referenceNode);
parent.insertAdjacentHTML('beforeend', '<span></span>');
// 删除
parent.removeChild(child);
element.remove();
// 克隆
element.cloneNode(true); // 深克隆
element.cloneNode(false); // 浅克隆
// 属性
element.setAttribute('data-id', '1');
element.getAttribute('data-id');
element.removeAttribute('data-id');
element.classList.add('active');
element.classList.remove('active');
element.classList.toggle('active');事件 API
// 绑定事件
element.addEventListener('click', handler, false);
// false: 冒泡阶段 | true: 捕获阶段
// 移除事件
element.removeEventListener('click', handler);
// 事件对象
element.addEventListener('click', (e) => {
e.preventDefault(); // 阻止默认行为
e.stopPropagation(); // 阻止冒泡
e.stopImmediatePropagation(); // 阻止后续事件
console.log(e.target); // 事件目标
console.log(e.currentTarget); // 当前绑定元素
console.log(e.type); // 事件类型
});
// 事件委托
parent.addEventListener('click', (e) => {
if (e.target.matches('.item')) {
// 处理点击
}
});
// 自定义事件
const event = new CustomEvent('my-event', { detail: { data: 1 } });
element.dispatchEvent(event);常见事件类型
| 类型 | 事件 |
|---|---|
| 鼠标 | click, dblclick, mouseenter, mouseleave, mousemove, mousedown, mouseup |
| 键盘 | keydown, keyup, keypress |
| 表单 | submit, reset, change, input, focus, blur |
| 资源 | load, error, abort |
| 滚动 | scroll, wheel |
| 触摸 | touchstart, touchmove, touchend |
Fetch API
// GET
fetch('/api/users')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
// POST
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', age: 30 }),
});
// 错误处理
fetch('/api/users')
.then(res => {
if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
return res.json();
})
.catch(err => console.error(err));
// 使用 async/await
async function getUsers() {
try {
const res = await fetch('/api/users');
if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
return await res.json();
} catch (err) {
console.error(err);
}
}Storage API
// localStorage
localStorage.setItem('key', 'value');
localStorage.getItem('key');
localStorage.removeItem('key');
localStorage.clear();
// sessionStorage
sessionStorage.setItem('key', 'value');
sessionStorage.getItem('key');
// 存储对象
localStorage.setItem('user', JSON.stringify({ name: 'John' }));
const user = JSON.parse(localStorage.getItem('user'));
// 事件监听 (仅支持 window)
window.addEventListener('storage', (e) => {
console.log(e.key, e.oldValue, e.newValue);
});History API
// 导航
history.pushState({ page: 1 }, 'Title', '/page1');
history.replaceState({ page: 2 }, 'Title', '/page2');
history.back();
history.forward();
history.go(-1);
// 监听 popstate
window.addEventListener('popstate', (e) => {
console.log('State:', e.state);
console.log('URL:', location.href);
});
// SPA 路由配合
window.addEventListener('popstate', () => {
router.match(location.pathname);
});Canvas API
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 绑定设备像素比
const dpr = window.devicePixelRatio || 1;
canvas.width = canvas.width * dpr;
canvas.height = canvas.height * dpr;
ctx.scale(dpr, dpr);
// 绘制矩形
ctx.fillStyle = '#ff0000';
ctx.fillRect(0, 0, 100, 100);
// 绘制路径
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100, 100);
ctx.stroke();
// 绘制文字
ctx.font = '16px Arial';
ctx.fillText('Hello', 10, 50);
// 绘制图片
const img = new Image();
img.onload = () => ctx.drawImage(img, 0, 0);
img.src = 'image.png';
// 动画
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新绘制
requestAnimationFrame(animate);
}WebSocket
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => {
console.log('Connected');
ws.send('Hello Server');
};
ws.onmessage = (event) => {
console.log('Received:', event.data);
};
ws.onerror = (error) => {
console.error('Error:', error);
};
ws.onclose = () => {
console.log('Disconnected');
};
// 关闭连接
ws.close();Intersection Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
} else {
entry.target.classList.remove('visible');
}
});
}, {
root: null, // 视口
rootMargin: '0px', // 扩展 root 区域
threshold: 0.1 // 10% 可见时触发
});
observer.observe(document.querySelector('.target'));
observer.disconnect(); // 停止观察Mutation Observer
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
console.log(mutation.type); // 'childList', 'attributes', 'characterData'
console.log(mutation.target); // 变化的节点
console.log(mutation.addedNodes); // 新增的节点
console.log(mutation.removedNodes); // 删除的节点
});
});
observer.observe(element, {
childList: true, // 观察子节点变化
attributes: true, // 观察属性变化
characterData: true, // 观察文本变化
subtree: true, // 观察所有后代
attributeOldValue: true,
characterDataOldValue: true,
});
observer.disconnect();Resize Observer
const observer = new ResizeObserver((entries) => {
entries.forEach(entry => {
console.log('Size:', entry.contentRect);
console.log('Device pixel ratio:', entry.devicePixelRatio);
});
});
observer.observe(element);
observer.disconnect();Performance API
// 测量性能
const start = performance.now();
// 执行操作
const duration = performance.now() - start;
// Performance Observer
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach(entry => {
console.log(entry.name, entry.duration);
});
});
observer.observe({ entryTypes: ['measure', 'navigation'] });
// 获取导航时间
performance.getEntriesByType('navigation').forEach(nav => {
console.log('DNS:', nav.domainLookupEnd - nav.domainLookupStart);
console.log('TTFB:', nav.responseStart - nav.requestStart);
console.log('DOM Load:', nav.domContentLoadedEventEnd - nav.fetchStart);
});常用工具函数
// 防抖
function debounce(fn, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流
function throttle(fn, delay) {
let canRun = true;
return function(...args) {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn.apply(this, args);
canRun = true;
}, delay);
};
}
// 深拷贝
function deepClone(obj, hash = new WeakMap()) {
if (Object(obj) !== obj) return obj;
if (obj instanceof Set) return new Set(obj);
if (hash.has(obj)) return hash.get(obj);
hash.set(obj, true);
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
const clone = new obj.constructor();
for (const key of Reflect.ownKeys(obj)) {
clone[key] = deepClone(obj[key], hash);
}
return clone;
}
// 类型判断
function typeOf(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}