7.dom 核心

252 阅读10分钟

web api概述

标准库:ECMAScript中的对象和函数

Web Api:浏览器宿主环境中的对象和函数

  1. 知识繁杂
  2. 成体系的知识
  3. 程序思维:知识+程序思维 = 应用
  4. 兼容性:了解,不记忆

Web Api:

  • BOM:Browser Object Model,浏览器对象模型
  • DOM:Document Object Model,文档对象模型

BOM:控制浏览器本身 DOM:控制HTML文档

ES 由 ECMAScript 规定的 WebApi 由 W3C(万维网联盟) 制定

关于DOM

  • DOM 0
  • DOM 1
  • DOM 2
  • DOM 3
  • DOM 4 2015年

DOM是什么

DOM的核心理念,是将一个HTML或XML文档,用对象模型表示,每个对象称之为dom对象

dom对象又称之为节点Node

节点的类型:

  • DocumentType,文档类型节点
  • Document,文档节点,表示整个文档
  • Comment,注释节点
  • Element,元素节点
  • Text,文本节点
  • Attribute,属性节点
  • DocumentFragment,文档片段节点

dom树:文档中不同的节点形成的树形结构。

下面是文档和对应的dom树。

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

<head>
    <meta charset="UTF-8">
    <title>标题</title>
</head>

<body>
    <!-- 注释 -->
    <p>lorem</p>
</body>

</html>

image.png

获取dom节点

获取dom对象

全局对象 window 中有属性document,代表的是整个文档节点

旧的获取元素节点的方式

dom 0

  • document.body:获取body元素节点
  • document.head:获取head元素节点
  • document.links:获取页面上所有的超链接元素节点,类数组
  • document.anchors:获取页面上所有的锚链接(具有name属性)元素节点
  • document.forms:获取页面中所有的form元素节点

新的获取元素节点的方式

通过方法获取

  • document.getElementById:通过id获取对应id的元素
  • document.getElementsByTagName: 通过元素名称获取元素
  • document.getElementsByClassName:通过元素的类样式获取元素,IE9以下无效
  • document.getElementsByName:通过元素的name属性值获取元素
  • document.querySelector:通过CSS选择器(以字符串的形式传入选择器)获取元素,得到匹配的第一个,IE8以下无效.注意这里,除了可以使用document调用querySelector,还可以使用某个元素querySelector,这代表的是从他的后代元素里面用选择器去选中某个元素。
element = baseElement.querySelector(selectors);
// 从divCenter选择data-myplugin-id 属性 = cancle的元素
btnCancel = divCenter.querySelector("[data-myplugin-id=cancel]")
  • document.querySelectorAll:通过CSS选择器(以字符串的形式传入选择器)获取元素,得到所有匹配的结果,IE8以下无效
  • document.documentElement: 获取根元素

细节:

  1. 在所有的得到类数组的方法中,除了querySelectorAll,其他的方法都是实时更新的。
  2. getElementById 得到元素执行效率最高。
  3. 书写了id的元素,会自动成为window对象的属性。它是一个实时的单对象。事实上的标准。不推荐使用。
<input type="text" id="txt1">

txt1.oninput = txt2.oninput = function(e) {
            if (!this.value.trim()) {
                console.log("请输入内容");
                return;
            }
            console.log(this.value, e.bubbles);
        }

其实就是说,如果你声明了一个id的元素,他会成为window的一个单对象,可以在一些特别小的系统里面使用txt1去获取dom元素。在一些大的系统里面使用已经不合适,他会因为挂在window里面导致一系列的问题,尽量不要去用。

  1. getElementsByTagName、getElementsByClassName、querySelector、querySelectorAll,可以作为其他元素节点对象的方法使用
  2. 最常用的是getElementById,querySelector,querySelectorAll的这个三个,getElementsByTagName偶尔会用一下。

根据节点关系获取节点

  • parentNode:获取父节点(元素、文档)
  • previousSibling:获取上一个兄弟节点
  • nextSibling:获取下一个兄弟节点
  • childNodes:获取所有的子节点
  • firstChild:获取第一个子节点,是他的孩子节点,它本身的属性节点不是。
  • lastChild:获取最后一个子节点
  • attributes: 获取某个元素的属性节点

节点的API用的少是因为对于HTML来说,节点有可能是空白文本等这些,当我们发布代码的时候使用压缩工具,压缩一下代码,代码的执行可能就出问题了

特别需要注意的一个元素节点也属于节点,只是节点的一种情况而已,所以上面的节点的所有方法,元素节点都可以使用 打印节点对象,就是将节点对象里面的内容完全输出,比方说div,他就会将div 标签里面的内容输出

获取元素节点

  • parentElement:获取父元素
  • previousElementSibling:获取上一个兄弟元素
  • nextElementSibling:获取下一个兄弟元素
  • children:获取子元素,特别注意这个名字,没有带Element,也是获取的是子元素。
  • firstElementChild:获取第一个子元素
  • lastElementChild:获取最后一个子元素

获取节点和获取元素的API,大部分只是多了一个Element而已,特别需要注意的是children 这个情况,是获取子元素。

获取节点信息

  • nodeName:获取节点名称
  • nodeValue:获取节点的值
  • nodeType:节点类型,是一个数字

这里重点记录下nodeName,nodeValue,nodeType这三个值。

每个节点都有一个 nodeType 属性,用于表明节点的类型,节点类型由 Node 类型中定义12个常量表示: Snip20231215_3.png

nodeName 属性 要了解节点的具体信息,可以使用 nodeName 和 nodeValue 这两个属性。这两个属性的值完全取决于节点的类型。

一般来说: 元素节点的 nodeName 是标签名称(大写)

属性节点的 nodeName 是属性名称

文本节点的 nodeName 永远是 #text

文档节点的 nodeName 永远是 #document

nodeValue 属性

  • 对于文本节点,nodeValue 属性包含文本。
  • 对于属性节点,nodeValue 属性包含属性值。
  • 文档节点和元素节点,nodeValue 属性的值始终为 null

dom元素操作

初识元素事件

元素事件:某个元素发生一件事(被点击 click)

事件处理程序:是一个函数,发生了一件事,应该做什么事情

注册事件:将事件处理程序与某个事件关联

this关键字在事件处理程序中指代当前发生的事件元素

有点像iOS里面的按钮的点击事件就把按钮传过来的思路是一样的。

获取和设置元素属性

  • 通用方式:getAttribute、setAttribute 正常的属性不建议使用上面的,有很多问题,自定义属性可以用。

可识别属性

正常的HTML属性

  • dom对象.属性名:推荐

细节:

  1. 正常的属性即使没有赋值,也有默认值
<input type="text">
var input = document.querySelector("input[type=text]");
console.log(input.value);

此时input 的value没有赋值,获取的也是默认空的字符串。

  1. 布尔属性在dom对象中,得到的是boolean
<input type="checkbox" checked="checked">

上面的checked是bool属性,获取的是bool值,如果写checked="checked",那么得到的就是true,否则是false。

  1. 某些表单元素可以获取到某些不存在的属性
<select class="ssss">
        <option value="chengdu">成都</option>
        <option value="beijing">北京</option>
        <option value="haerbin">哈尔滨</option>
    </select>

由于select 默认情况是没有value这个属性,但是dom操作的时候提供了select这个属性。 image.png

 <textarea>
            啊手动阀手动阀三发射发生
 </textarea>

类似上面的情况这里textarea也可以获取value的值

4.select元素的一些操作

<select name="" id="sel">
        <option value="1">Lorem.</option>
        <option value="2">Porro?</option>
        <option value="3">A?</option>
        <option value="4">Ad.</option>
        <option value="5">Voluptates?</option>
        <option value="6">Blanditiis!</option>
        <option value="7">Dicta.</option>
        <option value="8">Illum!</option>
        <option value="9">Sint.</option>
        <option value="10">Sunt.</option>
    </select>
  • 想要获取选中option的value值可以直接使用select的value属性获取即可。
  • 想要获取option里面的文本,可以通过option子元素,去匹配他的value值和option的值是否一致也是可以的,还可以通过option的selected属性为true来判断。还可以通过select的selectedIndex来获取选中的序列。
  • 另外sel还有一个options属性和sel.children获取到的一样。
  • 书写了id的元素,会自动成为window对象的属性。它是一个实时的单对象,因此这里可以sel就是select对象了。
sel.onchange = function() {
            Array.from(sel.children).forEach(function(item){
                console.log(item.selected,item.innerText);
            });
            console.log(sel.value, sel.options[sel.selectedIndex].innerHTML);
        }

5. 某些属性与标识符冲突,此时,需要更换属性名

for

<input id="cbgender" type="checkbox" checked="checked"> <label for="cbgender">男</label>

image.png

class

    <select class="ssss">
        <option value="chengdu">成都</option>
        <option value="beijing">北京</option>
        <option value="haerbin">哈尔滨</option>
    </select>

image.png

自定义属性

HTML5 建议自定义属性使用data-作为前缀

如果遵从HTML5 自定义属性规范,可以使用dom对象.dataset.属性名控制属性

删除自定义属性

  • removeAttribute("属性名");
  • delete dom.dataset.属性名

自定义属性的读取和设置 getAttribute、setAttribute 这个通用方式去设置和获取。 当然也可以使用上面的dom对象.dataset.属性名控制属性

获取和设置元素内容

  • innerHTML:获取和设置元素的内部HTML文本(HTML文本就是说内部的元素)
  • innerText:获取和设置元素内部的纯文本,仅得到元素内部显示出来的文本(如果内部有子元素,这个属性不包括),隐藏的这个方法获取不到。
  • textContent:获取和设置元素内部的纯文本,textContent得到的是内部源代码中的文本

元素结构重构

  • 父元素.appendChild(元素):在某个元素末尾加入一个子元素
  • 父元素.insertBefore(待插入的元素, 哪个元素之前)
  • 父元素.replaceChild(替换的元素, 被替换的元素)

细节:

更改元素结构效率较低,尽量少用。 如果要循环添加元素,可以使用代码片段来解决,可以解决频繁改变元素结构引起的效率问题。

<script>
    var ul = document.getElementById("ul1");
    var frag = document.createDocumentFragment();
    for (var i = 1; i <= 100; i++) {
        var li = document.createElement("li");
        li.innerText = "选项" + i;
        frag.appendChild(li);
    }

    ul.appendChild(frag);
</script>

创建和删除元素

创建元素

  • document.createElement("元素名"):创建一个元素对象 image.png

  • document.createTextNode("文本")

  • document.createDocumentFragment(): 创建文档片段

 var ul = document.getElementById("ul1");
        var frag = document.createDocumentFragment();
        for (var i = 1; i <= 100; i++) {
            var li = document.createElement("li");
            li.innerText = "选项" + i;
            frag.appendChild(li);
        }

        ul.appendChild(frag);
  • dom对象.cloneNode(是否深度克隆):复制一个新的dom对象并返回
  • 什么算深度克隆呢?这里clone必然会产生了一个新的dom对象,并且里面包含了dom对象的自带的一些属性,但是被clone对象里面的子对象还有自己又写的属性,都不会clone。深度克隆就会将里面的也clone了。

实时集合

何为实时集合,实时集合就是说方法调了一次获取以后,比方说这个childNodes来说,我们一个变量引用着这个集合,而操作后系统内部又把这个集合进行了增加或者删除,最后我们这个变量实际是指向的这个集合,再去读的时候自然是变化的。 而非实时集合,说明的得到结果是克隆了一个新的组合出来,增加和删除只是修改了原来的组合,这个变量指向的组合和原来的不是同一个对象,自然非实时的。要么就是对节点的操作后并没有去操作数组,再去获取一下,才操作这个数组,也有这个可能。

在所有的得到类数组的方法中,除了querySelectorAll,其他的方法都是实时更新的 重点记忆的就是querySelectorAll获取不是实时更新的,其余的都是实时更新的。

childNodes也是实时集合,

删除元素

  • removeChild:父元素调用,传入子元素
  • remove:把自己删除

dom元素样式

控制dom元素的类样式

  • className: 获取或设置元素的类名
  • classList: dom4的新属性,是一个用于控制元素类名的对象
    • add:用于添加一个类名
    • remove:用于移除一个类名
    • contains:用于判断一个类名是否存在
    • toggle:用于添加/移除一个类名

获取样式

CSS的短横线命名,需要转换为小驼峰命名

  • dom.style:得到行内样式对象
  • window.getComputedStyle(dom元素):得到某个元素最终计算的样式
    • 可以有第二个参数,用于得到某个元素的某个伪元素样式

设置样式

dom.style.样式名 = 值

设置的是行内样式。 上面获取样式的时候有一个计算样式,而这里设置样式只能设置行内样式。计算样式是最后计算的结果,自然无法设置。像外部样式是没办法设置的。而上面的值基本都是字符串。 如果本身是数字的,使用字符串不会出现问题。 详细可以看下面的解释。

image.png