整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

DOM 操作之DOM概念和获取元素

DOM 操作之DOM概念和获取元素

章目标

  • 了解 WebAPI 概念
  • 掌握 DOM 和 BOM 的概念
  • 能够获取页面上的元素

本章任务

  • 演示美女相册案例
  • 能够完成网页开关灯案例

Web API 基础概念

  • 理解 API
  • 理解 Web API
  • 理解 DOM 和 BOM

API 的概念


API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,API 是由语言本身或者运行平台提供的一系列特性和规则,通常是开发人员可以使用的一系列代码特性,通常以对象的形式提供给开发人员,比如:数组对象,数组对象提供 length 属性,以及 push/pop 等一些列的方法,这就是我们常用的 API,是由语言本身提供的 API。


API 目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。


  • 任何开发语言都有自己的 API
  • API 的特征输入和输出(I/O)
  • API 的使用方法(console.log())


Web API 的概念


Web API 是浏览器提供给我们操作浏览器和网页文档的一套编程接口。这是由 JavaScript 的运行环境(此处是浏览器)提供的 API。通过浏览器提供的 API,我们可以实现弹窗效果(alert、prompt)、以及操作网页文档的能力,当然还有很多涉及和硬件交互的 API,比如操作摄像头、获取地理位置等。

JavaScript 组成


下面在学习 BOM 和 DOM 之前,我们先来回顾下 JavaScript 组成:

BOM


BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。BOM 由多个对象组成,其中代表浏览器窗口的 window 对象是 BOM 的顶层对象,其他对象都是该对象的子对象。


我们在浏览器中的一些操作都可以使用BOM的方式进行编程处理

比如:刷新浏览器、后退、前进、在浏览器中输入URL等。


DOM


文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”,双方为了在JavaScript与JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上加入了不少专属事物,既有VBScript、ActiveX、以及微软自家的DHTML格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时蕴酿出来的杰作。


DOM 又称为文档树模型,因为 HTML 文档本身就是一个树形结构,而 DOM 是使用面向对象的思维方式把 HTML 文档以及 HTML 中的标签全部抽象成对象,浏览器在执行的之后就会把网页在内存中构建成 DOM 对象


如果 HTML 中的每一个标签/节点都是一个对象,我们就可以通过这个对象来操作 DOM 上的元素,比如:使用 JS 获取页面上的 div 对象,然后通过 div 对象的属性或者方法控制 div 显示或者隐藏。

DOM

DOM 简介

DOM 概念

DOM 是 JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将网页转为 JavaScript 对象,从而可以用脚本进行各种操作(比如增删内容)。


浏览器会根据 DOM 模型,将结构化文档(比如 HTML 和 XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。所有的节点和最终的树状结构,都有规范的对外接口。


DOM 只是一个接口规范,可以用各种语言实现。所以严格地说,DOM 不是 JavaScript 语法的一部分,但是 DOM 操作是 JavaScript 最常见的任务,离开了 DOM,JavaScript 就无法控制网页。另一方面,JavaScript 也是最常用于 DOM 操作的语言。后面介绍的就是 JavaScript 对 DOM 标准的实现和用法。


DOM 定义了访问 HTML 和 XML 文档的标准:

“W3C 文档对象模型 (DOM) 是中立于平台和语言的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。”

W3C DOM 标准被分为 3 个不同的部分:

  • DOM Core - 针对任何结构化文档的标准模型
  • XML DOM - 针对 XML 文档的标准模型

XML DOM 定义了所有 XML 元素的对象和属性,以及访问它们的方法。

  • HTML DOM - 针对 HTML 文档的标准模型

HTML DOM 定义了所有 HTML 元素的对象和属性,以及访问它们的方法。HTML DOM 是关于如何获取、修改、添加或删除 HTML 元素的标准。


节点


DOM 的最小组成单位叫做节点(node)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成。每个节点可以看作是文档树的一片叶子。节点也是对象。


节点的类型:


  • 文档节点:document,代表浏览器中加载的 HTML 页面
  • 元素节点:HTML 文档中的标签,后面元素节点我们简称元素
  • 属性节点:标签的属性
  • 文本节点:两个标签之间的文本内容
  • 注释节点:HTML 文档中的注释


DOM 的层级


因为 DOM 文档树是一个树形结构,树形结构中的节点包含兄弟、父子的关系,比如下图中,body 是 h1、p、和 table 的父节点,同时 h1、p、table 是 body 的子节点。h1 p table 是兄弟节点。这点很重要后面节点操作中会通过这种方式获取页面上的元素。


DOM 中的常用操作


例如我们要实现下图中的美女画廊,点击第一排的小图切换大图和最底下图片的描述,这个时候我们需要先获取到小图,并且让小图能够点击,最后修改显示的大图以及显示的内容。


根据上例总结未来我们常用的 DOM 操作是:获取元素、注册事件、操作元素。


获取元素


首先我们来看为什么要获取页面元素,我们这里有一个需求:把 body 背景色变成黑色(模拟网页中看视频的关灯效果)。

思路:首先找到 body 元素,然后改变 body 的背景颜色

let body=document.body;
console.log(body);

body 是页面内主体标签,有特殊性,可快速获取,但是 div 这类标签就不行。

下面我们来学习如何获取页面上的元素,这里我们先来介绍两个获取页面元素的方法:

  • 根据 id 获取元素
let div=document.getElementById(id)
console.log(div)

注意:由于id名具有唯一性,部分浏览器支持直接使用id名访问元素,但不是标准方式,不推荐使用。

  • 根据标签获取一组元素
let divs=document.getElementsByTagName(tagName)
console.log(divs)
let divs=document.getElementsByTagName('div');
for (let i=0; i < divs.length; i++) {
  let div=divs[i];
  console.log(div);
}


注意:通过标签名获取到的数据是伪数组,不管标签是一个还是多个,返回的都是伪数组。

返回的数据类型是 HTMLCollection 集合,HTMLCollection 是内置类型,我们无法直接使用


案例:关灯


点击按钮让 div 的背景颜色改变为黑色。


  • 获取按钮,给按钮注册点击事件
let btn=document.getElementById('btn');
btn.onclick=function () {};
    • 事件的三要素
      • 事件源:需要注册事件的元素
      • 事件名称:click 点击事件
      • 事件处理函数:当事件触发的时候执行的函数


  • 获取页面上的 div
let div=document.getElementById('div');
  • 把颜色设置为黑色(后续有专门的小节来学习)
div.style.background='black';


扩展内容


不同的 DOM 节点可能有不同的属性。例如,标签 <a> 相对应的元素节点具有链接相关的(link-related)属性,标签 <input> 相对应的元素节点具有与输入相关的属性等。文本节点与元素节点不同。但是所有这些标签对应的 DOM 节点之间也存在共有的属性和方法,因为所有类型的 DOM 节点都形成了一个单一层次的结构。


每个 DOM 节点都属于相应的内建类。

层次结构的根节点是 EventTarget,Node 继承自它,其他 DOM 节点继承自 Node。

下图做了进一步说明:

  • EventTarget — 是根的“抽象(abstract)”类。该类的对象从未被创建。它作为一个基础,以便让所有 DOM 节点都支持所谓的“事件(event)”,我们会在之后学习它。
  • Node — 也是一个“抽象”类,充当 DOM 节点的基础。它提供了树的核心功能:parentNode,nextSibling,childNodes 等(它们都是 getter)。Node 类的对象从未被创建。但是有一些继承自它的具体的节点类,例如:文本节点的 Text,元素节点的 Element,以及更多异域(exotic)类,例如注释节点的 Comment。
  • Element — 是 DOM 元素的基本类。它提供了元素级的导航(navigation),例如 nextElementSibling,children,以及像 getElementsByTagName 和 querySelector 这样的搜索方法。浏览器中不仅有 HTML,还会有 XML 和 SVG。Element 类充当更多特定类的基本类:SVGElement,XMLElement 和 HTMLElement。
  • HTMLElement— 最终是所有 HTML 元素的基本类。各种 HTML 元素均继承自它:
    • HTMLInputElement — <input> 元素的类,
    • HTMLBodyElement — <body> 元素的类,
    • HTMLAnchorElement — <a> 元素的类,
    • ……等,每个标签都有自己的类,这些类可以提供特定的属性和方法。

因此,给定节点的全部属性和方法都是继承的结果。


通过 console.dir(div) 可以打印 div 元素的所有成员,在属性的最下面可以看到当前打印的 div 对象的类型是 HTMLDivElement,如下图:

作业


通过查询 MDN 学习下面两个获取元素方法的使用方式:


  • querySelector(selector)
  • querySelectorAll(selector)

注意:这两个方法是 HTML5 以后新增,也是现在获取元素最常用的方法


完成以下两个功能:


  • 使用 querySelector() 获取元素实现开关灯案例。
  • 使用 querySelectorAll() 遍历页面上所有的 div 并打印出来。

Meta 对象

Meta 对象代表 HTML 的 一个 <meta> 元素。

<meta> 元素可提供有关某个 HTML 元素的元信息 (meta-information),比如描述、针对搜索引擎的关键词以及刷新频率。

Meta 对象属性

W3C: W3C 标准。

属性描述W3C
content设置或返回 <meta> 元素的 content 属性的值。Yes
httpEquiv把 content 属性连接到一个 HTTP 头部。Yes
name把 content 属性连接到某个名称。Yes
scheme设置或返回用于解释 content 属性的值的格式。Yes

标准属性和事件

Meta 对象同样支持标准的 属性 和 事件。

如您还有不明白的可以在下面与我留言或是与我探讨QQ群{{308855039},我们一起飞!

在Web开发中,尤其是在响应式布局设计时,我们常常需要根据HTML元素的尺寸变化来调整页面布局或内容展示。Vue3 提供了强大的响应式机制和Composition API,使得我们可以更灵活地监听并处理DOM元素尺寸的变化。本文将详细介绍如何在Vue3项目中实现这一功能。

一、传统方法:ResizeObserver

ResizeObserver 是浏览器提供的一个API,用于观察目标元素尺寸变化事件,并在其尺寸发生变化时触发回调函数。首先引入 ResizeObserver 并创建一个观察者实例:

import { onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const targetElement=ref(null); // 存储需要监听的DOM元素引用

    let resizeObserver;
    
    // 当组件挂载时创建ResizeObserver实例并开始监听
    onMounted(()=> {
      resizeObserver=new ResizeObserver((entries)=> {
        entries.forEach((entry)=> {
          console.log('Element size changed:', entry.contentRect.width, entry.contentRect.height);
          // 在这里执行相应的逻辑处理
        });
      });

      if (targetElement.value) {
        resizeObserver.observe(targetElement.value);
      }
    });

    // 组件卸载时停止监听
    onUnmounted(()=> {
      if (resizeObserver && targetElement.value) {
        resizeObserver.unobserve(targetElement.value);
      }
    });

    return {
      targetElement,
    };
  },
};

在模板中,绑定目标元素到 targetElement ref:

<div ref="targetElement">需要监听大小变化的元素</div>

二、结合Vue3的响应式优势

为了更好地与Vue3的数据响应性相结合,我们可以利用Ref或者Computed属性来存储和更新元素尺寸信息:

import { ref, computed, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const targetElement=ref(null);
    const elementSize=ref({ width: 0, height: 0 });

    let resizeObserver;

    onMounted(()=> {
      resizeObserver=new ResizeObserver((entries)=> {
        const entry=entries[0];
        elementSize.value={
          width: entry.contentRect.width,
          height: entry.contentRect.height,
        };
      });

      if (targetElement.value) {
        resizeObserver.observe(targetElement.value);
      }
    });

    onUnmounted(()=> {
      if (resizeObserver && targetElement.value) {
        resizeObserver.unobserve(targetElement.value);
      }
    });

    // 创建一个计算属性以返回最新尺寸信息
    const reactiveElementSize=computed(()=> elementSize.value);

    return {
      targetElement,
      reactiveElementSize,
    };
  },
};

现在你可以在其他组件内部使用 reactiveElementSize 计算属性来获取实时的元素尺寸数据,并据此做出相应布局调整。

在上述代码示例中,elementSize 用于存储元素的尺寸信息(宽度和高度),我们使用了 ref 来定义它。然而,如果你希望 elementSize 对象本身具有响应性,即当对象内部的属性发生变化时也能触发视图更新,那么使用 reactive 可能会更合适。

import { ref, reactive, onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const targetElement=ref(null);
    // 使用reactive创建响应式对象
    const elementSize=reactive({ width: 0, height: 0 });

    let resizeObserver;

    onMounted(()=> {
      resizeObserver=new ResizeObserver((entries)=> {
        const entry=entries[0];
        // 直接修改响应式对象内部属性
        elementSize.width=entry.contentRect.width;
        elementSize.height=entry.contentRect.height;
      });

      if (targetElement.value) {
        resizeObserver.observe(targetElement.value);
      }
    });

    onUnmounted(()=> {
      if (resizeObserver && targetElement.value) {
        resizeObserver.unobserve(targetElement.value);
      }
    });

    return {
      targetElement,
      elementSize,
    };
  },
};

在这种情况下,因为 elementSize 是一个由 reactive 创建的响应式对象,所以在其内部属性 width 和 height 发生变化时,依赖这些值的组件也会自动重新渲染,无需额外的操作。

需要注意的是,在实际应用中,如果只是简单的尺寸数值,使用 ref 足以满足需求,因为 ref 的 .value 属性本身就是响应式的。而 reactive 更适用于需要整个对象结构都具有响应性的场景。

三、总结

Vue3 的 Composition API 结合浏览器原生的 ResizeObserver 可以为我们在监听HTML元素尺寸变化上提供强大而灵活的支持。通过这样的方式,开发者可以轻松应对各种复杂的响应式布局需求,为用户带来更好的交互体验。同时,借助Vue3的数据响应性和自动更新机制,能够在元素尺寸变化时及时刷新视图,保持UI状态与实际DOM的一致性。