跟着 MDN 学 HTML day_47:深入理解 Document 接口
📑 目录
| 左列章节 | 右列章节 |
|---|---|
| [一、访问文档基本信息的属性](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) | [二、快速获取 DOM 元素的便捷属性](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) |
| [三、使用选择器精确查找元素](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) | [四、动态创建和修改 DOM 节点](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) |
| [五、操作文档结构和移动节点](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) | [六、文档加载状态与可见性](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) |
| [七、全屏操作与指针锁定](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) | [八、处理文档中的 Cookie](#左列章节 右列章节 一、访问文档基本信息的属性 二、快速获取 DOM 元素的便捷属性 三、使用选择器精确查找元素 四、动态创建和修改 DOM 节点 五、操作文档结构和移动节点 六、文档加载状态与可见性 七、全屏操作与指针锁定 八、处理文档中的 Cookie) |
一、访问文档基本信息的属性
在日常开发中,我们经常需要获取当前文档的基本信息,例如文档的标题、URL、字符集等。Document 接口提供了丰富的只读属性来满足这些需求。
代码示例:获取文档基本信息
javascript
// 获取文档标题(可读可写)
console.log('文档标题:', document.title);
// 获取文档的完整 URL
console.log('文档 URL:', document.URL);
// 获取文档的字符集
console.log('字符集:', document.characterSet);
// 获取文档的内容类型
console.log('内容类型:', document.contentType);
// 获取文档最后修改时间
console.log('最后修改时间:', document.lastModified);
// 获取引用来源页面
console.log('来源页面:', document.referrer);
核心结论 :
document.title不仅可以读取,还可以通过赋值动态修改 浏览器标签页上显示的标题。document.URL返回完整的 URL 字符串,而document.referrer则告诉你用户是从哪个页面跳转过来的,这在统计分析中非常有用。document.lastModified返回页面的最后修改时间字符串。
二、快速获取 DOM 元素的便捷属性
Document 接口提供了一些便捷属性,让我们无需使用选择器就能直接访问文档中的特定元素,这在处理页面结构时极为高效。
代码示例:便捷属性的使用
javascript
// 直接获取 <body> 元素
console.log('body 元素:', document.body);
// 直接获取 <head> 元素
console.log('head 元素:', document.head);
// 直接获取 <html> 根元素
console.log('文档根元素:', document.documentElement);
// 直接获取所有链接的集合(HTMLCollection)
const links = document.links;
console.log('链接数量:', links.length);
for (let i = 0; i < links.length; i++) {
console.log('链接 ' + i + ':', links[i].href);
}
// 直接获取所有表单的集合(HTMLCollection)
console.log('表单数量:', document.forms.length);
// 通过 name 属性直接获取表单
console.log('登录表单:', document.loginForm);
核心结论 :
document.body和document.head是最常用的便捷属性。document.links和document.forms返回的是动态的 HTMLCollection ,当文档中的元素发生增删时,这些集合会自动更新。具有name属性的表单和图片元素 会被直接暴露为document对象的属性。
⚠️ 【重点 / 面试考点 / 易错点】
| 便捷属性 | 返回类型 | 说明 |
|---|---|---|
document.body |
HTMLBodyElement |
页面 body 元素,DOM 就绪前可能为 null |
document.head |
HTMLHeadElement |
页面 head 元素 |
document.documentElement |
HTMLHtmlElement |
根 html 元素 |
document.forms |
HTMLCollection |
所有 form 元素,即时更新 |
document.links |
HTMLCollection |
所有带 href 的 a 和 area 元素 |
document.images |
HTMLCollection |
所有 img 元素 |
document.scripts |
HTMLCollection |
所有 script 元素 |
document.body在DOMContentLoaded之前访问可能为nulldocument.loginForm这种通过name直接访问的方式是遗留特性,不推荐在新代码中使用
三、使用选择器精确查找元素
当需要根据复杂条件查找元素时,选择器方法 是最强大的工具。Document 接口提供了 querySelector 和 querySelectorAll 这两个核心方法。
代码示例:querySelector 与 querySelectorAll
javascript
// querySelector 返回匹配的第一个元素
const firstFruit = document.querySelector('.fruit');
console.log('第一个水果:', firstFruit.textContent);
// querySelectorAll 返回所有匹配的元素(静态 NodeList)
const allFruits = document.querySelectorAll('.fruit');
allFruits.forEach(function(fruit, index) {
console.log(index + ':', fruit.textContent);
});
// 使用复杂的选择器
const highlightFruit = document.querySelector('.fruit.highlight');
console.log('高亮水果:', highlightFruit.textContent);
querySelector 和 querySelectorAll 支持完整的 CSS 选择器语法,使得元素查找变得极其灵活。相比之下,getElementById、getElementsByClassName 和 getElementsByTagName 是更早期的方法。
代码示例:传统查找方法
javascript
// 通过 ID 获取元素
const fruitList = document.getElementById('fruitList');
console.log('水果列表元素:', fruitList);
// 通过类名获取元素(HTMLCollection)
const fruitsByClass = document.getElementsByClassName('fruit');
console.log('通过类名获取的水果数量:', fruitsByClass.length);
// 通过标签名获取元素(HTMLCollection)
const allListItems = document.getElementsByTagName('li');
console.log('列表项数量:', allListItems.length);
核心结论 :
querySelectorAll返回的是静态的 NodeList ,而getElementsByClassName返回的HTMLCollection是动态的。在需要频繁操作且 DOM 可能变化时,静态集合更安全。
四、动态创建和修改 DOM 节点
Document 接口提供了丰富的工厂方法用于创建各种类型的节点,这是动态构建页面内容的基础能力。
代码示例:创建各类 DOM 节点
javascript
// 创建元素节点
const newDiv = document.createElement('div');
newDiv.className = 'card';
newDiv.style.border = '1px solid #ccc';
newDiv.style.padding = '16px';
// 创建文本节点
const textNode = document.createTextNode('这是动态创建的文本内容');
newDiv.appendChild(textNode);
// 创建注释节点
const commentNode = document.createComment('这是一个注释');
newDiv.appendChild(commentNode);
// 创建文档片段(批量插入优化)
const fragment = document.createDocumentFragment();
const header = document.createElement('h2');
header.textContent = '新闻标题';
fragment.appendChild(header);
const paragraph = document.createElement('p');
paragraph.textContent = '这是一段新闻内容';
fragment.appendChild(paragraph);
// 一次性插入文档片段,只触发一次重排
document.body.appendChild(fragment);
代码示例:使用 append 同时添加多个节点
javascript
const span1 = document.createElement('span');
span1.textContent = '标签1 ';
const span2 = document.createElement('span');
span2.textContent = '标签2 ';
const span3 = document.createElement('span');
span3.textContent = '标签3';
// append 可同时添加多个节点和文本
contentDiv.append(span1, span2, span3, ' 这是附加的文本');
核心结论 :
createDocumentFragment创建轻量级文档片段,批量插入时只触发一次页面重排 ,性能显著优于逐个插入。append是appendChild的增强版,支持同时添加多个节点和文本。
⚠️ 【重点 / 面试考点】
createElement是最常用的节点创建方法,根据标签名创建新元素createDocumentFragment用于批量插入优化,只触发一次重排重绘createTextNode创建文本节点,避免 innerHTML 的 XSS 风险appendvsappendChild:append支持多参数(节点+文本),appendChild只接受单个节点且返回被添加的节点- 文档片段被插入后,其所有子节点会转移到目标容器中,片段本身变为空
五、操作文档结构和移动节点
在实际开发中,经常需要重新组织文档结构。Document 接口提供了多种方法来完成这些操作。
DOM 节点的一个重要特性是它们在文档树中的唯一性 。当你使用 appendChild 或 insertBefore 操作一个已存在的节点时,浏览器会自动将其从原位置移除并插入到新位置,无需手动删除。
代码示例:移动现有节点
javascript
const sourceDiv = document.getElementById('source');
const destDiv = document.getElementById('destination');
const targetParagraph = document.getElementById('moveTarget');
// appendChild 移动已存在节点:自动从原位置移除
destDiv.appendChild(targetParagraph);
console.log('源容器剩余子元素:', sourceDiv.children.length);
console.log('目标容器子元素:', destDiv.children.length);
代码示例:在指定位置插入节点
javascript
// 使用 insertBefore 在指定位置插入
const newElement = document.createElement('div');
newElement.textContent = '新插入的元素';
destDiv.insertBefore(newElement, destDiv.firstChild);
// 使用 prepend 在容器开头插入
const prependText = document.createElement('span');
prependText.textContent = '[前置内容] ';
destDiv.prepend(prependText);
代码示例:替换所有子节点
javascript
// 使用 replaceChildren 替换所有子元素
const freshContent = document.createElement('p');
freshContent.textContent = '全新的替换内容';
destDiv.replaceChildren(freshContent);
六、文档加载状态与可见性
页面从开始加载到完全可交互,会经历不同的状态。了解这些状态对于优化用户体验和实现加载指示器非常重要。
代码示例:监听 readyState 变化
javascript
// readyState 有三个值:
// "loading" - 文档正在加载
// "interactive" - DOM 已解析完毕
// "complete" - 页面及所有资源加载完成
document.addEventListener('readystatechange', function() {
console.log('readyState 变化为:', document.readyState);
if (document.readyState === 'interactive') {
console.log('DOM 已解析完毕,正在加载资源...');
} else if (document.readyState === 'complete') {
console.log('页面完全加载完成!');
}
});
代码示例:DOMContentLoaded 事件
javascript
// DOMContentLoaded 在 DOM 解析完成后触发,无需等待图片等资源
document.addEventListener('DOMContentLoaded', function() {
console.log('DOMContentLoaded 事件触发');
console.log('此时可以安全地操作 DOM 元素');
});
代码示例:监听页面可见性变化
javascript
// visibilitychange 在用户切换标签页或最小化窗口时触发
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
console.log('页面被隐藏');
document.title = '页面已隐藏';
// 可以在此处暂停动画、视频播放
} else {
console.log('页面可见');
document.title = 'Document 接口示例页面';
// 恢复动画、视频播放
}
});
核心结论 :
document.hidden为true时表示页面不可见(用户切换了标签页或最小化了窗口)。visibilitychange事件可以用来暂停或恢复页面中的动画和视频播放,节省系统资源。
七、全屏操作与指针锁定
现代浏览器支持丰富的交互模式,包括全屏显示 和指针锁定功能,这些能力在游戏和多媒体应用中尤为重要。
代码示例:全屏 API 的使用
javascript
const element = document.getElementById('fullscreenTarget');
// 进入全屏
element.requestFullscreen();
// 退出全屏
document.exitFullscreen();
// 监听全屏变化
document.addEventListener('fullscreenchange', function() {
if (document.fullscreenElement) {
console.log('进入全屏,当前元素:', document.fullscreenElement);
} else {
console.log('退出全屏');
}
});
// 检查全屏功能是否可用
console.log('全屏支持:', document.fullscreenEnabled);
代码示例:指针锁定 API
javascript
const gameArea = document.getElementById('gameArea');
// 请求指针锁定
gameArea.requestPointerLock();
// 监听锁定状态变化
document.addEventListener('pointerlockchange', function() {
if (document.pointerLockElement === gameArea) {
console.log('指针已锁定,可以获取原始鼠标移动数据');
} else {
console.log('指针已解锁');
}
});
// 监听锁定失败
document.addEventListener('pointerlockerror', function() {
console.error('指针锁定失败');
});
核心结论 :全屏 API 和指针锁定 API 都需要用户主动触发 才能启用(如点击按钮),这是浏览器的安全策略。
document.fullscreenElement返回当前全屏元素,null表示没有元素处于全屏。指针锁定隐藏鼠标并获取原始移动数据,常用于第一人称游戏场景。
⚠️ 【重点 / 面试考点】
| API | 进入方法 | 退出方法 | 查询当前状态 | 事件 |
|---|---|---|---|---|
| 全屏 | element.requestFullscreen() |
document.exitFullscreen() |
document.fullscreenElement |
fullscreenchange |
| 指针锁定 | element.requestPointerLock() |
document.exitPointerLock() |
document.pointerLockElement |
pointerlockchange |
- 两者都必须由用户手势触发(点击、按键等),不能自动调用
fullscreenchange和pointerlockchange事件都绑定在document上- 按 Esc 键 可以退出全屏和指针锁定状态
document.fullscreenEnabled可检测浏览器是否支持全屏
八、处理文档中的 Cookie
Cookie 是 Web 开发中用于客户端存储少量数据的重要机制,Document 接口提供了对 Cookie 的直接读写能力。
document.cookie 的工作方式比较特殊。读取时返回当前页面可访问的所有 Cookie(分号分隔的键值对字符串)。设置时,赋值不会覆盖现有 Cookie,而是追加或更新指定的 Cookie。
代码示例:Cookie 的读写与删除
javascript
// 设置 Cookie(不会覆盖已有 Cookie)
function setCookie(name, value, days) {
let expires = '';
if (days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = '; expires=' + date.toUTCString();
}
document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/';
}
// 读取所有 Cookie 并解析为对象
function getAllCookies() {
const cookies = document.cookie.split('; ');
const cookieObj = {};
cookies.forEach(function(cookie) {
if (cookie) {
const parts = cookie.split('=');
cookieObj[parts[0]] = decodeURIComponent(parts[1]);
}
});
return cookieObj;
}
// 删除 Cookie(将过期时间设为过去)
function deleteCookie(name) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/';
}
代码示例:Cookie 操作的实际使用
javascript
// 设置 Cookie
setCookie('username', '张三', 7);
setCookie('theme', 'dark', 7);
// 读取 Cookie
const cookies = getAllCookies();
console.log('用户名:', cookies.username);
console.log('主题:', cookies.theme);
// 删除 Cookie
deleteCookie('theme');
核心结论 :删除 Cookie 的本质是将其过期时间设置为过去的时间 ,让浏览器自动清除。设置 Cookie 时必须包含
path=/才能确保在整个站点可访问。
九、Document 接口核心方法速查
| 方法 | 功能 | 返回值 |
|---|---|---|
document.getElementById(id) |
根据 ID 获取元素 | Element / null |
document.querySelector(selector) |
获取首个匹配元素 | Element / null |
document.querySelectorAll(selector) |
获取所有匹配元素 | 静态 NodeList |
document.getElementsByTagName(tag) |
根据标签名获取 | 动态 HTMLCollection |
document.getElementsByClassName(cls) |
根据类名获取 | 动态 HTMLCollection |
document.createElement(tagName) |
创建元素节点 | Element |
document.createTextNode(text) |
创建文本节点 | Text |
document.createComment(data) |
创建注释节点 | Comment |
document.createDocumentFragment() |
创建文档片段 | DocumentFragment |
Document 接口继承关系
EventTarget
Node
Document
HTMLDocument
document 实例
XMLDocument
✅ 文档总结
Document是 DOM 树的入口节点,代表浏览器中加载的整个 Web 页面- 便捷属性如
document.body、document.head、document.forms、document.links可直接快速访问常用元素 querySelector/querySelectorAll支持完整 CSS 选择器语法,返回静态 NodeList ;getElementsBy*返回动态 HTMLCollection- 节点创建方法:
createElement、createTextNode、createComment、createDocumentFragment(批量插入优化) appendChild操作已存在节点时会自动从原位置移动,无需手动删除document.readyState反映文档加载阶段(loading→interactive→complete),DOMContentLoaded在 DOM 就绪时触发visibilitychange事件 +document.hidden用于页面可见性检测,可暂停动画和视频节省资源- 全屏 API 和指针锁定 API 都必须由用户手势触发,按 Esc 键可退出
document.cookie的特殊机制:读取返回全部 Cookie,设置只更新单个,删除需将过期时间设为过
完整实践示例
javascript
// 综合应用:页面加载完成后动态构建内容并管理状态
document.addEventListener('DOMContentLoaded', function() {
// 1. 获取容器
const container = document.getElementById('app');
// 2. 使用文档片段批量创建内容(性能优化)
const fragment = document.createDocumentFragment();
const header = document.createElement('header');
header.innerHTML = '<h1>Document API 演示</h1>';
fragment.appendChild(header);
const main = document.createElement('main');
// 3. 动态创建多个卡片元素
const items = ['基本信息', '元素查找', '节点操作', '事件处理'];
items.forEach(function(text, index) {
const card = document.createElement('div');
card.className = 'card';
card.dataset.index = index;
card.textContent = text;
main.appendChild(card);
});
fragment.appendChild(main);
// 一次性插入,只触发一次重排
container.appendChild(fragment);
// 4. 使用 querySelectorAll 获取静态快照并绑定事件
const cards = document.querySelectorAll('.card');
cards.forEach(function(card) {
card.addEventListener('click', function() {
console.log('点击了:', this.textContent);
document.title = '当前选中: ' + this.textContent;
});
});
// 5. 页面可见性检测
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
console.log('页面不可见,暂停定时器');
} else {
console.log('页面可见,恢复定时器');
}
});
// 6. 输出文档基本信息
console.log('文档标题:', document.title);
console.log('字符集:', document.characterSet);
console.log('内容类型:', document.contentType);
});
通过动手实践,可以更直观地体会到 Document 接口作为 DOM 入口节点的核心地位,熟练掌握这些 API 能够显著提升前端开发效率和代码质量。
想要解锁更多HTML 核心标签实战、前端零基础入门干货、开发避坑全指南吗?
持续关注,后续将更新CSS 布局实战、JavaScript 交互基础、全站导航开发等硬核内容,带你从新手快速进阶,轻松搞定前端开发!