JavaScript DOM

基础知识

  在书写Js代码之前,一般都会先将HTML代码书写好。

  DOM的全称为Document Object Model即为文档对象模型。

  DOM支持将HTML文档转换为Js的对象进行操作。

文档渲染

  浏览器会将HTML文本内容进行渲染,并生成相应的Js对象,同时会对不符合规则的标签进行处理。

 

  标签修复

  当一个文本只有一段文字而没有任何标签时,浏览器会自动修复,将这段文字放入<body>标签中。

hello,world

image-20200816175641865

  表格处理

  表格<tabel>中不允许有内容,浏览器在渲染过程中会进行处理

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <table>
                放出去吧
                <tbody>
                        <tr>
                                <td>hello,world</td>
                        </tr>
                </tbody>
        </table>
</body>

</html>

image-20200816175949677

  标签移动

  所有的内容都要写在<body>标签中,下面的例子<script>标签写在了<body>标签下方,在渲染时浏览器会自动对它进行移动处理。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <h1>hello,world</h1>
</body>
<script>
        document.querySelector("h1").style.backgroundColor = "red";
</script>

</html>

image-20200816180217089

操纵时机

  浏览器的渲染是自上而下,所以我们在对元素节点进行操纵时应当将<script>标签放在<body>尾步。

  如果放在头部将会导致无法读取到节点对象。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <script>
                document.querySelector("h1").style.backgroundColor = "red";
        </script>
        <h1>hello,world</h1>
</body>


</html>

  异步处理

  如果非要将<script>标签放在上面,可以使用setTimeout来进行异步处理,它会让<script>中代码执行排在同步渲染任务之后。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <script>
                setTimeout(() => {
                        document.querySelector("h1").style.backgroundColor = "red";
                });
        </script>
        <h1>hello,world</h1>
</body>

</html>

  onload

  也可以对window对象使用onload进行事件绑定,onload事件是指目标渲染完成后自动触发的事件。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <script>
                window.onload = () => {
                        document.querySelector("h1").style.backgroundColor = "red";
                }
        </script>
        <h1>hello,world</h1>
</body>

</html>

  defer属性

  将Js代码放入一个外部文件中再使用<script>进行引入。

  对引入的<script>标签设置defer属性后,该<script>标签会延迟加载。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <script src="./test.js" defer></script>
        <h1>hello,world</h1>
</body>

</html>

节点对象

  HTML文档中的任何内容在Js中统称为DOM节点对象Node,既然是对象就包括操纵node的属性和方法。

  所有的Node共有12种类型

  常用根节点为document,标签元素节点,文本节点,注释节点

  节点继承自Node类型,所以有用相同的属性与方法

  documentDOM操作的起点。

节点类型类型代号
元素节点 1
属性节点 2
文本节点 3
CDATA节点 4
实体引用名称节点 5
实体名称节点 6
处理指令节点 7
注释节点 8
文档节点 9
文档类型节点 10
文档片段节点 11
DTD声明节点 12
<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <main id="main">

<!-- 注释节点 --></main>

</body>
<script>

        console.log(document.body.nodeType); // 1 body标签,标签节点

        let main = document.getElementById("main");
        console.log(main.attributes[0].nodeType);  // 2 main标签的id属性也是一个节点。属性节点
        console.log(main.firstChild.nodeType);  // 3 main标签下的第一个子标签 即空白行。文本节点
        console.log(main.lastChild.nodeType);  // 8 main标签下的最后一个子标签 即注释行。 注释节点

        console.log(document.nodeType);  // 9 document也是一个节点。文档节点
        console.log(document.childNodes.item(0).nodeType);  // 10  文档类型节点
        
</script>

</html>

原型链

  对每一种类型的节点进行原型链的攀升,可得到如下结论。

原型说明
Object 根对象
EventTarget 提供事件支持
Node 提供parentNode等节点操作方法
Element 提供getElementsByTagNamequerySelector等方法
HTMLElement 所有元素的基础类,提供classNamenodeName等方法
HTMLHeadingElement Head标题元素类

  以下以元素节点<main>标签为例,它的最终原型对象为ElementTarget.proptrpy

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <main id="main">

<!-- 注释节点 --></main>

</body>
<script>
        let main = document.getElementById("main");
        console.log(main.__proto__);
        console.log(main.__proto__.__proto__);
        console.log(main.__proto__.__proto__.__proto__);
        console.log(main.__proto__.__proto__.__proto__.__proto__);
        console.log(main.__proto__.__proto__.__proto__.__proto__.__proto__);
</script>

</html>

image-20200816184329033

document

  documentwindow对象的属性,是由HTMLDocument类实现的实例。

  document包含 DocumentType(唯一)或 html元素(唯一)或 comment等元素

  document的原型链中也包含Node,所以可以使用有关节点操作的方法如nodeType/nodeName

HTML

  下面将通过使用节点的nodeType属性判断来获取所有的元素节点。

let html = [...document.childNodes].filter((node) => {
  if (node.nodeType === 1) {
    return node
  }
})[0]
console.log(html)

  系统提供了简单的方式来获取html中的所有元素节点。

console.log(document.documentElement)

文档信息

  系统为document对象提供了一些属性,可以快速获取一些常用信息。

属性说明
title 获取和设置当前HTML文档标题
URL 获取当前HTML文档的url
domain 获取当前HTML文档的面域名
referrer 获取当前HTML文档的来源地址

  使用title属性可或获取和设置当前HTML文档标题。

<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>  
        <!-- 相当于会把这里改成 DOM LEARN-->
</head>
<body>
        
</body>
<script>
        console.log(document.title); // Document
        document.title = "DOM LEARN";
        console.log(document.title);
</script>
</html>

  使用URL属性可获取当前HTML文档的url

<script>
        console.log(document.URL); // http://127.0.0.1:5500/1.html
</script>

  使用domain属性可获取当前HTML文档的面域名。

<script>
        console.log(document.domain); // 127.0.0.1
</script>

  使用referrer属性可获取当前HTML文档的来源地址。

<script>
        console.log(document.referrer); 
</script>

节点属性

  不同类型的节点拥有不同属性,下面是节点属性的说明与示例。

nodeType

  每个节点都有nodeType属性,返回节点类型的数值。

节点类型类型代号
元素节点 1
属性节点 2
文本节点 3
CDATA节点 4
实体引用名称节点 5
实体名称节点 6
处理指令节点 7
注释节点 8
文档节点 9
文档类型节点 10
文档片段节点 11
DTD声明节点 12

  nodeType属性基本使用

<script>
        console.log(document.querySelector("h1").nodeType);  // 1
</script>

  使用对象原型进行检测

<script>
        let h1 = document.querySelector("h1"); 
        console.log(h1 instanceof Element);  // true
</script>

 

nodeName

  属性nodeName用于获取节点的名称

  获取值为大写形式

nodeTypenodeName
1 元素名称如DIV
2 属性名称
3 #text
8 #comment
<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <h1>hello,world</h1>
        <h2 class="show">标题</h2>
        <!-- 注释 -->
        文本
</body>
<script>

        let h1 = document.querySelector("h1");
        let h2Attr = document.querySelector("h2").attributes[0];
        let comment = document.body.childNodes[5];
        let text = document.body.childNodes[6];

        // 获取为大写形式

        console.log(h1.nodeName);  // H1
        console.log(h2Attr.nodeName);  // class
        console.log(comment.nodeName);  // #comment
        console.log(text.nodeName);  // #text

        console.log(document.body.nodeName);  // BODY

</script>

</html>

tagName

  nodeName可以获取不限于元素的节点名,tagName仅能用于获取元素节点名称。

  tagName存在于Element类的原型中

  元素上使用tagNamenodeName无异

  获取值为大写形式

<script>
        
        console.log(document.querySelector("h1").tagName);  // H1
        console.log(document.body.tagName); // BODY

</script>

nodeValue

  使用nodeValue属性或data方法获取节点值,也可以使用节点的data属性获取节点内容。

  元素节点获取不到任何值,请注意如果想获取<input>标签中的value不应该使用该属性

nodeTypenodeValue
1 null
2 属性值
3 文本内容
8 注释内容
<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <h1>hello,world</h1>
        <h2 class="show">标题</h2>
        <!-- 注释 -->
        文本
</body>
<script>

        let h1 = document.querySelector("h1");
        let h2Attr = document.querySelector("h2").attributes[0];
        let comment = document.body.childNodes[5];
        let text = document.body.childNodes[6];

        console.log(h1.nodeValue);  // null  元素节点获取不到值
        console.log(h2Attr.nodeValue);  // show
        console.log(comment.nodeValue);  //  注释 
        console.log(text.nodeValue);  // 文本

</script>

</html>

  使用data属性获取节点内容

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <h1>hello,world</h1>
        <h2 class="show">标题</h2>
        <!-- 注释 -->
        文本
</body>
<script>

        let h1 = document.querySelector("h1");
        let h2Attr = document.querySelector("h2").attributes[0];
        let comment = document.body.childNodes[5];
        let text = document.body.childNodes[6];

        console.log(h1.childNodes[0].data);  // hello,world
        console.log(h2Attr.data);  // undefined
        console.log(comment.data);  //  注释 
        console.log(text.data);  // 文本

</script>

</html>

节点选择

  系统提供了丰富的选择节点Node的操作方法

快速获取

  系统针对特定的元素节点提供了快速选择的方式

方法说明
document.documentElement 文档节点即html标签节点
document.body body标签节点
document.head head标签节点
document.links 超链接集合
document.anchors 所有锚点集合
document.forms form表单集合
document.images 图片集合

  返回HTMLCollection节点列表对象

  下面以获取<a>标签举例

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <a href="#">a1</a>
        <a href="#">a2</a>
        <a href="#">a3</a>
</body>
<script>

        let links = document.links;
        console.log(links);  // HTMLCollection(3) [a, a, a]
 
</script>

</html>

getElementById

  使用id进行元素节点是非常方便的选择,它会选择出所有具有id属性的元素节点,但注意id应该是唯一的

  返回单一选中的元素节点

  只能在document对象上使用此方法

  以下示例将展示通过id选择器选择出<main>标签

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <main id="main_1">这是一个main标签</main>
</body>
<script>
        let main = document.getElementById("main_1");
        console.log(main); // <main id="main-1">这是一个main标签</main>
</script>

</html>

  拥有标准属性id的元素可做为window对象的属性进行访问,但注意不要与变量名进行重合,所以不推荐这种方式。

  这也是为什么推荐在为标签id属性取名的时候用-进行分割而不是用_进行分割的原因。

<script>
        console.log(main_1);  // <main id="main_1">这是一个main标签</main>
</script>

  getElementById只能通过document进行调用,不能通过元素读取拥有id的子元素,下面的操作将产生错误。

  这是因为该方法是存在于document对象的原型中,而并不存在于任何节点元素的原型链上。

<script>

        let main = document.getElementById("main_1");
        main.getElementById("div-1");

        // Uncaught TypeError: main.getElementById is not a function

</script>

getElementByName

  使用getElementByName获取设置了name属性的元素,虽然在div等元素上同样有效,但一般用来对表单元素进行操作时使用。

  返回NodeList节点列表对象

  NodeList顺序为元素在文档中的顺序

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div name="username">这是普通的div哦</div>
        <form action="#">
                <input type="text" name="username" />
                <input type="password" name="pwd" />
                <button type="button" value="提交"></button>
        </form>
</body>
<script>

        let nameList = document.getElementsByName("username");
        console.log(nameList);  // NodeList(2) [div, input]
        
</script>

</html>

getElementsByTagName

  使用getElementsByTagName用于按标签名获取元素

  返回HTMLCollection节点列表对象

  不区分大小的获取

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div name="username">这是普通的div哦</div>
        <form action="#">
                <input type="text" name="username" />
                <input type="password" name="pwd" />
                <button type="button" value="提交"></button>
        </form>
</body>
<script>

        let tagNameList = document.getElementsByTagName("input");
        console.log(tagNameList); // HTMLCollection(2) [input, input, username: input, pwd: input]

</script>

</html>

  通配符

  可以使用通配符 * 获取所有元素

<script>

        let tagList = document.getElementsByTagName("*");
        console.log(tagList); // HTMLCollection(13) [html, head, meta, meta, title, body, div, form, input, input, button, script, script, viewport: meta, username: div, pwd: input]

</script>

  某个元素也可以使用通配置符*获取后代元素,下面获取 idmain-1的所有后代元素

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <main id="main-1">
                <nav>导航</nav>
                <header>头部</header>
                <article>主题</article>
                <footer>尾部</footer>
        </main>
</body>
<script>

        let main = document.getElementById("main-1");
        let tagList = main.getElementsByTagName("*");
        console.log(tagList);  // HTMLCollection(4) [nav, header, article, footer]

</script>

</html>

getElementsByClassName

  getElementsByClassName用于按class样式属性值获取元素集合

  返回HTMLCollection节点列表对象

  设置多个值时顺序无关,只包含这些class属性的元素

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.getElementsByClassName("show");
        console.log(showClassList);  // HTMLCollection(3) [div.show, div.show, div.show]

</script>

</html>

样式选择器

  在CSS中可以通过样式选择器修饰元素样式,在DOM操作中也可以使用这种方式查找元素。使用过jQuery库的朋友,应该对这种选择方式印象深刻。

  使用getElementsByTagName等方式选择元素不够灵活,建议使用下面的样式选择器操作,更加方便灵活

querySelectorAll

  使用querySelectorAll根据CSS选择器获取Nodelist节点列表

  返回NodeList节点列表对象

  该NodeList节点列表是静态的,添加或删除元素后不变

  获取idmain-1classshowdiv标签

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <main id="main-1">
                <div>不是我</div>
                <div class="show">是我</div>
                <div class="show">是我</div>
                <div>不是我</div>
                <article class="show">不是我</article>
                <article class="show">不是我</article>
        </main>
</body>
<script>

        let divList = document.querySelectorAll("#main-1 div.show")
        console.log(divList);  // NodeList(2) [div.show, div.show]

</script>

</html>

  获取所有属性中含有bgdiv标签

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div bg="red"></div>
        <div></div>
        <div bg="green"></div>
        <article bg="#fff"></article>
        <div></div>
</body>
<script>

        let divList = document.querySelectorAll("div[bg]")
        console.log(divList);  // NodeList(2) [div, div]

</script>

</html>

querySelector

  querySelector使用CSS选择器获取一个元素,下面是根据属性获取单个元素

  返回单一选中的元素节点

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div bg="red"></div>
        <div></div>
        <div bg="green"></div>
        <article bg="#fff"></article>
        <div></div>
</body>
<script>

        let divList = document.querySelector("div[bg]");
        console.log(divList);  // <div bg="red"></div>

</script>

</html>

matches

  用于检测元素是否可以被指定的样式选择器所匹配。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div bg="red"></div>
        <div></div>
        <div bg="green"></div>
        <article bg="#fff"></article>
        <div></div>
</body>
<script>

        let eleList = document.getElementsByTagName("*");  // 拿到所有元素节点

        Array.prototype.forEach.call(eleList,((ele) => {
                console.log(ele.matches("[bg]"));  // 验证是否有属性bg
        }));

        // 6 false
        // true
        // false
        // 2 true
        // 3 false

</script>

</html>

closest

  查找最近的符合选择器的祖先元素(包括自身)。

  找祖先,看最近的祖先能不能被选择器选中,如果不能继续向上找。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>

        <main class="show">
                <div class="hidden">
                        <article class="float"></article>
                </div>
        </main>

</body>
<script>

        let floatEle = document.querySelector(".float");

        console.log(floatEle.closest(".show"));  // 找到main标签

</script>

</html>

关系获取

节点关系

  节点是根据HTML内容产生的,所以也存在父子、兄弟、祖先、后代等节点关系。

  注意:文本节点和注释节点也在节点关系之中

节点属性说明
childNodes 获取所有子节点
parentNode 获取父节点
firstChild 子节点中第一个
lastChild 子节点中最后一个
nextSibling 下一个兄弟节点
previousSibling 上一个兄弟节点

  获取所有子节点(换行也包括其中)

<body>
        <main>
                文本
                <div>div标签</div>
                <article>article标签</article>
                <!-- 注释 -->
        </main>
</body>
<script>

        let main = document.querySelector("main");
        let mainChild = main.childNodes;
        console.log(mainChild);

        // NodeList(7) [text, div, text, article, text, comment, text]

</script>

  获取父节点(文本节点不能作为父节点)

<body>
        <main>
                文本
                <div>div标签</div>
                <article>art<aside>找爸爸</aside>icle标签</article>
                <!-- 注释 -->
        </main>
</body>
<script>

        let aside = document.querySelector("aside");
        console.log(aside.parentNode);

        /*

        <article>
                art<aside>找爸爸</aside>icle标签
        </article>

        */
        
</script>

元素关系

  使用childNodes等获取的节点包括文本与注释,但这不是我们常用的,系统也提供了只操作元素的关系 方法。

节点属性说明
parentElement 获取父元素
children 获取所有子元素
childElementCount 子标签元素的数量
firstElementChild 第一个子标签
lastElementChild 最后一个子标签
previousElementSibling 上一个兄弟标签
nextElementSibling 下一个兄弟标签

  获取所有子元素

<body>
        <main>
                文本
                <div>div标签</div>
                <article>article标签</article>
                <!-- 注释 -->
        </main>
</body>
<script>

        let main = document.querySelector("main");
        let mainChildElement = main.children;
        console.log(mainChildElement);

        // HTMLCollection(2) [div, article]

</script>

  获取父元素

<body>
        <main>
                文本
                <div>div标签</div>
                <article>art<aside>找爸爸</aside>icle标签</article>
                <!-- 注释 -->
        </main>
</body>
<script>

        let aside = document.querySelector("aside");
        console.log(aside.parentElement);

        /*

        <article>
                art<aside>找爸爸</aside>icle标签
        </article>

        */
</script>

节点集合

  NodeListHTMLCollection都是包含多个节点标签的集合,大部分功能也是相同的

  getElementsBy...等方法返回的是HTMLCollection

  querySelectorAll返回的是 NodeList

  NodeList节点列表是动态的,即内容添加后会动态获取

<script>

        let divList1 = document.querySelectorAll("div");
        console.log(divList1);  // NodeList(3) [div, div, div]
        
        let divList2 = document.getElementsByTagName("div");
        console.log(divList2);  // HTMLCollection(3) [div, div, div]

</script>

length

  NodeListHTMLCollection包含length属性,记录了节点元素的数量

<script>

        let divList = document.querySelectorAll("div");
        console.log(divList.length);  // 3

</script>

转换数组

  想要将nodeList或者HTMLCollection转换为Array调用其下的方法可使用以下三种方式

  1.不转换数组而使用call()方法进行方法借用

  2.使用Array.from()将其转换为Array

  3.使用...将其转换为Array

  以下示例将展示使用call()方法进行方法借用

<script>

        let divList = document.querySelectorAll("div");  // nodeList 不具有map方法。

        Array.prototype.map.call(divList, (ele) => { 
                console.log(ele);
        })

</script>

  以下示例将展示使用Array.from()nodeList转换为Array

<script>

        let divList = document.querySelectorAll("div");  // nodeList 不具有map方法。

        Array.from(divList).map((ele)=>{
                console.log(ele);
        })

</script>

  以下示例将展示使用...语法将nodeList转换为Array

<script>

        let divList = document.querySelectorAll("div");  // nodeList 不具有map方法。

        [...divList].map((ele)=>{
                console.log(ele);
        })

</script>

item

  NodelistHTMLCollection提供了item()方法来根据索引获取元素

<script>

        let divList = document.querySelectorAll("div"); 

        console.log(divList.item(0)); 
        // 效果相同
        console.log(divList[0]);  

</script>

namedItem

  HTMLCollection具有namedItem方法可以按nameid属性来获取元素

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div name="d1">1</div>
        <div id="d2">2</div>
        <div>3</div>
</body>
<script>

        let divList = document.getElementsByTagName("div");   // 必须是HTMLcollection类型才行。nodeList不支持

        console.log(divList.namedItem("d1"));  // <div name="d1">1</div>
        console.log(divList.namedItem("d2"));  // <div id="d2">2</div>
 
</script>

</html>

  也可以使用数组或属性的方式来取

<script>

        let divList = document.getElementsByTagName("div"); 

        console.log(divList["d1"]);  // <div name="d1">1</div>
        console.log(divList.d2);  // <div id="d2">2</div>
 
</script>

动态与静态

  使用NodeList获取的标签集合如果页面中新增了一个同类型标签会进行动态映射。

  而HTMLCollection标签集合则没有这种特性。

  注意:querySelectAllNodeList是静态的。

  动态特性

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div name="show">div1</div>
        <div name="show">div2</div>
        <div name="show">div3</div>
</body>
<script>

        let divList = document.getElementsByName("show");
        console.log(divList.length);   // 3

        let newDiv = document.createElement("div");  // 创建标签
        newDiv.innerText = "div4";  // 设置文本内容
        newDiv.setAttribute("name","show");  // 设置属性

        document.body.append(newDiv);  
        console.log(divList.length);  // 4

</script>

</html>

  querySelectAllNodeList是静态的。

<body>
        <div name="show">div1</div>
        <div name="show">div2</div>
        <div name="show">div3</div>
</body>
<script>

        let divList = document.querySelectorAll("[name=show]");
        console.log(divList.length);   // 3

        let newDiv = document.createElement("div");  // 创建标签
        newDiv.innerText = "div4";  // 设置文本内容
        newDiv.setAttribute("name","show");  // 设置属性

        document.body.append(newDiv);  //  新增的div4并没有被动态映射
        console.log(divList.length);  // 3

</script>

集合遍历

  尽管可以使用for/in进行遍历,但是并不推荐使用它。

  因为它会将该集合中可调用的属性遍历出来,而不仅仅是只遍历出元素本身。

for

  节点集合对象不论是NodeList还是HTMLCollection对象都具有length属性,因此可以对其进行遍历操作。

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.getElementsByClassName("show");
        for (let i = 0; i < showClassList.length; i++) {
                console.log(showClassList[i]);  // 只取出元素
        }

</script>

for/of

  节点的集合对象均可使用for/of进行遍历操作。

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.getElementsByClassName("show");
        for (let ele of showClassList) {
                console.log(ele);  // 只取出元素
        }

</script>

forEach

  NodeList节点列表也可以使用forEach来进行遍历,但HTMLCollection则不可以。

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.querySelectorAll(".show");
        showClassList.forEach((ele, index) => {  // 第三个参数为遍历的对象本身
                console.log(ele);  // 元素本身
                console.log(index);  // index索引  
        })

</script>

map

  虽然NodeListHTMLCollection本身并不提供map方法进行遍历,但是我们可以通过方法借用或数组转换实现。

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.querySelectorAll(".show");
        Array.prototype.map.call(showClassList,(ele, index,list) => {  // 第三个参数为遍历的对象本身
                console.log(ele);  // 元素本身
                console.log(index);  // index索引  
        })

</script>

Array.from

  Array.from用于将类数组转为组件,并提供第二个迭代函数。所以可以借用Array.from实现遍历

<body>
        <div class="show"></div>
        <div class="show"></div>
        <div class="show"></div>
</body>
<script>

        let showClassList = document.querySelectorAll(".show");
        Array.from(showClassList,(ele, index) => {  
                console.log(ele);  // 元素本身
                console.log(index);  // index索引  
        })

</script>

创建节点

createTextNode

  创建一个文本对象

<body>
        <div></div>
</body>
<script>

      let text = document.createTextNode("这是一个div");
      let div = document.querySelector("div");

      div.append(text);

</script>

createElement

  创建一个标签对象

<script>

        let div = document.createElement("div");
        div.style.width = "50px";
        div.style.height = "50px";
        div.style.background = "red";
        document.body.append(div);

</script>

  使用Promise结合节点操作来加载外部JavaScript文件

function js(file) {
  return new Promise((resolve, reject) => {
    let js = document.createElement('script')
    js.type = 'text/javascript'
    js.src = file
    js.onload = resolve
    js.onerror = reject
    document.head.appendChild(js)
  })
}

js('1.js')
  .then(() => console.log('加载成功'))
  .catch((error) => console.log(`${error.target.src} 加载失败`))

  使用同样的逻辑来实现加载CSS文件

function css(file) {
  return new Promise((resolve, reject) => {
    let css = document.createElement('link')
    css.rel = 'stylesheet'
    css.href = file
    css.onload = resolve
    css.onerror = reject
    document.head.appendChild(css)
  })
}
css('1.css').then(() => {
  console.log('加载成功')
})

createDocumentFragment

  使用createDocumentFragment创建虚拟的节点容器

  创建的节点的parentNodenull

  使用createDocumentFragment创建的节点来暂存文档节点

  createDocumentFragment创建的节点添加到其他节点上时,会将子节点一并添加

  createDocumentFragment是虚拟节点对象,不直接操作DOM所以性能更好

  在排序/移动等大量DOM操作时建议使用createDocumentFragment

  如果将该容器节点添加到页面中,将不会进行显示

cloneNode&importNode

  使用cloneNodedocument.importNode用于复制节点对象操作

  cloneNode是节点方法

  cloneNode参数为true时递归复制子节点即深拷贝

  importNodedocumet对象方法

  使用cloneNode克隆节点且参数为true时会将原标签的事件等也一同进行拷贝。

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div onclick="show(this,event)" style="width: 100px;height: 100px;background: red;" ></div>
</body>
<script>

        function show(ele,event) {
                ele.style.backgroundColor="blue";
        }

        let div = document.querySelector("div");
        document.body.append(div.cloneNode(true));

</script>

</html>

  document.importNode方法是部分IE浏览器不支持的,也是复制节点对象的方法

  第一个参数为节点对象

  第二个参数为true时递归复制

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div onclick="show(this,event)" style="width: 100px;height: 100px;background: red;" ></div>
</body>
<script>

        function show(ele,event) {
                ele.style.backgroundColor="blue";
        }

        let div = document.querySelector("div");
        document.body.append(document.importNode(div,true));

</script>

</html>

节点内容

innerHTML

  inneHTML用于获取标签中的HTML内容,并且也可以向标签中添加HTML内容,同时触发浏览器的解析器重绘DOM。

  下例使用innerHTML获取和设置<div>内容

  innerHTML中只解析HTML标签语法,所以其中的 <script>不会做为Js处理

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div></div>
</body>
<script>

        let div = document.querySelector("div");
        div.innerHTML = "<h1>欢迎学习JavaScript的DOM操作</h1>"
</script>

</html>

outerHTML

  outerHTMLinnerHTML的区别是包含父标签

  outerHTML不会删除原来的旧元素

  只是用新内容替换替换旧内容,旧内容(元素)依然存在

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div><p>旧内容</p></div>
</body>
<script>

        let div = document.querySelector("div");

        console.log(div.outerHTML);  // <div><p>旧内容</p></div>
        console.log(div.innerHTML);  // 不包含自身 <p>旧内容</p>

        div.outerHTML = "<p>欢迎学习JavaScript的DOM操作</p>"   // 将div替换成p

</script>

</html>

innerHTML&textContent

  textContentinnerText是访问或添加文本内容到元素中

  textContentb部分IE浏览器版本不支持

  innerText部分FireFox浏览器版本不支持

  获取时忽略所有标签

  设置时将内容中的标签当文本对待不进行解析

  获取时忽略内容中的所有标签

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
</head>

<body>
        <div><article>外层文本<time>内层文本</time></article></div>
</body>
<script>

        let div = document.querySelector("div");

        console.log(div.innerText);  // 外层文本内层文本
        console.log(div.textContent);  // 外层文本内层文本
 
</script>

</html>

  设置时将标签当文本对待,即转为HTML实体内容

<script>

        let div = document.querySelector("div");
        div.innerText = "<p>不会解析成标签</p>";
 
</script>

outerText

  与innerText差别是会影响所操作的标签,即将标签替换为纯文本。

<script>

        let div = document.querySelector("div");
        div.outerText = "<p>不会解析成标签</p>";
 
</script>

节点管理

  包括添加、删除、替换等操作

推荐方法

方法说明
append 节点内部的尾部追加新节点或字符串
prepend 节点内部的头始插入新节点或字符串
before 节点同级的前面插入新节点或字符串
after 节点同级的后面追加新节点或字符串
replaceWith 将节点替换为新节点或字符串

  节点内部的尾部追加新节点或字符串

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.append(article);

        /* 
        
        <div>
                <p>原本内容</p>
                <article>新内容</article>
        </div>
        
        */

</script>

  节点内部的头始插入新节点或字符串

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.prepend(article);

        /*
        
        <div>
                <article>新内容</article>
                <p>原本内容</p>
        </div> 
        
        */

</script>

  节点同级的前面插入新节点或字符串

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.before(article);

        /*
        
        <article>新内容</article>
        <div>
                <p>原本内容</p>
        </div> 
        
        */

</script>

  节点同级的后面追加新节点或字符串

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.after(article);

        /*

        <div>
                <p>原本内容</p>
        </div> 
        <article>新内容</article>
        
        */

</script>

  将节点替换为新节点或字符串

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.replaceWith(article);

        /*

        <article>新内容</article>
 
        */

</script>

insertAdjacentText

  将文本插入到元素指定位置,不会对文本中的标签进行解析,包括以下位置

选项说明
beforebegin 元素本身前面
afterend 元素本身后面
afterbegin 元素内部前面
beforeend 元素内部后面

  将文本内容添加到元素本身前面

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        div.insertAdjacentText("beforebegin","<p>新内容</p>"); // 不会解析成标签

        /*

        <p>新内容</p>
        <div>
                <p>原本内容</p>
        </div>
 
        */

</script>

insertAdjacentHTML

  将HTML文本插入到元素指定位置,浏览器会对文本进行标签解析,包括以下位置

选项说明
beforebegin 元素本身前面
afterend 元素本身后面
afterbegin 元素内部前面
beforeend 元素内部后面

  将HTML文本添加到元素本身前面

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        div.insertAdjacentHTML("beforebegin","<p>新内容</p>"); // 会解析成标签

        /*

        <p>新内容</p>
        <div>
                <p>原本内容</p>
        </div>
 
        */

</script>

insertAdjacentElement

  insertAdjacentElement() 方法将指定元素插入到元素的指定位置,包括以下位置

选项说明
beforebegin 元素本身前面
afterend 元素本身后面
afterbegin 元素内部前面
beforeend 元素内部后面

  将<article>标签添加到元素本身前面

<body>
        <div><p>原本内容</p></div>
</body>
<script>

        let div = document.querySelector("div");
        let article = document.createElement("article");
        article.innerText = "新内容";
        div.insertAdjacentElement("beforebegin",article);

        /*
        
        <article>新内容</article>
        <div>
                <p>原本内容</p>
        </div> 
        
        */

</script>

古老方法

  下面是过去使用的操作节点的方法,现在不建议使用了。但在阅读老代码时可来此查看语法

方法说明
appendChild 添加节点
insertBefore 用于插入元素到另一个元素的前面
removeChild 删除节点
replaceChild 进行节点的替换操作

标准属性

  元素的标准属性具有相对应的DOM对象属性

  操作属性区分大小写

  多个单词属性命名规则为第一个单词小写,其他单词大写

  属性值是多类型并不全是字符串

  事件处理程序属性值为函数

  style属性为CSSStyleDeclaration对象

  DOM对象不同生成的属性也不同

属性别名

  有些属性名与Js关键词冲突,系统已经起了别名

属性别名
class className
for htmlFor

操纵属性

  元素的标准属性可以直接进行操作,下面是直接设置元素的className

<body>
        <main></main>
</body>
<script>
        
        let main = document.querySelector("main");
        main.className = "show";

</script>

  下面设置图像元素的标准属性

<body>
        <img src="" alt="" />
</body>
<script>

        let img = document.img[0];
        img.src = "./1.png";
        img.alt = "没加载出来...";

</script>

  使用hidden隐藏元素

<body>
        <main>main标签</main>
</body>
<script>

        document.querySelector("main").addEventListener("click", (ele) => {
                ele.target.hidden = true;
        });

</script>

多类型

  大部分属性值是都是字符串,但并不是全部。

  比如checked的值就是Boolean类型

<body>
        <input type="checkbox" name="gender" value="male" checked />
        <input type="checkbox" name="gender" value="female" />
</body>
<script>

        let input = document.getElementsByName("gender").item(0).addEventListener("change", (event) => {
                console.log(event.target.checked);  // 修改事件绑定 查看checked
        })

</script>

  属性值并不都与HTML中的内容相同,下列<a>标签的href属性获取出的就是完整链接

<script>

        let tagA = document.querySelector("a");
        console.log(tagA.href); // http://127.0.0.1:5500/test

</script>

特征属性

  特征属性是指自定义的元素属性,对于标准的属性可以使用DOM属性的方式进行操作,但对于标签的非标准的自定义属性则不可以。但Js提供了相应的操作非标准属性的方式来控制标准或非标准的属性。

  可以理解为元素的属性分两个地方保存,DOM属性中记录标准属性,特征中记录标准和定制属性

  使用特征操作时属性名称不区分大小写

  特征值都为字符串类型

推荐方法

  使用以下方法可以操纵特征属性与标准属性。

方法说明
getAttribute 获取属性
setAttribute 设置属性
removeAttribute 删除属性
hasAttribute 检测某一属性是否存在

  使用getAttribute来获取某一元素的特征属性或标准属性。

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        console.log(eleTag.getAttribute("content"));  // 支持获取特征属性
        console.log(eleTag.getAttribute("class"));  // 支持获取标准属性

</script>

  使用setAttribute来设置某一元素的特征属性或标准属性。

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        eleTag.setAttribute("content","内容区域");  // 支持设置特征属性
        eleTag.setAttribute("class","hidden");  // 支持设置标准属性

</script>

  使用removeAttribute来删除某一元素的特征属性或标准属性。

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        eleTag.removeAttribute("content");  // 支持删除特征属性
        eleTag.removeAttribute("class");  // 支持删除标准属性

</script>

  使用hasAttribute来检测某一元素的特征属性或标准属性是否存在。

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        console.log(eleTag.hasAttribute("content"));  // 支持检测特征属性
        console.log(eleTag.hasAttribute("class"));  // 支持检测标准属性

</script>

  获取到的属性值均为string类型

<body>
        <input type="text" name="age" value="18">
</body>
<script>

        let eleTag = document.querySelector("[name=age]");
        console.log(typeof eleTag.value);  // string

</script>

attributes

  元素提供了attributes属性可以只读的获取元素的属性

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        console.log(eleTag.attributes['content'].nodeValue);  // 内容块
        console.log(eleTag.attributes['class'].nodeValue);  // show

</script>

  attributes属性会返回一个NamedNodeMap的可迭代对象,因此可以对他进行迭代取值的操作。

<body>
        <article content="内容块" color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("[color]");
        for (let attr of eleTag.attributes){
                console.log(attr);
        }

        /*

                content="内容块"
                color="#fff"
                class="show"
        */

</script>

属性集

  如果单纯的对特征属性进行任意命名,可能会和标准属性产生冲突。

  因此可以使用前缀的方式进行特征属性的命名,如data-xxx,针对这种定义方式Js也提供了接口方便操作

  元素中以data-为前缀的属性会添加到属性集中

  使用元素的dataset可获取属性集中的属性

  改变dataset的值也会影响到元素上

  使用dataset属性集

<body>
        <article data-content="内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("article");
        console.log(eleTag.dataset.content); // 内容块

</script>

  以-命名的特征属性,在使用属性集获取时要采用驼峰式命名法获取。

<body>
        <article data-content-top-left="顶部左区域内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("article");
        console.log(eleTag.dataset.contentTopLeft); // 顶部左区域内容块

</script>

  改变dataset值也会影响到页面元素上

<body>
        <article data-content-top-left="顶部左区域内容块" data-color="#fff" class="show">HELLO,WORLD</article>
</body>
<script>

        let eleTag = document.querySelector("article");
        eleTag.dataset.contentTopLeft = "左区域顶部内容块";

</script>

表单控制

表单查找

  Js为表单的操作提供了单独的集合控制

  使用document.forms获取表单集合

  使用formname属性获取指定form元素

  根据表单项的name属性使用form.elements.title获取表单项,

  也可以直接写成form.name形式,不需要form.elements.title

  针对radio/checkbox获取的表单项是一个集合

  使用document.formsform.elements

<body>
        <form action="#" name="register">
                <input type="text" name="username">
                <input type="text" name="pwd">
        </form>
</body>
<script>

        let form = document.forms.register; // 获取到表单
        let formChildren = form.elements;  // 拿到其下所有表单项
        let username = form.elements.username; // 拿到name为username的表单项

        console.log(formChildren);  // HTMLFormControlsCollection(2) [input, input, username: input, pwd: input]
        console.log(username);  // <input type="text" name="username">

</script>

样式管理

  通过DOM修改样式可以通过更改元素的class属性或通过style对象设置行样式来完成。

  建议使用class控制样式,将任务交给CSS处理,更简单高效

classList

  如果对类单独进行控制使用 classList属性操作

方法说明
node.classList.add 添加类名
node.classList.remove 删除类名
node.classList.toggle 切换类名
node.classList.contains 检测元素类名是否存在

  在元素的原有class上添加新class

<body>
        <section class="show left"></section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.classList.add("top");

</script>

  移除原本元素的某个class

<body>
        <section class="show left"></section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.classList.remove("show");
        // <section class="left"></section>

</script>

  将原本元素的某个class切换为另一个class,即类已经存在时删除,不存在时添加

<body>
        <section class="show left"></section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.classList.toggle("show");  // 存在删除
        section.classList.toggle("hidden"); // 不存在添加

        // <section class="left hidden"></section>
        
</script>

  使用contains检查class是否存在

<body>
        <section class="show left"></section>
</body>
<script>
     
        let section = document.querySelector("section");
        let result = section.classList.contains("show"); 
        console.log(result); // true
        
</script>

style&cssText

  使用style可以单独的为某一个元素进行单独的样式设置

  多个单词的属性使用驼峰进行命名,不要使用-进行分割

<body>
        <section>文字</section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.style.color = "blue";
        section.style.backgroundColor = "red";  // background-color 需要改成驼峰体设置 backgroundColor

</script>

  使用cssText属性可以批量设置行样式,属性名和写CSS一样不需要考虑驼峰命名

<body>
        <section>文字</section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.style.cssText = "color:blue;background-color:red;"

</script>

  也可以使用setAttribute批量进行样式设置,属性名和写CSS一样不需要考虑驼峰命名

<body>
        <section>文字</section>
</body>
<script>
     
        let section = document.querySelector("section");
        section.setAttribute("style","color:blue;background-color:red;")

</script>

获取样式

  可以通过style对象,window.window.getComputedStyle对象获取样式属性,下面进行说明

  可以使用DOM对象的style属性读取行样式

  style对象不能获取行样式外定义的样式

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
                section{
                        color: blue;
                }
        </style>
</head>

<body>
        <section style="background-color: red;">文字</section>
</body>
<script>
     
        let section = document.querySelector("section");
        console.log(section.style.backgroundColor); // red
        console.log(section.style.color); // 空白,获取不到

</script>

</html>

  使用window.getComputedStyle可获取所有应用在元素上的样式属性

  函数第一个参数为元素

  第二个参数为伪类

  这是计算后的样式属性,所以取得的单位和定义时的可能会有不同

<!DOCTYPE html>
<html lang="en">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
                section{
                        color: blue;
                        font-size: 18px;
                }
        </style>
</head>

<body>
        <section style="background-color: red;">文字</section>
</body>
<script>
     
        let section = document.querySelector("section");

        let bgColor = window.getComputedStyle(section).backgroundColor;
        console.log(bgColor); // rgb(255, 0, 0)

        let fontColor = window.getComputedStyle(section).color;
        console.log(fontColor); // rgb(0, 0, 255)

        let fontSize = window.getComputedStyle(section).fontSize;
        console.log(fontSize); // 18px

</script>

</html>
posted @ 2020-08-18 15:48  云崖先生  阅读(233)  评论(0编辑  收藏  举报