文章目录
一、引言:Web开发中的两大核心模型
在现代Web开发中,BOM(Browser Object Model,浏览器对象模型)和DOM(Document Object Model,文档对象模型)是JavaScript与浏览器交互的两大核心接口。它们虽然名称相似,但功能和使用场景却大不相同。本文将深入剖析这两者的区别与联系,并通过丰富的代码示例和流程图帮助开发者全面掌握它们的使用方法。
二、BOM(浏览器对象模型)详解
2.1 BOM概述
BOM(Browser Object Model)是指浏览器提供的对象模型,用于访问和操作浏览器窗口本身。BOM没有统一的标准(W3C标准),但大多数浏览器都实现了相似的功能。
2.2 BOM核心对象及方法
1. window对象
window对象是BOM的顶层对象,代表浏览器窗口。
// 获取窗口尺寸
const windowWidth = window.innerWidth;
const windowHeight = window.innerHeight;
// 打开新窗口
const newWindow = window.open('https://example.com', '_blank', 'width=600,height=400');
// 定时器
const timer = setTimeout(() => {
console.log('2秒后执行');
}, 2000);
// 清除定时器
clearTimeout(timer);
2. location对象
提供当前窗口加载文档的信息和控制导航功能。
// 获取当前URL信息
console.log(location.href); // 完整URL
console.log(location.protocol); // 协议(http:或https:)
console.log(location.host); // 主机名和端口
console.log(location.pathname); // 路径部分
// 页面跳转
location.assign('https://newpage.com');
location.replace('https://newpage.com'); // 不会在历史记录中留下记录
location.reload(); // 重新加载当前页面
3. navigator对象
提供浏览器和操作系统相关信息。
// 浏览器信息
console.log(navigator.userAgent); // 用户代理字符串
console.log(navigator.platform); // 操作系统平台
console.log(navigator.language); // 浏览器语言
// 功能检测
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(position => {
console.log(position.coords.latitude, position.coords.longitude);
});
}
4. screen对象
提供用户屏幕的信息。
console.log(screen.width); // 屏幕宽度
console.log(screen.height); // 屏幕高度
console.log(screen.availWidth); // 可用宽度
console.log(screen.colorDepth); // 颜色深度
5. history对象
提供浏览器历史记录的操作。
// 历史记录导航
history.back(); // 等同于点击后退按钮
history.forward(); // 等同于点击前进按钮
history.go(-2); // 后退两页
// 添加历史记录
history.pushState({page: 1}, "title 1", "?page=1");
history.replaceState({page: 2}, "title 2", "?page=2");
三、DOM(文档对象模型)详解
3.1 DOM概述
DOM(Document Object Model)是将HTML或XML文档表示为树形结构的API,允许程序和脚本动态访问和更新文档的内容、结构和样式。
3.2 DOM核心概念
1. 节点类型
节点类型 | nodeType值 | 描述 |
---|---|---|
Element | 1 | 元素节点 |
Attr | 2 | 属性节点 |
Text | 3 | 文本节点 |
Comment | 8 | 注释节点 |
Document | 9 | 文档节点 |
DocumentType | 10 | 文档类型节点 |
2. DOM查询方法
// 获取元素
const element = document.getElementById('myId');
const elements = document.getElementsByClassName('myClass');
const tags = document.getElementsByTagName('div');
// 现代选择器
const el = document.querySelector('#container .item');
const allEls = document.querySelectorAll('div.highlight');
// 遍历DOM
const parent = el.parentNode;
const children = el.childNodes;
const firstChild = el.firstChild;
const lastChild = el.lastChild;
const nextSibling = el.nextSibling;
const prevSibling = el.previousSibling;
3. DOM操作
// 创建节点
const newDiv = document.createElement('div');
const newText = document.createTextNode('Hello World');
// 添加节点
el.appendChild(newDiv);
el.insertBefore(newDiv, referenceNode);
// 删除节点
el.removeChild(childNode);
// 替换节点
el.replaceChild(newNode, oldNode);
// 克隆节点
const clonedNode = el.cloneNode(true); // 深度克隆
4. 属性和样式操作
// 属性操作
el.setAttribute('data-id', '123');
const value = el.getAttribute('data-id');
el.removeAttribute('data-id');
// class操作
el.classList.add('new-class');
el.classList.remove('old-class');
el.classList.toggle('active');
// 样式操作
el.style.color = 'red';
el.style.backgroundColor = '#fff';
5. 事件处理
// 添加事件监听
el.addEventListener('click', function(event) {
console.log('Clicked!', event.target);
});
// 移除事件监听
const handler = function() { console.log('Only once'); };
el.addEventListener('click', handler, {once: true});
el.removeEventListener('click', handler);
// 事件委托
document.getElementById('list').addEventListener('click', function(e) {
if(e.target.tagName === 'LI') {
console.log('List item clicked:', e.target.textContent);
}
});
四、BOM与DOM的关系与区别
4.1 关系图
图3:BOM与DOM关系图
4.2 主要区别
特性 | BOM | DOM |
---|---|---|
标准 | 无官方标准 | W3C标准 |
作用对象 | 浏览器窗口 | 文档内容 |
核心对象 | window, location, navigator等 | document, element, node等 |
主要用途 | 控制浏览器行为 | 操作页面内容 |
兼容性 | 浏览器实现差异大 | 各浏览器实现较一致 |
五、高级应用与性能优化
5.1 DOM操作性能优化
// 1. 批量修改使用文档片段
const fragment = document.createDocumentFragment();
for(let i = 0; i < 100; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
// 2. 读写分离(减少重排)
// 不好的做法
for(let i = 0; i < 100; i++) {
el.style.width = (el.offsetWidth + 10) + 'px'; // 读写交替
}
// 好的做法
let width = el.offsetWidth; // 先读
for(let i = 0; i < 100; i++) {
width += 10;
}
el.style.width = width + 'px'; // 最后写
// 3. 使用requestAnimationFrame优化动画
function animate() {
// 动画逻辑
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
5.2 现代DOM API
// Intersection Observer API - 检测元素可见性
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
console.log('Element is visible');
}
});
});
observer.observe(document.querySelector('.target'));
// Mutation Observer API - 监听DOM变化
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
console.log('DOM changed:', mutation.type);
});
});
mutationObserver.observe(document.getElementById('app'), {
childList: true,
attributes: true,
subtree: true
});
// Resize Observer API - 监听元素尺寸变化
const resizeObserver = new ResizeObserver(entries => {
for(let entry of entries) {
console.log('New dimensions:', entry.contentRect);
}
});
resizeObserver.observe(document.querySelector('.resizable'));
六、总结与最佳实践
-
BOM使用建议:
- 注意浏览器兼容性问题
- 慎用window.open等可能被浏览器拦截的方法
- 使用feature detection而不是userAgent嗅探
-
DOM操作最佳实践:
- 尽量减少直接DOM操作
- 使用事件委托处理动态内容
- 批量修改时使用文档片段
- 合理使用现代Observer API
-
安全注意事项:
- 避免使用innerHTML插入不可信内容
- 对用户输入进行适当转义
- 注意XSS攻击防范
// 安全示例:使用textContent而不是innerHTML
const userInput = '<script>maliciousCode()</script>';
el.textContent = userInput; // 安全
// el.innerHTML = userInput; // 危险!
通过本文的详细讲解,相信您已经对BOM和DOM有了全面深入的理解。在实际开发中,合理利用这两种模型的能力,可以创建出功能强大、性能优异的Web应用程序。