LOADING

加载过慢请开启缓存 浏览器默认开启

DOM学习

2023/10/25 学习 学习

DOM基础

DOM概述

​       DOM(文档对象模型)是一个网络文档的编程接口,DOM将文档表示为节点和对象,因此编程语言可以和页面交互。

​       网页是既可以在浏览器窗口中显示,又可以作为HTML源代码的文档,用DOM使它可以被操作。

const paragraphs = document.querySelectorAll("p");
//paragraphs[0], paragraphs[1]...
alert(paragraphs[0].nodeName);

​       DOM是使用多个API构建的,核心DOM定义了描述任何文档和其中对象的实体,其他API对其进行扩展。

​       DOM不是一门编程语言,而是用于建立网站的API。所以DOM不一定非要JavaScript才能实现,Python也行

访问DOM

​       可以使用documentwindow对象来操作文档本身

//创造一个新的h1元素,向元素添加文本,再将其添加到文档的树中
<html lang="zh-CN">
  <head>
    <script>
      // 当文档加载时,运行这段函数
      window.onload = () => {
        // 在空 HTML 页面中创建一系列元素
        const heading =	document.createElement("h1");
        const headingText = document.createTextNode("Big Head!");
        heading.appendChild(headingText);
        document.body.appendChild(heading);
      };
    </script>
  </head>
  <body></body>
</html>

基本的数据类型

​       通常把DOM中的节点成为元素,但严格来说不是每个节点都是一个元素。

数据类型描述
Document当一个成员返回 document 对象时,这个对象就是rootdocument 对象本身。参见文章 DOM document 参考
Node位于文档中的每个对象都是某种类型的节点。一个对象可以是一个元素节点,也可以是一个文本节点或属性节点
Element基于Node,指的是一个元素或由DOM API成员返回的element类型的节点
NodeList由元素组成的数组
Attrattribute 通过成员函数返回时,是一个为属性暴露出专门接口的对象引用
NamedNodeMap和数组类似,但是条目是由名称或索引访问的

DOM中的核心接口

示例

设置文本内容

<div class="container">
  <textarea class="story"></textarea>
  <button id="set-text" type="button">设置文本内容</button>
  <button id="clear-text" type="button">清除文本内容</button>
</div>
.container {
  display: flex;
  gap: 0.5rem;
  flex-direction: column;
}

button {
  width: 200px;
}
const story = document.body.querySelector(".story");

const setText = document.body.querySelector("#set-text");
setText.addEventListener("click", () => {
  story.textContent = "It was a dark and stormy night...";
});

const clearText = document.body.querySelector("#clear-text");
clearText.addEventListener("click", () => {
  story.textContent = "";
});

添加子元素

<div class="container">
  <div class="parent">父元素</div>
  <button id="add-child" type="button">添加子元素</button>
  <button id="remove-child" type="button">移除子元素</button>
</div>
.container {
  display: flex;
  gap: 0.5rem;
  flex-direction: column;
}

button {
  width: 100px;
}

div.parent {
  border: 1px solid black;
  padding: 5px;
  width: 100px;
  height: 100px;
}

div.child {
  border: 1px solid red;
  margin: 10px;
  padding: 5px;
  width: 80px;
  height: 60px;
  box-sizing: border-box;
}
const parent = document.body.querySelector(".parent");

const addChild = document.body.querySelector("#add-child");
addChild.addEventListener("click", () => {
  // 只在文本节点“父节点”没有子节点时添加一个子节点
  if (parent.childNodes.length > 1) {
    return;
  }
  const child = document.createElement("div");
  child.classList.add("child");
  child.textContent = "子节点";
  parent.appendChild(child);
});

const removeChild = document.body.querySelector("#remove-child");
removeChild.addEventListener("click", () => {
  const child = document.body.querySelector(".child");
  parent.removeChild(child);
});

实例方法

document.querySelector

概要

​       返回文档中与指定选择器或选择器组匹配的第一个Element对象,找不到返回null。

​       匹配:使用深度优先先序遍历,从文档第一个元素开始按子节点的顺序遍历。

语法

element = document.querySelector(selectors);
/*
    selectors: 包含一个或多个要匹配的选择器的DOM字符串,必须为CSS选择器,否则引发SYNTAX_ERR异常。
    SYNTAX_ERR:指定selectors的语法无效
    CSS伪类不会返回任何元素
*/

示例

//查找第一个匹配.myclass属性的元素
let e1 = document.querySelector(".myclass");

//查找一个元素,该元素是被一个class = "user-panel main"属性的div包裹的name = "login"的input
let e2 = document.querySelector("div.user-panel.main input[name = 'login']");

document.querySelectorAll()

概要

此方法基于ParentNode mixin的querySelectorAll()实现。

​       返回与指定的选择器组匹配的文档中的元素列表,返回NodeList(可以为空)。

​       一旦返回了NodeList,就可以像数组一样使用。

​       匹配:深度优先先序遍历文档节点。

语法

querySelectorAll(selectors)
/*
    selectors: 必须为CSS选择器的字符串,否则引发SyntaxError异常。
    selectors中包含CSS伪元素会始终返回空值。
    SyntaxError:指定的选择器不合法会抛出该错误。
*/

示例

//获取所有p元素
let e = document.querySelectorAll("p");

//获取所有class为note和alert的div元素
let e1 = document.querySelectorAll("div.note", "div.alert");

//获得一个p元素的列表,直接父元素是一个class = "highlighted"的div,位于ID为"test"的容器中
let container = document.querySelector("#test");
let matches = container.querySelectorAll("div.highlighted > p");

//获得文档中属性名为“data-src”的iframe元素列表
let matches = document.querySelectorAll("iframe[data-stc]");

//获得ID为userlist的列表中包含值为1的data-active属性的元素
let container = document.querySelector("#userlist");
let matcher = container.querySelector("li[data-active = '1']");

document.createElement

概要

​       用于创建一个由标签名称tagName指定的HTML元素,如果无法识别该tagName会生成一个未知HTML元素HTMLUnknownElement

​       会返回新建的元素。

语法

var element = document.createElement(tagName[, options]);
/*
    tagName:指定要创建元素类型的字符串
*/

示例

//新建一个新的div并且插入到ID为div1的元素前
document.body.onload = addElement;

function addElement(){
    //创造一个新的div元素
    let newDiv = document.createElement("div");
    //添加内容
    let newtext = document.createTextNode("Hello World!");
    //添加文本节点到这个div元素
    newDiv.appendChlid(newtext);
    
    //获取div1
    let curDiv = document.getElementById("div1");
    //添加到div1的元素前
    document.body.insertBefore(newDiv, curDiv);
}

element.innerHTML

概要

​       设置或获取HTML语法表示的元素的后代。

语法

const content = element.innerHTML;
element.innerHTML = htmlString;
/*
    设置元素的innerHTML将会删除所有该元素的后代并以htmlString替代。
    SyntaxError:HTML没有正确标记时,设置innerHTML将抛出语法错误。
    NoModificationAllowedError:当父元素是Document时设置innerHTML将抛出语法错误。
*/

示例

<div class="box">
        <div><strong>Log:</strong></div>
        <div class="log"></div>
    </div>
.box{
        width: 600px;
        height: 300px;
        border: 1px solid black;
        padding: 2px 4px;
        overflow-y: scroll;
        overflow-x: auto;
}
.log{
        margin-top: 8px;
        font-family: monospace;
}
let s = document.querySelector(".box");
s.addEventListener("click", logEvent);
s.addEventListener("mousedown", logEvent); s.addEventListener("mouseup", logEvent);
s.addEventListener("mouseenter", logEvent);
s.addEventListener("mouseleave", logEvent);

function logEvent(){
    let msg = "Event <strong>" + event.type + "</strong> at <em>" + event.clientX + "," + event.clientY + "</em>";
    log(msg);
 }

function log(msg){
    let a = document.querySelector(".log");
    let time = new Date();
    let timestr = time.toLocaleTimeString();
    a.innerHTML += timestr + ':' + msg +  "<br />";
}
    log("Logging mouse events inside this container...");

element.setAttribute

概要

​       设置指定元素上的某个属性值,若该属性存在则更新该值,否则使用指定的名称和值添加一个新的属性,返回undefined。

语法

element.setAttribute(name, value)
/*
    name:表示属性名称的字符串
    value:属性的值
*/

示例

//为HTML的button设置属性
let b = document.querySelector("button");
b.setAttribute("name", "helloButton");
b.setAttribute("disabled", "");

element.getAttribute

概要

​       返回元素上一个指定的属性值,若指定的属性不存在,返回null""

语法

let attribute = element.getAttribute(attributeName);
/*
    attributeName:你想获取属性值的属性名称。
*/

示例

let div1 = document.getElementById("div1");
let align = div1.getAttribute("align");
alert(align);

EventTarget.addEventListener

概要

​       将指定的监听器注册到EventTarget上,该对象触发指定的事件时,相应的回调函数会被执行,无返回值。

​       EventTarget可以是ElementDocumentWindow和任何支持事件的对象。

使用 addEventListener()的优点:

  • 它允许为一个事件添加多个监听器。特别是对库、JavaScript 模块和其他需要兼容第三方库/插件的代码来说,这一功能很有用。
  • 相比于 onXYZ 属性绑定来说,它提供了一种更精细的手段来控制 listener 的触发阶段。(即可以选择捕获或者冒泡)。
  • 它对任何事件都有效,而不仅仅是 HTML 或 SVG 元素。

原理

​       将EventListener的函数或对象添加到调用它的EventTarget

的事件侦听器列表中,若已被添加则不会重复该操作。

​       当一个EventListener在处理事件时被注册到EventTarget上时,不会被立即触发。

​ 如果先前向事件侦听器列表中添加过一个匿名函数,并且在之后的代码中调用 addEventListener 来添加一个功能完全相同的匿名函数,那么之后的这个匿名函数也会被添加到列表中。

​ 实际上,即使使用完全相同的代码来定义一个匿名函数,这两个函数仍然存在区别,在循环中也是如此。在使用该方法的情况下,匿名函数的重复定义会带来许多麻烦。

语法

addEventLister(type, listener, [options], [useCapture]);
/*
    type:监听类型
    listener:一个实现了EventListener接口的对象,或函数
    options:capture(事件捕获), once(最多只调用一次),passive(不会调用preventDefault), signal(abort()方法被调用时,监听器被移除)
    useCapture:是否要先于它下面的EventTarget调用该Listener(不太懂这个...)
*/

示例

<table id="outside">
  <tr>
    <td id="t1">one</td>
  </tr>
  <tr>
    <td id="t2">two</td>
  </tr>
</table>
/*1.添加一个简单的监听器*/
// 为 table 添加事件监听器
const el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

// 改变 t2 内容的函数
function modifyText() {
  const t2 = document.getElementById("t2");
  const isNodeThree = t2.firstChild.nodeValue === "three";
  t2.firstChild.nodeValue = isNodeThree ? "two" : "three";
}

/*2.添加一个可被移除的监听器*/
// 为 table 添加可被移除的事件监听器
const controller = new AbortController();
const el = document.getElementById("outside");
el.addEventListener("click", modifyText, { signal: controller.signal });

// 改变 t2 内容的函数
function modifyText() {
  const t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue === "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
    controller.abort(); // 当值变为 "three" 后,移除监听器
  }
}

/*3.带有匿名函数的监听器*/
// 改变 t2 内容的函数
function modifyText(new_text) {
  const t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;
}

// 用匿名函数为 table 添加事件监听器
const el = document.getElementById("outside");
el.addEventListener(
  "click",
  function () {
    modifyText("four");
  },
  false,
);

/*4.带有箭头函数的监听器*/
// 改变 t2 内容的函数
function modifyText(new_text) {
  var t2 = document.getElementById("t2");
  t2.firstChild.nodeValue = new_text;
}

// 用箭头函数为 table 添加事件监听器
const el = document.getElementById("outside");
el.addEventListener(
  "click",
  () => {
    modifyText("four");
  },
  false,
);

Node.appendChlid

概要

​       将一个节点附加到指定父节点的子节点列表末尾处。若该节点已经存在,则将其移动到新的位置,返回追加后的子节点。

语法

element.appendChild(aChild)
/*
    aChild:要追加给父节点的节点。
*/

示例

//创造一个新的段落元素p,然后将其添加到body的最尾部
let p = document.createElement("p");
document.body.appendChild(p);

window.onload

概要

​       load事件在整个页面及所有依赖资源都已完全加载时触发。

语法

addEventListener("load", (event) => {});

onload = (event) => {};

示例

windows.addEventListener("load", (event) =>{
   console.log("page is fully loaded"); 
});

windows.onload = (event) => {
   console.log("page is fully loaded"); 
};

window.scrollTo

概要

​       滚动到文档中的某个坐标。

语法

window.scrollTo(x-coord, y-coord);
window.scrollTo(options);
/*
    x-coord:文档的横轴坐标=left
    y-coord:文档的纵轴坐标=top
    options:包含三个属性的对象
*/

示例

window.scrollTo(0, 1000);
//设置滚动行为为平滑的滚动
window.scrollTo({
    top:1000,
    behavior:"smooth"
});