1. 事件委托
- 原理:将事件绑定到父元素,利用事件冒泡机制,让父元素统一处理子元素的事件。这样可以减少事件绑定的数量,提高性能。
- 示例代码:
<ul id="parent">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
const parent = document.getElementById('parent');
parent.addEventListener('click', function(event) {
if (event.target.tagName === 'LI') {
console.log('Clicked on:', event.target.textContent);
}
});
</script>
2. 文档片段(DocumentFragment)
- 原理:文档片段是一个轻量级的 DOM 容器,它存在于内存中,不在文档树里。对文档片段进行操作不会引起页面回流和重绘,操作完成后再将文档片段添加到文档树中,这样只会触发一次回流和重绘。
- 示例代码:
<div id="container"></div>
<script>
const container = document.getElementById('container');
const fragment = document.createDocumentFragment();
for (let i = 0; i < 10; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
container.appendChild(fragment);
</script>
3. 虚拟 DOM
- 原理:虚拟 DOM 是一个用 JavaScript 对象来描述真实 DOM 的数据结构。当数据发生变化时,会生成新的虚拟 DOM,然后与旧的虚拟 DOM 进行对比(diff 算法),计算出最小的 DOM 变化,最后将这些变化应用到真实 DOM 上,从而减少直接操作真实 DOM 的性能开销。
- 示例代码(使用 React 来简单示意,React 内部使用虚拟 DOM):
import React, { useState } from'react';
function App() {
const [items, setItems] = useState([]);
const addItem = () => {
setItems([...items, `New Item ${items.length + 1}`]);
};
const removeItem = () => {
if (items.length > 0) {
setItems(items.slice(0, -1));
}
};
return (
<div>
<button onClick={addItem}>Add Item</button>
<button onClick={removeItem}>Remove Item</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
export default App;
4. 批量操作
- 原理:将多次 DOM 操作合并为一次,减少回流和重绘次数。
- 示例代码:
<div id="element1"></div>
<div id="element2"></div>
<script>
const element1 = document.getElementById('element1');
const element2 = document.getElementById('element2');
// 开始批量操作
element1.style.display = 'none';
element2.style.color ='red';
// 批量操作结束,此时只触发一次回流和重绘
</script>
5. 节流与防抖
- 原理:
- 节流:规定在一个单位时间内,只能触发一次函数。如果在这个单位时间内触发多次函数,只有一次生效。
- 防抖:在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时。
- 示例代码(节流):
<button id="throttleButton">Click Me</button>
<script>
function throttle(func, delay) {
let timer = null;
return function() {
if (!timer) {
func.apply(this, arguments);
timer = setTimeout(() => {
timer = null;
}, delay);
}
};
}
const throttleButton = document.getElementById('throttleButton');
const handleClick = function() {
console.log('Button clicked');
};
throttleButton.addEventListener('click', throttle(handleClick, 1000));
</script>
<input type="text" id="searchInput" placeholder="Search...">
<script>
function debounce(func, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, arguments);
}, delay);
};
}
const searchInput = document.getElementById('searchInput');
const handleSearch = function() {
console.log('Searching:', searchInput.value);
};
searchInput.addEventListener('input', debounce(handleSearch, 500));
</script>