活动公告

系统通知
通知:本站资源由网友上传分享,如有违规等问题请到版务模块进行投诉,资源失效请在帖子内回复要求补档,会尽快处理!
10-23 09:31

掌握HTML DOM属性访问技巧提升网页交互性能从基础到进阶全面解析属性获取与修改方法助你成为前端开发高手

SunJu_FaceMall

3万

主题

2720

科技点

3万

积分

执行版主

碾压王

积分
32881

塔罗立华奏

执行版主 发表于 2025-8-31 15:10:00 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
引言

在现代Web开发中,文档对象模型(DOM)扮演着至关重要的角色。它是HTML和XML文档的编程接口,允许开发者和程序动态地访问和更新文档的内容、结构和样式。掌握DOM属性访问技巧不仅能提升网页的交互性能,还能帮助开发者构建更加高效、响应迅速的用户界面。本文将从基础到进阶,全面解析DOM属性的获取与修改方法,助你成为前端开发高手。

DOM基础:理解文档对象模型

什么是DOM

DOM(Document Object Model)是HTML和XML文档的编程接口,它将文档表示为一个节点树,其中每个节点代表文档的一部分(如元素、属性、文本等)。通过DOM,开发者可以使用脚本语言(如JavaScript)动态地访问和修改文档的各个方面。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <title>示例页面</title>
  5. </head>
  6. <body>
  7.     <h1>欢迎来到DOM世界</h1>
  8.     <p>这是一个关于DOM的示例段落。</p>
  9. </body>
  10. </html>
复制代码

上述HTML代码对应的DOM树结构如下:
  1. Document
  2. └── html
  3.      ├── head
  4.      │   └── title
  5.      │       └── "示例页面"
  6.      └── body
  7.          ├── h1
  8.          │   └── "欢迎来到DOM世界"
  9.          └── p
  10.              └── "这是一个关于DOM的示例段落。"
复制代码

DOM节点类型

DOM中包含多种节点类型,常见的有:

1. 元素节点(Element Node):表示HTML元素,如<div>、<p>等。
2. 属性节点(Attribute Node):表示元素的属性,如id、class等。
3. 文本节点(Text Node):表示元素中的文本内容。
4. 文档节点(Document Node):表示整个文档。

基础DOM属性访问方法

直接属性访问

最简单的DOM属性访问方式是通过JavaScript对象的属性直接访问。这种方式适用于大多数标准HTML属性。
  1. // 获取元素
  2. const element = document.getElementById('myElement');
  3. // 访问和修改属性
  4. element.id = 'newId';           // 修改id属性
  5. element.className = 'newClass'; // 修改class属性
  6. element.href = 'https://example.com'; // 修改a标签的href属性
  7. // 访问属性值
  8. const id = element.id;          // 获取id属性值
  9. const className = element.className; // 获取class属性值
复制代码

getAttribute()和setAttribute()方法

对于非标准属性或需要更精确控制的场景,可以使用getAttribute()和setAttribute()方法。
  1. // 获取元素
  2. const element = document.getElementById('myElement');
  3. // 使用getAttribute获取属性值
  4. const id = element.getAttribute('id');
  5. const dataValue = element.getAttribute('data-custom');
  6. // 使用setAttribute设置属性值
  7. element.setAttribute('id', 'newId');
  8. element.setAttribute('data-custom', 'customValue');
复制代码

属性(Property)与属性(Attribute)的区别

在DOM操作中,理解属性(Property)和属性(Attribute)的区别非常重要:

• 属性(Attribute):是HTML标签中定义的属性,如<div id="myDiv" class="container">中的id和class。
• 属性(Property):是DOM对象的属性,是JavaScript中的概念。

大多数情况下,属性(Attribute)和属性(Property)是同步的,但也有一些例外:
  1. <input type="checkbox" id="myCheckbox" checked>
复制代码
  1. const checkbox = document.getElementById('myCheckbox');
  2. // 获取属性值(Attribute)
  3. console.log(checkbox.getAttribute('checked')); // 返回 "checked"(初始状态)
  4. // 获取属性值(Property)
  5. console.log(checkbox.checked); // 返回 true(当前状态)
  6. // 修改属性(Property)
  7. checkbox.checked = false; // 复选框取消选中
  8. console.log(checkbox.getAttribute('checked')); // 仍然返回 "checked"
  9. console.log(checkbox.checked); // 返回 false
  10. // 修改属性(Attribute)
  11. checkbox.setAttribute('checked', 'checked'); // 复选框被选中
  12. console.log(checkbox.checked); // 返回 true
复制代码

进阶DOM属性操作技巧

批量属性操作

当需要同时操作多个属性时,可以使用Object.assign()或自定义函数来批量设置属性,减少DOM操作次数,提升性能。
  1. // 方法1:使用Object.assign()
  2. const element = document.getElementById('myElement');
  3. Object.assign(element, {
  4.     id: 'newId',
  5.     className: 'newClass anotherClass',
  6.     style: {
  7.         color: 'red',
  8.         fontSize: '16px'
  9.     }
  10. });
  11. // 方法2:自定义批量设置属性函数
  12. function setAttributes(el, attrs) {
  13.     for (let key in attrs) {
  14.         if (attrs.hasOwnProperty(key)) {
  15.             if (key === 'style' && typeof attrs[key] === 'object') {
  16.                 // 处理样式对象
  17.                 Object.assign(el.style, attrs[key]);
  18.             } else {
  19.                 el.setAttribute(key, attrs[key]);
  20.             }
  21.         }
  22.     }
  23. }
  24. // 使用自定义函数
  25. setAttributes(element, {
  26.     'data-id': '123',
  27.     'data-name': 'example',
  28.     'aria-label': 'Example element',
  29.     style: {
  30.         backgroundColor: '#f0f0f0',
  31.         padding: '10px'
  32.     }
  33. });
复制代码

性能优化的属性访问方法

频繁的DOM操作会导致性能问题,以下是一些优化技巧:
  1. // 不好的做法:每次都查询DOM
  2. function updateItems() {
  3.     const items = document.querySelectorAll('.item');
  4.     items.forEach(item => {
  5.         item.style.color = 'red';
  6.     });
  7. }
  8. // 好的做法:缓存DOM引用
  9. const items = document.querySelectorAll('.item');
  10. function updateItems() {
  11.     items.forEach(item => {
  12.         item.style.color = 'red';
  13.     });
  14. }
复制代码
  1. // 不好的做法:多次DOM操作
  2. const list = document.getElementById('list');
  3. for (let i = 0; i < 100; i++) {
  4.     const item = document.createElement('li');
  5.     item.textContent = `Item ${i}`;
  6.     list.appendChild(item);
  7. }
  8. // 好的做法:使用DocumentFragment
  9. const list = document.getElementById('list');
  10. const fragment = document.createDocumentFragment();
  11. for (let i = 0; i < 100; i++) {
  12.     const item = document.createElement('li');
  13.     item.textContent = `Item ${i}`;
  14.     fragment.appendChild(item);
  15. }
  16. list.appendChild(fragment);
复制代码
  1. // 不好的做法:直接修改样式
  2. element.style.width = '100px';
  3. element.style.height = '100px';
  4. element.style.backgroundColor = 'red';
  5. // 好的做法:使用requestAnimationFrame
  6. requestAnimationFrame(() => {
  7.     element.style.width = '100px';
  8.     element.style.height = '100px';
  9.     element.style.backgroundColor = 'red';
  10. });
复制代码

自定义属性(data-*)的使用

HTML5引入了自定义数据属性(data-*),允许在HTML元素上存储自定义数据,这些数据不会影响页面的呈现,但可以通过JavaScript访问。
  1. <div id="user" data-id="123" data-name="John Doe" data-email="john@example.com"></div>
复制代码
  1. // 获取元素
  2. const user = document.getElementById('user');
  3. // 使用getAttribute访问
  4. const userId = user.getAttribute('data-id'); // "123"
  5. const userName = user.getAttribute('data-name'); // "John Doe"
  6. // 使用dataset属性访问(更简洁)
  7. const userId2 = user.dataset.id; // "123"
  8. const userName2 = user.dataset.name; // "John Doe"
  9. // 修改自定义属性
  10. user.dataset.id = '456'; // 修改data-id
  11. user.dataset.role = 'admin'; // 添加data-role
  12. // 删除自定义属性
  13. delete user.dataset.role; // 删除data-role
复制代码

自定义属性在实际开发中有很多用途,例如:

1. 存储与元素相关的数据
2. 实现组件状态管理
3. 传递配置参数
  1. // 示例:使用data-*属性实现简单的选项卡组件
  2. const tabs = document.querySelectorAll('.tab');
  3. const contents = document.querySelectorAll('.tab-content');
  4. tabs.forEach(tab => {
  5.     tab.addEventListener('click', () => {
  6.         const targetId = tab.dataset.target;
  7.         
  8.         // 隐藏所有内容
  9.         contents.forEach(content => {
  10.             content.style.display = 'none';
  11.         });
  12.         
  13.         // 显示目标内容
  14.         document.getElementById(targetId).style.display = 'block';
  15.         
  16.         // 更新选项卡样式
  17.         tabs.forEach(t => t.classList.remove('active'));
  18.         tab.classList.add('active');
  19.     });
  20. });
复制代码

DOM属性与性能

重排(Reflow)与重绘(Repaint)

理解重排和重绘对于优化DOM操作性能至关重要:

• 重排(Reflow):当DOM的变化影响了元素的几何属性(宽、高、位置等),浏览器需要重新计算元素的几何属性,其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。
• 重绘(Repaint):当元素的外观发生变化,但没有影响布局,浏览器会将元素的新外观绘制到屏幕上。这个过程称为重绘。

重排(Reflow):当DOM的变化影响了元素的几何属性(宽、高、位置等),浏览器需要重新计算元素的几何属性,其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。

重绘(Repaint):当元素的外观发生变化,但没有影响布局,浏览器会将元素的新外观绘制到屏幕上。这个过程称为重绘。

重排的成本比重绘高得多,因此我们应该尽量减少重排操作。

以下操作会触发重排:

1. 添加或删除可见的DOM元素
2. 元素位置改变
3. 元素尺寸改变(包括外边距、内边距、边框厚度、宽度、高度等属性改变)
4. 内容改变(如文本改变或图片被另一个不同尺寸的图片替代)
5. 页面渲染器初始化
6. 浏览器窗口尺寸改变

如何减少DOM操作提升性能
  1. // 不好的做法:多次修改样式,触发多次重排
  2. element.style.width = '100px';
  3. element.style.height = '100px';
  4. element.style.backgroundColor = 'red';
  5. // 好的做法:一次性修改样式,只触发一次重排
  6. element.style.cssText = 'width: 100px; height: 100px; background-color: red;';
  7. // 或者使用class
  8. element.className = 'new-class';
复制代码
  1. // 不好的做法:直接操作可见DOM
  2. const list = document.getElementById('list');
  3. for (let i = 0; i < 1000; i++) {
  4.     const item = document.createElement('li');
  5.     item.textContent = `Item ${i}`;
  6.     list.appendChild(item);
  7. }
  8. // 好的做法:先克隆节点,操作后再替换
  9. const list = document.getElementById('list');
  10. const clone = list.cloneNode(false); // 浅克隆,不包含子节点
  11. for (let i = 0; i < 1000; i++) {
  12.     const item = document.createElement('li');
  13.     item.textContent = `Item ${i}`;
  14.     clone.appendChild(item);
  15. }
  16. list.parentNode.replaceChild(clone, list);
复制代码

虚拟DOM是现代前端框架(如React、Vue)广泛使用的技术,它通过在内存中维护一个虚拟的DOM树,计算出最小的DOM操作,然后批量应用到真实DOM上,从而提升性能。
  1. // 简化的虚拟DOM示例
  2. function createVirtualDOM(tag, props, children) {
  3.     return { tag, props, children };
  4. }
  5. function render(vdom, container) {
  6.     const element = document.createElement(vdom.tag);
  7.    
  8.     // 设置属性
  9.     if (vdom.props) {
  10.         for (let key in vdom.props) {
  11.             if (vdom.props.hasOwnProperty(key)) {
  12.                 element.setAttribute(key, vdom.props[key]);
  13.             }
  14.         }
  15.     }
  16.    
  17.     // 添加子元素
  18.     if (vdom.children) {
  19.         vdom.children.forEach(child => {
  20.             if (typeof child === 'string') {
  21.                 element.appendChild(document.createTextNode(child));
  22.             } else {
  23.                 render(child, element);
  24.             }
  25.         });
  26.     }
  27.    
  28.     container.appendChild(element);
  29. }
  30. // 使用虚拟DOM
  31. const vdom = createVirtualDOM('div', { class: 'container' }, [
  32.     createVirtualDOM('h1', {}, ['Hello Virtual DOM']),
  33.     createVirtualDOM('p', {}, ['This is a paragraph.'])
  34. ]);
  35. render(vdom, document.body);
复制代码

最佳实践

1. 减少DOM访问次数:缓存DOM引用,避免重复查询。
2. 批量操作DOM:使用文档片段(DocumentFragment)或离线节点进行批量操作。
3. 避免频繁读取布局信息:读取布局信息(如offsetWidth、offsetHeight等)会强制浏览器刷新布局队列,触发重排。

减少DOM访问次数:缓存DOM引用,避免重复查询。

批量操作DOM:使用文档片段(DocumentFragment)或离线节点进行批量操作。

避免频繁读取布局信息:读取布局信息(如offsetWidth、offsetHeight等)会强制浏览器刷新布局队列,触发重排。
  1. // 不好的做法:在循环中读取布局信息
  2. for (let i = 0; i < elements.length; i++) {
  3.     elements[i].style.width = elements[i].offsetWidth + 10 + 'px';
  4. }
  5. // 好的做法:先读取所有布局信息,再进行修改
  6. const widths = Array.from(elements).map(el => el.offsetWidth);
  7. for (let i = 0; i < elements.length; i++) {
  8.     elements[i].style.width = widths[i] + 10 + 'px';
  9. }
复制代码

1. 使用事件委托:减少事件监听器的数量,提升性能。
  1. // 不好的做法:为每个按钮添加事件监听器
  2. const buttons = document.querySelectorAll('.button');
  3. buttons.forEach(button => {
  4.     button.addEventListener('click', () => {
  5.         // 处理点击事件
  6.     });
  7. });
  8. // 好的做法:使用事件委托
  9. document.addEventListener('click', (event) => {
  10.     if (event.target.classList.contains('button')) {
  11.         // 处理点击事件
  12.     }
  13. });
复制代码

1. 使用CSS动画代替JavaScript动画:CSS动画通常比JavaScript动画性能更好,因为它们可以由浏览器直接优化。
  1. /* CSS动画 */
  2. .element {
  3.     transition: transform 0.3s ease;
  4. }
  5. .element:hover {
  6.     transform: scale(1.1);
  7. }
复制代码
  1. // JavaScript动画(性能较差)
  2. element.addEventListener('mouseenter', () => {
  3.     let scale = 1;
  4.     const animate = () => {
  5.         scale += 0.01;
  6.         element.style.transform = `scale(${scale})`;
  7.         if (scale < 1.1) {
  8.             requestAnimationFrame(animate);
  9.         }
  10.     };
  11.     animate();
  12. });
复制代码

实战案例:使用DOM属性构建交互式网页

让我们通过一个完整的示例来应用我们学到的DOM属性访问技巧。我们将构建一个简单的任务管理应用,包含添加、删除、标记完成和筛选任务的功能。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>任务管理应用</title>
  7.     <style>
  8.         * {
  9.             box-sizing: border-box;
  10.             margin: 0;
  11.             padding: 0;
  12.         }
  13.         
  14.         body {
  15.             font-family: 'Arial', sans-serif;
  16.             line-height: 1.6;
  17.             color: #333;
  18.             max-width: 600px;
  19.             margin: 0 auto;
  20.             padding: 20px;
  21.         }
  22.         
  23.         h1 {
  24.             text-align: center;
  25.             margin-bottom: 20px;
  26.         }
  27.         
  28.         .task-form {
  29.             display: flex;
  30.             margin-bottom: 20px;
  31.         }
  32.         
  33.         .task-input {
  34.             flex: 1;
  35.             padding: 10px;
  36.             border: 1px solid #ddd;
  37.             border-radius: 4px 0 0 4px;
  38.             font-size: 16px;
  39.         }
  40.         
  41.         .task-submit {
  42.             padding: 10px 15px;
  43.             background: #5c67f2;
  44.             color: white;
  45.             border: none;
  46.             border-radius: 0 4px 4px 0;
  47.             cursor: pointer;
  48.             font-size: 16px;
  49.         }
  50.         
  51.         .task-submit:hover {
  52.             background: #4a54e1;
  53.         }
  54.         
  55.         .filters {
  56.             display: flex;
  57.             margin-bottom: 20px;
  58.             border-bottom: 1px solid #ddd;
  59.         }
  60.         
  61.         .filter {
  62.             padding: 10px 15px;
  63.             cursor: pointer;
  64.             border-bottom: 2px solid transparent;
  65.         }
  66.         
  67.         .filter.active {
  68.             border-bottom: 2px solid #5c67f2;
  69.             color: #5c67f2;
  70.         }
  71.         
  72.         .task-list {
  73.             list-style: none;
  74.         }
  75.         
  76.         .task-item {
  77.             display: flex;
  78.             align-items: center;
  79.             padding: 10px;
  80.             border-bottom: 1px solid #eee;
  81.         }
  82.         
  83.         .task-checkbox {
  84.             margin-right: 10px;
  85.         }
  86.         
  87.         .task-text {
  88.             flex: 1;
  89.         }
  90.         
  91.         .task-text.completed {
  92.             text-decoration: line-through;
  93.             color: #999;
  94.         }
  95.         
  96.         .task-delete {
  97.             background: #ff5252;
  98.             color: white;
  99.             border: none;
  100.             padding: 5px 10px;
  101.             border-radius: 4px;
  102.             cursor: pointer;
  103.         }
  104.         
  105.         .task-delete:hover {
  106.             background: #ff3838;
  107.         }
  108.         
  109.         .task-count {
  110.             text-align: center;
  111.             margin-top: 20px;
  112.             color: #999;
  113.         }
  114.     </style>
  115. </head>
  116. <body>
  117.     <h1>任务管理应用</h1>
  118.    
  119.     <form class="task-form" id="taskForm">
  120.         <input type="text" class="task-input" id="taskInput" placeholder="添加新任务..." required>
  121.         <button type="submit" class="task-submit">添加</button>
  122.     </form>
  123.    
  124.     <div class="filters">
  125.         <div class="filter active" data-filter="all">全部</div>
  126.         <div class="filter" data-filter="active">进行中</div>
  127.         <div class="filter" data-filter="completed">已完成</div>
  128.     </div>
  129.    
  130.     <ul class="task-list" id="taskList"></ul>
  131.    
  132.     <div class="task-count" id="taskCount">0 个任务</div>
  133.    
  134.     <script>
  135.         // 使用立即执行函数表达式(IIFE)避免全局变量污染
  136.         (function() {
  137.             // DOM缓存
  138.             const taskForm = document.getElementById('taskForm');
  139.             const taskInput = document.getElementById('taskInput');
  140.             const taskList = document.getElementById('taskList');
  141.             const taskCount = document.getElementById('taskCount');
  142.             const filters = document.querySelectorAll('.filter');
  143.             
  144.             // 应用状态
  145.             let tasks = [];
  146.             let currentFilter = 'all';
  147.             
  148.             // 初始化
  149.             function init() {
  150.                 // 从本地存储加载任务
  151.                 const savedTasks = localStorage.getItem('tasks');
  152.                 if (savedTasks) {
  153.                     tasks = JSON.parse(savedTasks);
  154.                     renderTasks();
  155.                 }
  156.                
  157.                 // 事件监听
  158.                 taskForm.addEventListener('submit', handleAddTask);
  159.                
  160.                 // 使用事件委托处理筛选器点击
  161.                 document.addEventListener('click', (event) => {
  162.                     if (event.target.classList.contains('filter')) {
  163.                         handleFilterChange(event.target.dataset.filter);
  164.                     }
  165.                 });
  166.                
  167.                 // 使用事件委托处理任务列表中的点击事件
  168.                 taskList.addEventListener('click', handleTaskClick);
  169.             }
  170.             
  171.             // 添加任务
  172.             function handleAddTask(event) {
  173.                 event.preventDefault();
  174.                
  175.                 const taskText = taskInput.value.trim();
  176.                 if (taskText) {
  177.                     // 创建新任务
  178.                     const newTask = {
  179.                         id: Date.now(),
  180.                         text: taskText,
  181.                         completed: false
  182.                     };
  183.                     
  184.                     // 添加到任务数组
  185.                     tasks.push(newTask);
  186.                     
  187.                     // 保存到本地存储
  188.                     saveTasks();
  189.                     
  190.                     // 重新渲染任务列表
  191.                     renderTasks();
  192.                     
  193.                     // 清空输入框
  194.                     taskInput.value = '';
  195.                     taskInput.focus();
  196.                 }
  197.             }
  198.             
  199.             // 处理任务点击事件
  200.             function handleTaskClick(event) {
  201.                 const target = event.target;
  202.                 const taskItem = target.closest('.task-item');
  203.                
  204.                 if (!taskItem) return;
  205.                
  206.                 const taskId = parseInt(taskItem.dataset.id);
  207.                
  208.                 // 处理复选框点击
  209.                 if (target.classList.contains('task-checkbox')) {
  210.                     toggleTaskStatus(taskId);
  211.                 }
  212.                
  213.                 // 处理删除按钮点击
  214.                 if (target.classList.contains('task-delete')) {
  215.                     deleteTask(taskId);
  216.                 }
  217.             }
  218.             
  219.             // 切换任务状态
  220.             function toggleTaskStatus(taskId) {
  221.                 const task = tasks.find(t => t.id === taskId);
  222.                 if (task) {
  223.                     task.completed = !task.completed;
  224.                     saveTasks();
  225.                     renderTasks();
  226.                 }
  227.             }
  228.             
  229.             // 删除任务
  230.             function deleteTask(taskId) {
  231.                 tasks = tasks.filter(t => t.id !== taskId);
  232.                 saveTasks();
  233.                 renderTasks();
  234.             }
  235.             
  236.             // 处理筛选器变化
  237.             function handleFilterChange(filter) {
  238.                 currentFilter = filter;
  239.                
  240.                 // 更新筛选器样式
  241.                 filters.forEach(f => {
  242.                     if (f.dataset.filter === filter) {
  243.                         f.classList.add('active');
  244.                     } else {
  245.                         f.classList.remove('active');
  246.                     }
  247.                 });
  248.                
  249.                 renderTasks();
  250.             }
  251.             
  252.             // 渲染任务列表
  253.             function renderTasks() {
  254.                 // 使用文档片段批量操作DOM
  255.                 const fragment = document.createDocumentFragment();
  256.                
  257.                 // 根据当前筛选器过滤任务
  258.                 const filteredTasks = tasks.filter(task => {
  259.                     if (currentFilter === 'all') return true;
  260.                     if (currentFilter === 'active') return !task.completed;
  261.                     if (currentFilter === 'completed') return task.completed;
  262.                 });
  263.                
  264.                 // 如果没有任务,显示提示信息
  265.                 if (filteredTasks.length === 0) {
  266.                     const emptyMessage = document.createElement('li');
  267.                     emptyMessage.textContent = currentFilter === 'all'
  268.                         ? '还没有任务,添加一个吧!'
  269.                         : `没有${currentFilter === 'active' ? '进行中' : '已完成'}的任务`;
  270.                     emptyMessage.style.textAlign = 'center';
  271.                     emptyMessage.style.padding = '20px';
  272.                     emptyMessage.style.color = '#999';
  273.                     fragment.appendChild(emptyMessage);
  274.                 } else {
  275.                     // 创建任务项
  276.                     filteredTasks.forEach(task => {
  277.                         const taskItem = document.createElement('li');
  278.                         taskItem.className = 'task-item';
  279.                         taskItem.dataset.id = task.id;
  280.                         
  281.                         // 复选框
  282.                         const checkbox = document.createElement('input');
  283.                         checkbox.type = 'checkbox';
  284.                         checkbox.className = 'task-checkbox';
  285.                         checkbox.checked = task.completed;
  286.                         
  287.                         // 任务文本
  288.                         const taskText = document.createElement('span');
  289.                         taskText.className = 'task-text';
  290.                         if (task.completed) {
  291.                             taskText.classList.add('completed');
  292.                         }
  293.                         taskText.textContent = task.text;
  294.                         
  295.                         // 删除按钮
  296.                         const deleteButton = document.createElement('button');
  297.                         deleteButton.className = 'task-delete';
  298.                         deleteButton.textContent = '删除';
  299.                         
  300.                         // 添加到任务项
  301.                         taskItem.appendChild(checkbox);
  302.                         taskItem.appendChild(taskText);
  303.                         taskItem.appendChild(deleteButton);
  304.                         
  305.                         // 添加到文档片段
  306.                         fragment.appendChild(taskItem);
  307.                     });
  308.                 }
  309.                
  310.                 // 清空任务列表并添加新内容
  311.                 while (taskList.firstChild) {
  312.                     taskList.removeChild(taskList.firstChild);
  313.                 }
  314.                 taskList.appendChild(fragment);
  315.                
  316.                 // 更新任务计数
  317.                 updateTaskCount();
  318.             }
  319.             
  320.             // 更新任务计数
  321.             function updateTaskCount() {
  322.                 const activeTasks = tasks.filter(t => !t.completed).length;
  323.                 taskCount.textContent = `${activeTasks} 个任务待完成`;
  324.             }
  325.             
  326.             // 保存任务到本地存储
  327.             function saveTasks() {
  328.                 localStorage.setItem('tasks', JSON.stringify(tasks));
  329.             }
  330.             
  331.             // 初始化应用
  332.             init();
  333.         })();
  334.     </script>
  335. </body>
  336. </html>
复制代码

这个任务管理应用展示了多种DOM属性访问和操作的技巧:

1. DOM缓存:我们缓存了常用的DOM引用,避免重复查询。
2. 事件委托:我们使用事件委托处理筛选器和任务列表的点击事件,减少事件监听器的数量。
3. 批量DOM操作:使用文档片段(DocumentFragment)批量添加任务项,减少重排次数。
4. 自定义数据属性:使用data-id存储任务ID,方便在事件处理中识别任务。
5. 本地存储:使用localStorage保存任务数据,实现数据持久化。
6. 状态管理:使用JavaScript对象管理应用状态,通过渲染函数更新UI。

总结与展望

本文从基础到进阶,全面解析了HTML DOM属性的获取与修改方法,并探讨了如何通过优化DOM操作提升网页交互性能。我们学习了:

1. DOM基础概念和节点类型
2. 直接属性访问和getAttribute()/setAttribute()方法
3. 属性(Property)与属性(Attribute)的区别
4. 批量属性操作和性能优化技巧
5. 自定义属性(data-*)的使用
6. 重排与重绘的概念及其对性能的影响
7. 减少DOM操作的最佳实践

掌握这些技巧,将帮助你构建更加高效、响应迅速的网页应用。随着前端技术的不断发展,新的DOM操作方法和优化策略也在不断涌现。例如,现代前端框架(如React、Vue)通过虚拟DOM技术进一步优化了DOM操作,提供了更高级的抽象和更好的性能。

作为前端开发者,持续学习和实践这些技术,将使你能够构建出用户体验更好、性能更优的网页应用,真正成为前端开发高手。
「七転び八起き(ななころびやおき)」
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则