当前位置: 首页 > ai >正文

JavaScript 操作 DOM

目录

一、DOM 基础概念

二、获取 DOM 元素

2.1 通过 ID 获取元素

2.2 通过类名获取元素

2.3 通过标签名获取元素

2.4 通过 CSS 选择器获取元素

2.5 获取特殊元素

三、DOM 元素属性操作

3.1 获取和设置标准属性

3.2 使用 getAttribute() 和 setAttribute()

3.3 移除属性

3.4 检查属性是否存在

3.5 数据属性(data-*)

四、修改元素内容

4.1 innerHTML

4.2 textContent

4.3 outerHTML

五、操作元素样式

5.1 直接操作 style 属性

5.2 使用 classList 操作类名

5.3 获取计算样式

六、DOM 节点操作

6.1 创建节点

6.2 添加节点

6.3 插入节点

6.4 替换节点

6.5 移除节点

6.6 克隆节点

七、DOM 事件处理

7.1 事件监听器的基本用法

7.2 常用事件类型

7.3 事件对象属性和方法

7.4 事件冒泡和事件捕获

7.5 事件委托

八、DOM 遍历和查找

8.1 父节点和子节点

8.2 兄弟节点

8.3 遍历所有子节点

九、表单操作

9.1 获取表单元素

9.2 获取和设置表单值

9.3 表单提交处理

十、DOM 性能优化

10.1 减少 DOM 操作次数

10.2 避免频繁查询 DOM

10.3 使用 CSS 类批量修改样式

10.4 避免 layout thrashing(布局抖动)

十一、DOM 扩展方法

十二、总结


一、DOM 基础概念

DOM(Document Object Model,文档对象模型)是 HTML 和 XML 文档的编程接口,它将文档解析为一个由节点和对象(包含属性和方法)组成的结构集合。JavaScript 可以通过 DOM 接口来操作网页的内容、结构和样式。

  • 文档:指整个 HTML 或 XML 页面
  • 对象:表示文档中的元素、属性、文本等
  • 模型:表示这些对象之间的关系,类似树状结构

DOM 树结构示意图:

document
├── html
│   ├── head
│   │   ├── title
│   │   ├── meta
│   │   └── link
│   └── body
│       ├── h1
│       ├── p
│       └── div
└── ...

二、获取 DOM 元素

JavaScript 提供了多种方法来选择和获取 DOM 元素,以下是常用方法:

2.1 通过 ID 获取元素

// getElementById() 返回具有指定 ID 的元素
const element = document.getElementById('myId');

注意:ID 在文档中应该是唯一的,该方法返回单个元素,如果找不到则返回 null

2.2 通过类名获取元素

// getElementsByClassName() 返回具有指定类名的所有元素集合(HTMLCollection)
const elements = document.getElementsByClassName('myClass');// 转换为数组以便使用数组方法
const elementsArray = Array.from(elements);
// 或
const elementsArray = [...elements];

2.3 通过标签名获取元素

// getElementsByTagName() 返回具有指定标签名的所有元素集合(HTMLCollection)
const paragraphs = document.getElementsByTagName('p');
const divs = document.getElementsByTagName('div');

2.4 通过 CSS 选择器获取元素

// querySelector() 返回匹配指定 CSS 选择器的第一个元素
const firstParagraph = document.querySelector('p');
const element = document.querySelector('#myId .myClass');// querySelectorAll() 返回匹配指定 CSS 选择器的所有元素(NodeList)
const allParagraphs = document.querySelectorAll('p');
const elements = document.querySelectorAll('.myClass');

注意:querySelectorAll() 返回的 NodeList 是静态的,而 getElementsBy* 系列方法返回的是动态集合

2.5 获取特殊元素

// 获取 html 元素
const htmlElement = document.documentElement;// 获取 head 元素
const headElement = document.head;// 获取 body 元素
const bodyElement = document.body;// 获取所有表单元素
const forms = document.forms;// 获取所有图像元素
const images = document.images;

三、DOM 元素属性操作

3.1 获取和设置标准属性

const link = document.querySelector('a');// 获取属性值
const href = link.href;
const target = link.target;// 设置属性值
link.href = 'https://example.com';
link.target = '_blank';

3.2 使用 getAttribute() 和 setAttribute()

const element = document.querySelector('div');// 获取属性值
const id = element.getAttribute('id');
const classValue = element.getAttribute('class');// 设置属性值
element.setAttribute('id', 'newId');
element.setAttribute('class', 'newClass');
element.setAttribute('data-custom', 'value'); // 设置自定义属性

3.3 移除属性

const element = document.querySelector('div');
element.removeAttribute('class'); // 移除 class 属性

3.4 检查属性是否存在

const element = document.querySelector('div');
if (element.hasAttribute('id')) {// 元素具有 id 属性
}

3.5 数据属性(data-*)

HTML5 允许自定义数据属性,前缀为 data-

<div id="user" data-id="123" data-name="John" data-age="30"></div>
const user = document.getElementById('user');// 获取数据属性
const userId = user.dataset.id; // "123"
const userName = user.dataset.name; // "John"// 设置数据属性
user.dataset.email = "john@example.com";
user.dataset.age = "31"; // 更新已有数据属性// 移除数据属性
delete user.dataset.age;

四、修改元素内容

4.1 innerHTML

获取或设置元素的 HTML 内容,包括所有子元素:

const container = document.getElementById('container');// 获取 HTML 内容
const htmlContent = container.innerHTML;// 设置 HTML 内容(会覆盖原有内容)
container.innerHTML = '<p>新的 HTML 内容</p>';// 追加 HTML 内容
container.innerHTML += '<p>追加的内容</p>';

注意:使用 innerHTML 可能存在 XSS 安全风险,插入用户输入时要特别小心

4.2 textContent

获取或设置元素的文本内容,不包含 HTML 标签:

const paragraph = document.querySelector('p');// 获取文本内容
const text = paragraph.textContent;// 设置文本内容
paragraph.textContent = '新的文本内容';

textContent 与 innerText 的区别:

  • textContent 会获取所有元素的内容,包括 <script> 和 <style>
  • innerText 只获取可见文本,受 CSS 样式影响
  • textContent 性能更好,推荐使用

4.3 outerHTML

获取或设置包括当前元素本身的 HTML 内容:

const div = document.querySelector('div');// 获取 outerHTML
const outerHtml = div.outerHTML; // <div>...</div>// 设置 outerHTML(会替换当前元素)
div.outerHTML = '<section>新内容</section>';

五、操作元素样式

5.1 直接操作 style 属性

通过元素的 style 属性可以访问和修改内联样式:

const element = document.querySelector('div');// 设置样式
element.style.color = 'red';
element.style.backgroundColor = '#f0f0f0'; // 注意驼峰命名法
element.style.fontSize = '16px';
element.style.marginTop = '20px';// 获取样式
const color = element.style.color;
const fontSize = element.style.fontSize;

注意:CSS 属性名在 JavaScript 中使用驼峰命名法(如 backgroundColor 对应 CSS 中的 background-color)

5.2 使用 classList 操作类名

const element = document.querySelector('div');// 添加类名
element.classList.add('active');
element.classList.add('highlight', 'rounded'); // 添加多个类名// 移除类名
element.classList.remove('active');
element.classList.remove('highlight', 'rounded'); // 移除多个类名// 切换类名(存在则移除,不存在则添加)
element.classList.toggle('active');// 检查是否包含类名
if (element.classList.contains('active')) {// 元素包含 active 类
}// 替换类名
element.classList.replace('old-class', 'new-class');

5.3 获取计算样式

获取元素最终应用的所有样式(包括外部样式表、内部样式和内联样式):

const element = document.querySelector('div');
const computedStyles = window.getComputedStyle(element);// 获取计算后的样式值
const color = computedStyles.color;
const fontSize = computedStyles.fontSize;
const margin = computedStyles.margin;

六、DOM 节点操作

6.1 创建节点

// 创建元素节点
const newDiv = document.createElement('div');
const newParagraph = document.createElement('p');// 创建文本节点
const textNode = document.createTextNode('这是一段文本');// 创建注释节点
const commentNode = document.createComment('这是一段注释');

6.2 添加节点

const parent = document.getElementById('parent');
const child = document.createElement('div');
child.textContent = '新添加的元素';// .appendChild() - 添加到子节点列表的末尾
parent.appendChild(child);// .prepend() - 添加到子节点列表的开头(ES6+)
parent.prepend(child);// .before() - 添加到当前节点前面(ES6+)
parent.before(child);// .after() - 添加到当前节点后面(ES6+)
parent.after(child);

6.3 插入节点

const parent = document.getElementById('parent');
const newElement = document.createElement('div');
newElement.textContent = '插入的元素';
const referenceElement = document.getElementById('reference');// 在 referenceElement 前面插入 newElement
parent.insertBefore(newElement, referenceElement);

6.4 替换节点

const parent = document.getElementById('parent');
const oldElement = document.getElementById('old');
const newElement = document.createElement('div');
newElement.textContent = '替换的元素';// 替换节点
parent.replaceChild(newElement, oldElement);

6.5 移除节点

const parent = document.getElementById('parent');
const child = document.getElementById('child');// 方法一:通过父节点移除
parent.removeChild(child);// 方法二:直接移除自身(ES6+)
child.remove();

6.6 克隆节点

const original = document.getElementById('original');// 浅克隆 - 只克隆元素本身,不克隆子节点
const shallowClone = original.cloneNode(false);// 深克隆 - 克隆元素本身及所有子节点
const deepClone = original.cloneNode(true);// 将克隆的节点添加到文档中
document.body.appendChild(deepClone);

七、DOM 事件处理

7.1 事件监听器的基本用法

const button = document.querySelector('button');// 添加事件监听器
button.addEventListener('click', function(event) {console.log('按钮被点击了');console.log('事件对象:', event);
});// 使用箭头函数
button.addEventListener('click', (event) => {console.log('按钮被点击了');
});// 移除事件监听器(需要引用同一个函数)
function handleClick() {console.log('按钮被点击了');
}button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);

7.2 常用事件类型

  • 鼠标事件:click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave
  • 键盘事件:keydown, keyup, keypress
  • 表单事件:submit, reset, change, input, focus, blur
  • 文档事件:DOMContentLoaded, load, beforeunload, resize, scroll
  • 触摸事件:touchstart, touchmove, touchend(移动设备)

7.3 事件对象属性和方法

事件处理函数接收一个事件对象,包含事件的详细信息:

element.addEventListener('click', (e) => {// 事件类型console.log(e.type); // "click"// 事件目标(触发事件的元素)console.log(e.target);// 当前元素(当前正在处理事件的元素)console.log(e.currentTarget);// 鼠标位置console.log('X坐标:', e.clientX, 'Y坐标:', e.clientY);// 阻止默认行为e.preventDefault();// 阻止事件冒泡e.stopPropagation();
});

7.4 事件冒泡和事件捕获

DOM 事件传播有三个阶段:

  1. 捕获阶段:从最外层元素向内传播
  2. 目标阶段:到达事件目标
  3. 冒泡阶段:从事件目标向外传播
// 第三个参数为 true 表示在捕获阶段处理事件
parent.addEventListener('click', () => {console.log('父元素捕获阶段');
}, true);// 第三个参数为 false 或省略表示在冒泡阶段处理事件
parent.addEventListener('click', () => {console.log('父元素冒泡阶段');
}, false);child.addEventListener('click', (e) => {console.log('子元素点击');// 阻止事件冒泡e.stopPropagation();
});

7.5 事件委托

利用事件冒泡原理,将事件监听器添加到父元素,而不是每个子元素:

<ul id="list"><li>项目 1</li><li>项目 2</li><li>项目 3</li>
</ul>
const list = document.getElementById('list');// 事件委托:将事件监听器添加到父元素
list.addEventListener('click', (e) => {// 检查事件目标是否是 li 元素if (e.target.tagName === 'LI') {console.log('点击了项目:', e.target.textContent);}
});

事件委托的优势:

  • 减少事件监听器数量,提高性能
  • 动态添加的子元素也能响应事件,无需重新绑定

八、DOM 遍历和查找

8.1 父节点和子节点

const element = document.querySelector('div');// 获取父节点
const parent = element.parentNode;
const parentElement = element.parentElement; // 只返回元素节点// 获取子节点
const childNodes = element.childNodes; // 所有子节点(包括文本、注释等)
const children = element.children; // 只包含元素子节点// 获取第一个和最后一个子节点
const firstChild = element.firstChild;
const lastChild = element.lastChild;
const firstElementChild = element.firstElementChild; // 第一个元素子节点
const lastElementChild = element.lastElementChild; // 最后一个元素子节点

8.2 兄弟节点

const element = document.querySelector('div');// 获取前一个和后一个兄弟节点
const previousSibling = element.previousSibling;
const nextSibling = element.nextSibling;// 获取前一个和后一个元素兄弟节点
const previousElementSibling = element.previousElementSibling;
const nextElementSibling = element.nextElementSibling;

8.3 遍历所有子节点

function traverseChildren(element) {// 遍历所有子节点for (let i = 0; i < element.childNodes.length; i++) {const node = element.childNodes[i];console.log(node.nodeName, node.nodeType);// 如果是元素节点,递归遍历其子节点if (node.nodeType === Node.ELEMENT_NODE) {traverseChildren(node);}}
}// 从 body 开始遍历整个文档
traverseChildren(document.body);

节点类型常量:

  • Node.ELEMENT_NODE (1):元素节点
  • Node.TEXT_NODE (3):文本节点
  • Node.COMMENT_NODE (8):注释节点
  • Node.DOCUMENT_NODE (9):文档节点

九、表单操作

9.1 获取表单元素

// 通过 ID 获取表单
const form = document.getElementById('myForm');// 通过 document.forms 获取
const formByName = document.forms['formName'];
const firstForm = document.forms[0]; // 通过索引获取// 获取表单控件
const usernameInput = form.elements['username'];
const passwordInput = form.querySelector('input[type="password"]');

9.2 获取和设置表单值

const usernameInput = document.getElementById('username');
const checkbox = document.getElementById('agree');
const select = document.getElementById('options');// 获取值
const username = usernameInput.value;
const isAgreed = checkbox.checked; // 复选框和单选按钮使用 checked 属性
const selectedValue = select.value;// 设置值
usernameInput.value = 'newUsername';
checkbox.checked = true;
select.value = 'option2';

9.3 表单提交处理

const form = document.getElementById('myForm');// 方式一:监听 form 的 submit 事件
form.addEventListener('submit', (e) => {e.preventDefault(); // 阻止表单默认提交行为// 处理表单数据const formData = new FormData(form);// 获取表单数据const username = formData.get('username');const password = formData.get('password');console.log('用户名:', username, '密码:', password);// 可以在这里发送 AJAX 请求
});// 方式二:在 HTML 中使用 onsubmit 属性
// <form onsubmit="return handleSubmit(event)">
function handleSubmit(e) {e.preventDefault();// 处理表单提交return false; // 阻止默认提交
}

十、DOM 性能优化

10.1 减少 DOM 操作次数

DOM 操作代价高昂,应尽量减少操作次数:

// 不推荐:频繁操作 DOM
const list = document.getElementById('list');
for (let i = 0; i < 1000; i++) {const item = document.createElement('li');item.textContent = `项目 ${i}`;list.appendChild(item); // 每次循环都操作 DOM
}// 推荐:使用文档片段减少 DOM 操作
const list = document.getElementById('list');
const fragment = document.createDocumentFragment();for (let i = 0; i < 1000; i++) {const item = document.createElement('li');item.textContent = `项目 ${i}`;fragment.appendChild(item); // 操作文档片段,不影响 DOM
}list.appendChild(fragment); // 一次性添加到 DOM

10.2 避免频繁查询 DOM

多次使用的 DOM 元素应缓存起来:

// 不推荐:多次查询同一元素
for (let i = 0; i < 10; i++) {document.getElementById('myDiv').style.left = i * 10 + 'px';
}// 推荐:缓存 DOM 元素引用
const myDiv = document.getElementById('myDiv');
for (let i = 0; i < 10; i++) {myDiv.style.left = i * 10 + 'px';
}

10.3 使用 CSS 类批量修改样式

// 不推荐:逐个修改样式属性
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';// 推荐:使用 CSS 类
element.classList.add('highlight');
// 在 CSS 中定义 .highlight 类包含所有样式

10.4 避免 layout thrashing(布局抖动)

尽量避免在短时间内频繁读取和修改布局属性:

// 不推荐:交替读取和修改布局属性
const elements = document.querySelectorAll('.box');
for (let i = 0; i < elements.length; i++) {elements[i].style.width = '100px';const height = elements[i].offsetHeight; // 触发重排elements[i].style.height = height + 'px';
}// 推荐:先读取所有布局属性,再统一修改
const elements = document.querySelectorAll('.box');
const heights = [];// 先读取所有需要的布局信息
for (let i = 0; i < elements.length; i++) {heights.push(elements[i].offsetHeight);
}// 再统一修改布局
for (let i = 0; i < elements.length; i++) {elements[i].style.width = '100px';elements[i].style.height = heights[i] + 'px';
}

十一、DOM 扩展方法

可以封装一些常用的 DOM 操作方法,提高开发效率:

// DOM 工具类
const DOMUtils = {// 根据选择器获取元素$: (selector) => document.querySelector(selector),// 根据选择器获取所有元素$$: (selector) => document.querySelectorAll(selector),// 创建元素并设置属性createElement: (tag, options = {}) => {const element = document.createElement(tag);Object.keys(options).forEach(key => {if (key === 'text') {element.textContent = options[key];} else if (key === 'html') {element.innerHTML = options[key];} else if (key === 'class') {element.className = options[key];} else {element.setAttribute(key, options[key]);}});return element;},// 为多个元素添加事件监听器on: (elements, event, handler) => {if (!Array.isArray(elements)) {elements = [elements];}elements.forEach(element => {element.addEventListener(event, handler);});},// 清空元素内容empty: (element) => {while (element.firstChild) {element.removeChild(element.firstChild);}}
};// 使用示例
const div = DOMUtils.createElement('div', {class: 'container',id: 'main',text: 'Hello World'
});DOMUtils.on(DOMUtils.$$('button'), 'click', (e) => {console.log('按钮被点击:', e.target);
});

十二、总结

JavaScript 操作 DOM 是前端开发的核心技能之一,本文详细介绍了:

  • DOM 基础概念和树结构
  • 获取 DOM 元素的多种方法
  • 元素属性和内容的操作
  • 样式修改技术
  • 节点的创建、添加、删除等操作
  • 事件处理机制和事件委托
  • DOM 遍历和查找
  • 表单操作技巧
  • 性能优化策略

http://www.xdnf.cn/news/18404.html

相关文章:

  • php apache无法接收到Authorization header
  • express+mongoose的node部署
  • 优考试局域网系统V6.0.0版
  • AI 论文周报丨多模态记忆智能体/视觉基础模型/推理模型等多领域成果一键速览
  • AI服务器介绍
  • 《Linux 网络编程一:网络编程导论及UDP 服务器的创建与数据接收》
  • 《基于大数据的农产品交易数据分析与可视化系统》选题不当,毕业答辩可能直接挂科
  • Linux系统 --- 指令
  • tauri配置允许执行eval脚本,在打包cocos游戏web/phone移动端的时候一定要配置
  • yolo训练实例(一)
  • AAA 服务器与 RADIUS 协议笔记
  • C++函数重载与引用详解
  • Django中间件自定义开发指南:从原理到实战的深度解析
  • 【机器学习深度学习】vLLM的核心优化技术详解
  • 大型语言模型中奖励模型的原理:训练、打分与更新
  • Java面试-自动装箱与拆箱机制解析
  • 零知开源——基于ESP8266(ESP-12F)驱动YS-IR05F红外控制空调
  • pytorch 网络可视化
  • Electron 核心 API 全解析:从基础到实战场景
  • k8sday14数据存储(2/2)
  • RSS与今日头条技术对比分析
  • 代码随想录刷题Day40
  • Linux 软件包安装和管理的相关操作及使用总结(未完成)
  • 漏洞分析 | Kafka Connect 任意文件读取漏洞(CVE-2025-27817)
  • 如何使用AI大语言模型解决生活中的实际小事情?
  • 【Protues仿真】基于AT89C52单片机的LCD液晶显示屏显示控制
  • 如何在 Axios 中处理多个 baseURL 而不造成混乱
  • portainer-ce汉化版下载
  • 从零开始的云计算生活——第四十九天,长路漫漫,kubernetes模块之持久化存储
  • 拆解本地组策略编辑器 (gpedit.msc) 的界面和功能