JavaScript---DOM对象

1、DOM 基础概念

        DOM (Document Object Model,文档对象模型) 是 JavaScript 操作网页内容的核心 API。它将 HTML 文档转换为一个由节点组成的树状结构,允许通过 JavaScript 动态地访问、修改、添加或删除网页中的任何元素

2、DOM 树结构

        当浏览器加载 HTML 页面时,它会将文档解析为一个由节点组成的树状结构

document (根节点)
├── html (元素节点)
│   ├── head (元素节点)
│   │   ├── title (元素节点)
│   │   └── meta (元素节点)
│   └── body (元素节点)
│       ├── h1 (元素节点)
│       ├── p (元素节点)
│       ├── div (元素节点)
│       │   └── img (元素节点)
│       └── form (元素节点)
│           ├── input (元素节点)
│           └── button (元素节点)
│           └── ...

3、DOM 的核心对象

        1、document 对象

                作用:document 是 DOM 的入口点,代表整个 HTML 文档,就代表当前当前网页内容

                常用属性和方法:

// 获取文档信息
document.title;        // 获取/设置页面标题
document.URL;          // 获取完整 URL
document.domain;       // 获取域名
document.referrer;     // 获取来源页面

// 查找元素
document.getElementById('id');          // 通过ID获取元素
document.getElementsByClassName('class'); // 通过类名获取元素集合
document.getElementsByTagName('h1');   // 通过标签名获取元素集合
document.querySelector('css选择器');    // 获取第一个匹配元素
document.querySelectorAll('css选择器'); // 获取所有匹配元素集合

var father = document.getElementById('fater ');   
var childrens = father.children;  // 获取父级下的所有子级元素集合

// 创建和操作文档
document.createElement('tagName');      // 创建新元素
document.createTextNode('text');        // 创建文本节点
document.createComment('comment');      // 创建注释节点
        2、Element 对象

                  作用:代表 HTML 元素,是 DOM 树中最常用的对象类型,也就是通过document对象得到的元素对象

                  常用属性和方法:


// 获取和设置内容
element.innerHTML;      // 获取/设置HTML内容(会自动解析HTML标签)
element.textContent;    // 获取/设置纯文本内容
element.innerText;      // 获取/设置可见文本内容(考虑CSS隐藏)

// 获取元素信息
element.id;             // 元素ID
element.className;      // 元素类名
element.classList;      // 类列表对象(推荐操作类)
element.tagName;        // 元素标签名(大写)
element.attributes;     // 元素所有属性集合

// 操作样式
element.style;          // 元素内联样式对象
element.style.color = 'red'; // 设置内联样式
...  //所有的样式都是操作

// 获取元素位置和尺寸
element.offsetParent;   // 最近的定位父元素
element.offsetTop;      // 相对于offsetParent的顶部距离
element.offsetLeft;     // 相对于offsetParent的左侧距离
element.offsetWidth;    // 元素宽度(含边框和内边距)
element.offsetHeight;   // 元素高度(含边框和内边距)
element.getBoundingClientRect(); // 获取元素相对于视口的位置和尺寸

// 操作DOM
element.appendChild(newChild);      // 添加子元素
element.removeChild(child);         // 删除子元素  必须通过父级删除
element.replaceChild(newChild, oldChild); // 替换子元素
element.insertBefore(newNode, referenceNode); // 在指定节点前插入
element.remove();                   // 删除自身(现代方法)
element.cloneNode(deep);            // 克隆节点(deep=true克隆后代)

例:操作节点~增、删、改、查

        1、追加节点

//初始代码
<body>
<p id="p2">p2</p>
<div id="myDiv">
    <p id="s1">s1</p>
    <h1 id="h1">h1</h1>
    <p id="p1">p1</p>
</div>

</body>
<script>
    var father = document.getElementById("myDiv");
    var p2 = document.getElementById("p2");
    father.appendChild(p2)  //将p2追加到myDiv的子级中,默认追加到最后一个(是直接移动整个标签)


</script>

        追加后的效果

        2、修改节点,也是一种节点插入,当有父级节点的时候修改父级内容,就会生成一个新的节点并且覆盖旧的子级节点,所有在修改父级节点的时候一定要注意这个问题

//动态赋值以及修改样式
<body>
<p id="ss"></p>

</body>
<script>
    var s = document.getElementById("ss")
    s.innerText = "123";  //页面展示123
    s.innerHTML = "<strong>456</strong>"   //页面展示粗体456

    s.style.color = 'red';  //页面展示红色粗体456
    
    //所以上述element代表的就是此处的s


</script>

       3、删除节点


//删除节点
<body>
<div id="myDiv">
    <p id="ss">11</p>
    <h1 id="h1">22</h1>
    <p id="p1">33</p>
</div>

</body>
<script>
    var myDiv = document.getElementById("myDiv");  //父节点
    var h1 = document.getElementById("h1");
    myDiv.removeChild(h1);

    myDiv.removeChild(myDiv.children[0]);  //删除,注意此种方式多次删除时,children的下标是动态变的


</script>

//删除节点方式二
<body>
<div id="myDiv">
    <p id="ss">11</p>
    <h1 id="h1">22</h1>
    <p id="p1">33</p>
</div>

</body>
<script>
    var h1 = document.getElementById("h1");
    var myDiv = h1.parentElement;  //找父节点
    myDiv.removeChild(h1);  //删除


</script>


//删除节点方式三
<body>
<div id="myDiv">
    <p id="ss">11</p>
    <h1 id="h1">22</h1>
    <p id="p1">33</p>
</div>

</body>
<script>
    var h1 = document.getElementById("h1");
    h1.remove();  //删除


</script>
        3、Node 对象

                作用:所有DOM节点的基类,包括元素节点、文本节点、注释节点等

                常用节点类型常量:

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

                常用属性和方法:

// 节点关系
node.parentNode;      // 父节点
node.childNodes;      // 所有子节点集合
node.firstChild;      // 第一个子节点
node.lastChild;       // 最后一个子节点
node.nextSibling;     // 下一个兄弟节点
node.previousSibling; // 上一个兄弟节点

// 节点操作
node.appendChild(newNode);      // 添加子节点
node.insertBefore(newNode, referenceNode); // 在指定节点前插入
node.removeChild(child);        // 删除子节点
node.replaceChild(newChild, oldChild); // 替换子节点
node.contains(otherNode);       // 是否包含指定节点
node.hasChildNodes();           // 是否有子节点

4、其他重要DOM对象

        1、NodeList 和 HTMLCollection

                NodeList: 类数组对象,表示节点集合(如 querySelectorAll 返回)

                HTMLCollection: 类数组对象,表示元素集合(如 getElementsByClassName 返回)

// 遍历NodeList/HTMLCollection
const elements = document.querySelectorAll('.test');
elements.forEach(el => {
  console.log(el.textContent);
});

// 或传统方式
for (let i = 0; i < elements.length; i++) {
  console.log(elements[i].textContent);
}
        2、Attribute 对象

                代表元素的属性

// 获取和设置属性
element.getAttribute('name');      // 获取自定义属性
element.setAttribute('name', '哈哈');// 设置自定义属性
element.removeAttribute('name');   // 删除属性
element.hasAttribute('name');      // 检查属性是否存在

// 直接访问标准属性
element.name= '哈哈';                 // 等同于setAttribute
element.age= '18';       // 等同于setAttribute
        3、Event 对象

                代表事件相关信息的对象

// 事件监听示例
element.addEventListener('click', function(event) {
  console.log(event.target);     // 触发事件的元素
  console.log(event.type);       // 事件类型
  console.log(event.clientX);    // 鼠标X坐标
  console.log(event.clientY);    // 鼠标Y坐标
  event.preventDefault();        // 阻止默认行为
  event.stopPropagation();       // 阻止事件冒泡
});

5、DOM 操作实践           

        1、基本DOM操作示例   :
<div id="container">
  <ul id="list">
    <li class="item">测试1</li>
    <li class="item">测试2</li>
  </ul>
</div>

<script>
  // 1. 获取元素
  const container = document.getElementById('container');
  const list = document.getElementById('list');
  const items = document.querySelectorAll('.item');
  
  // 2. 修改内容
  list.innerHTML = '<li class="item">新测试</li>'; // 替换所有子元素
  
  // 3. 创建新元素
  const newItem = document.createElement('li');
  newItem.className = 'item';
  newItem.textContent = '动态创建的测试';
  
  // 4. 添加元素
  list.appendChild(newItem); // 添加到末尾
  
  // 5. 插入元素到指定位置
  const referenceItem = list.children[0];  //要通过父级找到子级节点,才能实现insertBefore的指定插入
  list.insertBefore(newItem, referenceItem); // 在referenceItem前插入
  
  // 6. 删除元素
  const oldItem = items[1];
  oldItem.remove(); // 现代方法
  // 或 list.removeChild(oldItem);
  
  // 7. 克隆元素
  const clonedItem = newItem.cloneNode(true); // true表示深度克隆
  list.appendChild(clonedItem);
</script>
        2、表单简单操作示例:
//监听表单方式
<form id="myForm">
  <input type="text" id="username" placeholder="用户名">
  <input type="password" id="password" placeholder="密码">
  <button type="submit">提交</button>
</form>

<script>
  const form = document.getElementById('myForm');
  const usernameIn = document.getElementById('username');
  const passwordIn = document.getElementById('password');
  
  // 监听表单提交
  form.addEventListener('submit', function(event) {
    event.preventDefault(); // 阻止表单默认提交
    
    const username = usernameIn.value;
    const password = passwordIn.value;
    
    console.log('用户名:', username);
    console.log('密码:', password);
    
    // 表单验证示例
    if (!username || !password) {
      alert('请填写所有字段');
      return;
    }
    
    // 处理表单数据...
    alert('表单提交成功!');
  });
  
  // 实时验证
  usernameIn.addEventListener('input', function() {
    if (this.value.length < 3) {
      this.style.borderColor = 'red';
    } else {
      this.style.borderColor = 'green';
    }
  });
</script>





//表单提交事件方式
<form id="myForm">
    <input type="text" id="username" placeholder="用户名">
    <input type="password" id="password" placeholder="密码">
    <button type="submit" onclick="sub()">提交</button>
</form>

<script>
    const usernameIn = document.getElementById('username');
    const passwordIn = document.getElementById('password');

    // 表单提交事件
    function sub() {
        event.preventDefault(); // 阻止表单默认提交

        const username = usernameIn.value;
        const password = passwordIn.value;

        console.log('用户名:', username);
        console.log('密码:', password);

        // 表单验证示例
        if (!username || !password) {
            alert('请填写所有字段');
            return;
        }

        // 处理表单数据...
        alert('表单提交成功!');
    }

    // 实时验证
    usernameIn.addEventListener('input', function () {
        if (this.value.length < 3) {
            this.style.borderColor = 'red';
        } else {
            this.style.borderColor = 'green';
        }
    });
</script>

6、DOM 高级特性

        1、事件委托

                利用事件冒泡机制,在父元素上监听子元素的事件

<ul id="todoList">
  <li>任务1 <button class="delete">删除</button></li>
  <li>任务2 <button class="delete">删除</button></li>
  <li>任务3 <button class="delete">删除</button></li>
</ul>

<script>
  const todoList = document.getElementById('todoList');
  
  // 事件委托 - 在父元素上监听子按钮的点击
  todoList.addEventListener('click', function(event) {
    if (event.target.classList.contains('delete')) {
      const listItem = event.target.parentElement;
      listItem.remove();
    }
  });
</script>
        2、动态加载内容

                使用 Fetch API 或 AJAX 动态加载数据并更新DOM

<div id="content"></div>
<button id="loadData">加载数据</button>

<script>
  document.getElementById('loadData').addEventListener('click', function() {
    // 使用Fetch API获取数据
    fetch('http://localhost:8080/test/posts/1')
      .then(response => response.json())
      .then(data => {
        const contentDiv = document.getElementById('content');
        contentDiv.innerHTML = `
          <h2>${data.title}</h2>
          <p>${data.body}</p>
        `;
      })
      .catch(error => {
        console.error('加载数据出错:', error);
      });
  });
</script>
        3、自定义数据属性 (data-*)

                HTML5 提供的自定义数据属性,可通过 dataset 访问

<div id="user" data-id="123" data-role="admin" data-active="true">
  用户信息
</div>

<script>
  const userDiv = document.getElementById('user');
  
  // 获取data属性
  console.log(userDiv.dataset.id);     // "123"
  console.log(userDiv.dataset.role);   // "admin"
  console.log(userDiv.dataset.active); // "true"
  
  // 设置data属性
  userDiv.dataset.role = 'user';
  userDiv.dataset.lastLogin = '2023-01-01';
  
  console.log(userDiv.dataset.lastLogin); // "2023-01-01"
</script>

7、DOM 性能优化

        1、减少DOM操作

                DOM 操作是昂贵的,应尽量减少直接操作

// 每次循环都直接操作DOM - 性能差
for (let i = 0; i < 100; i++) {
  const div = document.createElement('div');
  document.body.appendChild(div);
}

        优化:

// 先在内存中构建,然后一次性添加 - 性能好
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
  const div = document.createElement('div');
  fragment.appendChild(div);
}
document.body.appendChild(fragment);
        2、使用 DocumentFragment

                DocumentFragment 是轻量级的文档对象,用于临时存储DOM节点,减少重排和重绘。

const fragment = document.createDocumentFragment();

for (let i = 0; i < 10; i++) {
  const li = document.createElement('li');
  li.textContent = `项目 ${i}`;
  fragment.appendChild(li);
}

document.getElementById('list').appendChild(fragment);
        3、批量修改样式

                避免频繁读写样式属性,应批量修改。

// 每次循环都查询和修改样式 - 触发多次重排
for (let i = 0; i < elements.length; i++) {
  elements[i].style.left = i * 10 + 'px';
  elements[i].style.top = i * 10 + 'px';
}

        优化:

// 使用CSS类或一次性修改style
elements.forEach((el, i) => {
  el.style.cssText = `left: ${i * 10}px; top: ${i * 10}px;`;
});

// 或更好的方式 - 使用CSS类
elements.forEach(el => {
  el.classList.add('new-position');
});

8、DOM API

        1、MutationObserver

                监听DOM树的变化。

const observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    console.log('DOM发生了变化:', mutation.type);
    if (mutation.type === 'childList') {
      console.log('子节点发生变化');
    }
  });
});

// 开始观察目标节点
observer.observe(document.body, {
  childList: true,    // 观察子节点的添加或删除
  subtree: true,      // 观察所有后代节点
  attributes: true,   // 观察属性变化
  attributeOldValue: true // 记录旧属性值
});

// 停止观察
// observer.disconnect();
        2、 IntersectionObserver

                监听元素与视口的交叉状态,常用于懒加载

const observer = new IntersectionObserver(function(entries) {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('元素进入视口:', entry.target);
      // 执行加载操作...
      entry.target.classList.add('loaded');
      observer.unobserve(entry.target); // 停止观察已加载的元素
    }
  });
});

// 观察元素
document.querySelectorAll('.lazy-image').forEach(img => {
  observer.observe(img);
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值