JavaScript — DOM API

x33g5p2x  于2022-02-07 转载在 JavaScript  
字(8.8k)|赞(0)|评价(0)|浏览(562)

前言:
JS 分为三大部分,之前已经学习了ES(基础语法部分),本篇来讨论第二部分:DOM API — 操作页面结构

DOM 概念

DOM (Document Object Model),页面文档对象模型
W3C 标准给我们提供了一系列的函数,让我们可以操作:

  • 网页内容
  • 网页结构
  • 网页样式

DOM 树
一个页面的结构是一个树形结构,称为 DOM 树
相当于 html 树形结构,为一个多子树结构(一个节点下可以有多个);每个节点都可以抽象为一个页面文档的对象

DOM API
即:JS 提供的,操作界面元素(节点)的API

事件

基本概念

JS 及 DOM API,都和事件有关
JS 要构建动态页面,就需要感知到用户的行为;如:用户对于页面的一些操作(点击,选择,修改等) 操作都会在浏览器中产生一个个事件,被 JS 获取到,从而进行更复杂的交互操作

时间三要素

  • 事件源: 由哪个元素触发的;如:用户点了一个按钮,这个按钮就是事件源
  • 事件类型: 用户操作的类型,如:点击,选中,修改…
  • 事件处理程序: 事件发生之后,需要做什么?即: 进一步如何处理,往往是一个回调函数(回调函数,事件发生后,由浏览器自动执行里边的代码)

举例:

  1. <input type="button" value="点我呀" onclick="alert('点就点');">

JS 代码主要流程

写 JS 代码,主要流程:
1.事件源: 学习如何选择页面元素 (DOM API 中,把这些页面元素也称为 DOM 元素)
2.调用 DOM 元素的 API 来做事情
做什么事情?
2.1 设置属性(比如style属性就是样式,on开头的属性就是事件属性)
2.2 设置标签内容

获取页面元素

这部分工作类似于 CSS 选择器的功能

querySelector & querySelectorAll

querySelector

之前的获取元素的方式都比较麻烦,而使用 querySelector 能够完全复用前面学过的 CSS 选择
器知识,可以更快更精准的获取到元素对象

querySelector 调用的节点元素下,去查找满足选择器条件的元素,最后 element 就是选择到的元素
var element = document.querySelector(selectors);
.
document: 页面顶级节点
selectors: 字符串内容,格式和 CSS 一样(CSS 选择器可以获取到哪些元素,querySelector 就可以获取到哪些元素)

总结:

  • selectors 包含一个或多个要匹配的选择器的 DOM字符串 DOMString,该字符串必须是有效的
    CSS选择器字符串;如果不是,则引发 SYNTAX_ERR 异常
  • 表示文档中与指定的一组CSS选择器匹配的第一个元素的 html元素 Element 对象.
  • 如果您需要与指定选择器匹配的所有元素的列表,则应该使用 querySelectorAll()
  • 可以在任何元素上调用,不仅仅是 document;调用这个方法的元素将作为本次查找的根元素
    如:

querySelectorAll

用法和 querySelector 类似

举例:
若选择器返回多个元素,需要使用querySelectorAll,返回的是一个数组,其中包含多个元素

  1. <body>
  2. <p>p1</p>
  3. <p>p2</p>
  4. <p>p3</p>
  5. </body>
  6. <script>
  7. // 如果选择器返回多个元素,需要使用querySelectorAll,返回的是一个数组,其中包含多个元素
  8. var arr = document.querySelectorAll("p");
  9. // 遍历数组
  10. for(let i=0; i<arr.length; i++){
  11. console.log(arr[i]);
  12. }
  13. </script>

操作元素

获取 / 修改元素内容

innerHTML 用的场景比 innerText 更多

innerText

Element.innerText 属性表示一个节点及其后代的"渲染"文本内容
读操作 —— var renderedText = HTMLElement.innerText;
写操作 —— HTMLElement.innerText = string;

举例:

  1. <body>
  2. <div></div>
  3. </body>
  4. <script>
  5. // 给div 添加内容
  6. var div = document.querySelector("div");
  7. div.innerText = "innerText设置内容";
  8. </script>

缺点: 若是修改内容时,带一些 html 的标签作为字符串,此时不会把标签渲染成 html 的元素 (不识别 html 标签)

  1. <script>
  2. var div = document.querySelector("div");
  3. div.innerText = "<span>innerText设置内容</span>";
  4. </script>

由上述例子可以看到,通过 innerText 无法获取到 div 内部的 html 结构,只能得到文本内容; 修改页面的时候也会把 span 标签当成文本进行设置,不会渲染为 html 结构

innerHTML

Element.innerHTML 属性设置或获取HTML语法表示的元素的后代
读操作 —— var content = element.innerHTML;
写操作 —— element.innerHTML = htmlString;

  1. <script>
  2. var div = document.querySelector("div");
  3. div.innerHTML = "<span>innerHTML设置内容</span>";
  4. </script>

通过 innerHTML 获取到的字符串, 不光能获取到页面的 html 结构,同时也能修改结构;并且获取到的内容保留空格和换行

获取 / 修改元素属性

可以通过 Element 对象的属性来直接修改,就能影响到页面显示效果

举例:
console.dir() 表示,将一个对象中的属性、方法打印出来

  1. <body>
  2. <img src="xiawen2.jpg" alt="加载失败" title="哈温呐">
  3. </body>
  4. <script>
  5. var img = document.querySelector("img");
  6. console.dir(img);
  7. </script>

修改 img 的 src 属性:

  1. <body>
  2. <img src="xiawen2.jpg" alt="加载失败" title="哈温呐">
  3. </body>
  4. <script>
  5. var img = document.querySelector("img");
  6. console.dir(img);
  7. img.src = "xiawen.jpg";
  8. </script>

打开网页的时候,最开始是 xiawen2.jpg,还没有等我们反应过来时,就已经变成了 xiawen.jpg,因为执行的速度非常快

点击图片,切换为另一张图片:

  1. <script>
  2. var img = document.querySelector("img");
  3. img.onclick = function () {
  4. if (img.src.lastIndexOf('xiawen2.jpg') !== -1) {
  5. img.src = './xiawen.jpg';
  6. } else {
  7. img.src = './xiawen2.jpg';
  8. }
  9. }
  10. </script>

获取 / 修改样式属性

CSS 中指定给元素的属性,都可以通过 JS 来修改

行内样式操作
element.style.[属性名] = [属性值];
element.style.cssText = [属性名+属性值];

“行内样式”,通过 style 直接在标签上指定的样式,优先级很高;适用于改的样式少的情况

举例:

  1. <div style="font-size: 20px; font-weight: 700;">一朵花花</div>

点击修改颜色:

  1. // 点击后修改颜色
  2. var div = document.querySelector('div');
  3. div.onclick = function () {
  4. // 获取 div 标签文本颜色
  5. var curColor = div.style.color;
  6. if(curColor == '' || curColor == 'black'){
  7. div.style.color = "red";
  8. }
  9. else{
  10. div.style.color = "black";
  11. }
  12. }

类名样式操作
element.className = [CSS 类名];

修改元素的 CSS 类名,适用于要修改的样式很多的情况

夜间模式切换

  1. <style>
  2. /* 白天模式: 白底黑字 */
  3. .day {
  4. background-color: white;
  5. color: black;
  6. }
  7. /* 黑夜模式: 黑底白字 */
  8. .night {
  9. background-color: black;
  10. color: white;
  11. }
  12. </style>
  1. <body>
  2. <span class="day">花花呀</span>
  3. </body>
  4. <script>
  5. var span = document.querySelector("span");
  6. span.onclick = function(){
  7. //获取当前点击的 class
  8. var cls = span.className;
  9. if(cls == 'day') {
  10. span.className = "night";
  11. }
  12. else{
  13. span.className = "day";
  14. }
  15. }
  16. </script>

由于 class 是 JS 的保留字,所以名字叫做 className

获取 / 修改表单元素属性

表单 (主要是指 input 标签) 的以下属性都可以通过 DOM 来修改

  • value: input 的值
  • disabled:禁用
  • checked:复选框会使用
  • selected:下拉框会使用
  • type:input 的类型(文本,密码,按钮,文件等)

例1 — 切换按钮的文本

  1. <input type="button" id="bf" value="播放">
  2. // 选择按钮元素,绑定点击事件,切换显示的文版内容
  3. var btn = document.querySelector("#bf");
  4. btn.onclick = function(){
  5. var content = btn.value;
  6. if(content == '播放') {
  7. btn.value = '暂停';
  8. }else{
  9. btn.value = '播放';
  10. }
  11. }

例2 — 点击按钮,文本值+1

  1. <input type="text" id="sum" value="0">
  2. <input type="button" id="sum_btn" value="点我+1">
  3. var sum = document.querySelector("#sum");
  4. var sumBtn = document.querySelector("#sum_btn");
  5. sumBtn.onclick = function(){
  6. var count = +sum.value; //返回字符串
  7. console.log(count); // 转换成数值
  8. sum.value = count + 1;
  9. }

例3 — 全选 / 取消全选按钮

在 HTML 中,属性值设为 “checked” 为选中;而在 JS 中,需要设置为 true / false

  1. <input type="checkbox" id="all">全部选中
  2. <input type="checkbox" class="item">艾希
  3. <input type="checkbox" class="item">凯特琳
  4. <input type="checkbox" class="item">VN
  5. // 全部选择 / 取消
  6. var all = document.querySelector("#all");
  7. all.onclick = function(){
  8. //子复选框
  9. var items = document.querySelectorAll(".item");
  10. if(all.checked){
  11. for(item of items){
  12. item.checked = true;
  13. }
  14. }
  15. else{
  16. for(item of items){
  17. item.checked = false;
  18. }
  19. }
  20. }

优化用户体验:

  1. var all = document.querySelector("#all");
  2. var items = document.querySelectorAll(".item");
  3. all.onclick = function(){
  4. console.log(all.checked);
  5. for(item of items){
  6. item.checked = all.checked;
  7. }
  8. }
  9. for(item of items){
  10. item.onclick = function(){
  11. // all 复选框是否被选中
  12. let allChecked = true;
  13. // 所有子复选框是否被选中
  14. for(it of items){
  15. if(!it.checked){
  16. allChecked = false;
  17. }
  18. }
  19. all.checked = allChecked;
  20. }
  21. }

操作节点

新增节点

分成两个步骤

  1. 创建元素节点
  2. 把元素节点插入到 DOM 树中
1.创建元素节点

可以直接在最后的元素后创建

  1. <input type="text" id="content">
  2. <input type="button" id="add" value="内容">
  3. <div id="container">
  4. <h3>内容</h3>
  5. </div>
  6. var add = document.querySelector("#add");
  7. var content = document.querySelector("#content");
  8. var container = document.querySelector("#container");
  9. add.onclick = function(){
  10. // 点击,获取文本框内容
  11. var text = content.value;
  12. // innerHTML ,先获取 container 中的所有元素,在最后添加元素
  13. var html = container.innerHTML;
  14. html += "<p>";
  15. html += text;
  16. html += "</p>";
  17. container.innerHTML = html;
  18. }

但以上修改 container 中的所有内容,效率比较差,已有的标签已经渲染了,重新设置又会再次渲染
可以使用 createElement 方法来创建一个元素
var element = document.createElement(tagName[, options]);

  1. var add = document.querySelector("#add");
  2. var content = document.querySelector("#content");
  3. var container = document.querySelector("#container");
  4. add.onclick = function(){
  5. var text = content.value;
  6. // 方式2
  7. // 创建一个dom元素(<p>),然后添加到 container 中,作为最后一个子节点
  8. var p = document.createElement("p"); // 创建一个元素
  9. p.innerHTML = text;
  10. container.appendChild(p); //添加到dom树形结构中,作为最后一个子节点
  11. }
2.插入节点到 DOM 树中
  • 使用 appendChild 将节点插入到指定节点的最后一个孩子之后
    element.appendChild(aChild)
    .
    DOM 包含的子节点不动,在最后添加 element 节点,效率比较高

仍以上述为例:

  1. container.appendChild(p); —— 添加到dom树形结构中,作为最后一个子节点
  • 使用 insertBefore 将节点插入到指定节点之前
    var insertedNode = parentNode.insertBefore(newNode, referenceNode);
    .
    含义: 在 parentNode 节点中,有一个 insertedNode 的子节点,在这个子节点前,插入一个 newNode 节点

  • insertedNode 被插入节点(newNode)

  • parentNode 新插入节点的父节点

  • newNode 用于插入的节点

  • referenceNode newNode 将要插在这个节点之前

如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾
注意: referenceNode 引用节点不是可选参数

补充:
DOM 对象,其中包含属性:

  • dom.children — 返回 DOM 对象下一级左右的子节点数组
  • dom.parentNode — 返回该 DOM 对象上一级的父节点
  1. <div id="insertBeforeDiv">
  2. <p>11111</p>
  3. <p>22222</p>
  4. <p>33333</p>
  5. <p>44444</p>
  6. </div>
  7. // insertBefore 学习
  8. var insertBeforeDiv = document.querySelector("#insertBeforeDiv");
  9. // 准备要插入的节点
  10. var insertNode = document.createElement("p");
  11. insertNode.innerHTML = "新插入节点";
  12. insertBeforeDiv.insertBefore(insertNode, insertBeforeDiv.children[0]);

如果节点是页面已存在的,就做移动操作

  1. <p id="beInsert">原P标签</p>
  2. <ul>
  3. <li>
  4. <p>p111</p>
  5. </li>
  6. <li>
  7. <p>p222</p>
  8. </li>
  9. </ul>
  10. var beInsert = document.querySelector("#beInsert");
  11. var ul = document.querySelector("ul");
  12. // 构造一个 li 标签
  13. var li = document.createElement("li");
  14. li.appendChild(beInsert); // <li><p>beInsert</p></li>
  15. ul.insertBefore(li,ul.children[0]);

删除节点

使用 removeChild 删除子节点
oldChild = element.removeChild(child);
.
含义: element 作为父节点,删除里边的 child 子节点,返回值 oldChild,作为已经删除的节点,还可以继续使用.
.
① child 为待删除节点
② element 为 child 的父节点
③ 返回值为该被删除节点
④ 被删除节点只是从 dom 树被删除了,但是仍然在内存中,可以随时加入到 dom 树的其他位
置.
⑤ 若 child节点 不是 element 节点的子节点,则该方法会抛出异常

举例: 删除 ul 中的最后一个 li

  1. var last = ul.children[ul.children.length - 1]; // 取最后一个 li 节点
  2. ul.removeChild(last);

相关文章