元素Element | 青训营笔记

24 阅读11分钟

8.7 元素Element

8.7.1 元素的标签属性(Attribute)

标签里面的属性称之为Attribute。

浏览器在解析HTML元素时,会将对应的Attribute也创建出来,放在对应的元素对象上。例如:id、class就是全局的Arttribute,会有对应的id、class属性;href属性是针对a元素的;type、value属性是针对input元素的。

  1. 标准属性

像 id、class、href、type、value等由官方提供的标签属性称为标准标签属性。

  1. 非标准属性

自定义的标签属性。

8.7.1.1 标签属性(Attribute)的操作

  1. 属性
  • attributes

    • 描述:返回一个注册到指定节点的所有属性节点的实时集合。该集合是一个 NamedNodeMap 对象,不是 Array,所以它没有 Array 的方法。更确切地说,attributes 是字符串形式的键值对,代表了那个属性的任何信息(name、value)。

    注:

    ①attribute的名字是大小写不敏感的(id与ID相同);

    ②值总是字符串类型。

  1. 通用方法
  • hasAttribute()

    • 语法:var result = element.hasAttribute(attName);
      • result 为返回的布尔值:truefalse
      • attName 是一个字符串,表示属性的名称。
    • 描述:返回一个布尔值,指示该元素是否包含有指定的属性(attribute)。
  • getAttribute()

    • 语法:let attribute = element.getAttribute(attributeName);
      • attribute 是一个包含 attributeName 属性值的字符串。
      • attributeName 是你想要获取的属性值的属性名称。
    • 描述:返回元素上一个指定的属性值。如果指定的属性不存在,则返回 null"" (空字符串)。
  • setAttribute()

    • 语法:element.setAttribute(name, value);
    • 参数(name):表示属性名称的字符串。
    • 参数(value):属性的值/新值。
    • 描述:设置指定元素上的某个属性值。如果属性已经存在,则更新该值;否则,使用指定的名称和值添加一个新的属性。
  • removeAttribute()

    • 语法:element.removeAttribute(attrName);

    • 参数(attrName):要从元素中移除的属性的名称。

    • 描述:从指定的元素中删除一个属性。

    • 返回值:IE 返回 boolean 类型值,其他返回 undefined

    因为 removeAttribute() 不会返回任何有效值,你不能使用链式方法(连续使用方法,例如 document.body.removeAttribute("first").removeAttribute("second")…)连续移除多个属性。

8.7.2 元素的property属性

对象里的属性称为property

标准的标签属性Attribute会在DOM对象上创建与其对应的property属性。

<div class="box" id="ha" age=18 height=1.8>哈哈哈</div>

<script>
    // 获取box元素
    var boxEl = document.querySelector(".box")
    console.log(boxEl.id)       // ha
    console.log(boxEl.age)      // undefined
    console.log(boxEl.height)   // undefined
    
    // 疑问:为什么第12行的的代码输出不是box?因为class属性的property名为idEl.className
    var idEl = document.getElementById("ha")
    console.log(idEl.class)		// undefined
    
    console.log(idEl.idEl.className)	// box
</script>

property的缺点

以下面的checked属性为例,判断一个input是否是选中状态,会出现问题。因为像chenked这种值相当于一个空字符串。

<input type="checkbox" checked>

var inputEl = document.querySelector("input")
if (inputEl.getAttribute("checked")) {
 console.log("checkbox处于选中状态") // 不会输出
}

property的优点

对于标准的property属性,通过element.arrName来获取,既可以获取到值,也可以获取到类型。

// 实际开发中
if (inputEl.checked) {
 console.log("checkbox处于选中状态") // 会输出
}
console.log(typeof inputEl.checked)    // boolean

除非特殊情况,大多数情况下,设置、获取attribute,推荐使用property的方式,因为它默认情况下是有类型的。

8.7.3 JavaScript动态修改样式

  • 方式一:直接修改style
// 获取boxEl
var boxEl = document.querySelector(".box")

// 方式一:直接修改style
boxEl.onclick = function() {
    boxEl.style.color = "blue"
    boxEl.style.fontSize = "20px"
}
  • 方式二:动态修改style属性

先在style中写好样式,然后通过JavaScript直接替换。

<style>
    .active {
        font-size: 20px;
        background: green;
    }
</style>

// 方式二:动态添加某一个class 
boxEl.className = "active"

如果可以动态修改样式完成某个功能,使用动态修改样式;如果无法通过动态修改样式(比如精准修改某个CSS属性的值),则直接修改style。

8.7.3.1 Element元素的class操作

元素的标签属性class,对应的property不叫class,而是className

  1. 方法一:使用className
boxEl.className = "active"
  1. 方法二:使用classList操作class

Element.classList 是一个只读属性,返回一个元素 class 属性的动态 DOMTokenList 集合。这可以用于操作 class 集合。

相比将 element.className 作为以空格分隔的字符串来使用,classList 是一种更方便的访问元素的类列表的方法。

尽管 classList 属性自身是只读的,但是你可以使用 add()remove()replace()] 和 toggle() 方法修改其关联的 DOMTokenList

  • classList.add()

    • 语法:element.classList.add()
    • 描述:将给定的标记添加到列表中。
  • classList.remove()

    • 语法:element.classList.remove()
    • 描述:移除指定标记。
  • classList.replace()

    • 语法:element.classList.replace(oldToken, newToken)
    • 参数(oldToken):DOMString类型,想要替换掉的字符串。
    • 参数(newToken):DOMString类型,表示要将oldToken字符串替换成的字符串。
    • 描述:将列表中一个已存在的 token 替换为一个新 token。如果第一个参数 token 在列表中不存在, replace() 立刻返回false ,而不会将新 token 字符串添加到列表中。
  • classList.toggle()

    • 语法:element.classList.toggle(token[, force])
    • 参数(token):一个字符串,表示你想要 toggle 的标记。
    • 参数(force):可选。如果包含该值,设置后会将方法变成单向操作。如果设置为 false会删除标记列表中匹配的给定标记,且不会再度添加。如果设置为 true在标记列表中添加给定标记,且不会再度删除。
    • 描述:从列表中删除一个给定的标记并返回 false。如果标记不存在,则添加并且函数返回 true
    const div = document.createElement('div');
    div.className = 'foo';
    
    // 初始状态:<div class="foo"></div>
    console.log(div.outerHTML);
    
    // 使用 classList API 移除、添加类值
    div.classList.remove("foo");
    div.classList.add("anotherclass");
    
    // <div class="anotherclass"></div>
    console.log(div.outerHTML);
    
    // 如果 visible 类值已存在,则移除它,否则添加它
    div.classList.toggle("visible");
    
    // add/remove visible, depending on test conditional, i less than 10
    div.classList.toggle("visible", i < 10 );
    
    console.log(div.classList.contains("foo"));
    
    // 添加或移除多个类值
    div.classList.add("foo", "bar", "baz");
    div.classList.remove("foo", "bar", "baz");
    
    // 使用展开语法添加或移除多个类值
    const cls = ["foo", "bar"];
    div.classList.add(...cls);
    div.classList.remove(...cls);
    
    // 将类值 "foo" 替换成 "bar"
    div.classList.replace("foo", "bar");
    
    /*
    	需求:通过点击按钮,使样式在class="box"和class="active"之间切换。
    */
    var btnEl = document.querySelector(".btn")
    btnEl.onclick = function() {
    	if (boxEl,classList.contains("active")) {
    		boxEl.classList.remove("active")
    	} else {
    		boxEl.classList.add("active")
    	}
    }
    // 第6到10行代码可直接替换为
    boxEl.classList.toggle("active")
    

classList是可迭代对象,可以使用for...of进行遍历。

8.7.3.2 Element元素的style操作

8.7.3.2.1 style的用法
  1. 可以通过style单独修改某一个CSS属性。

注:对于一个多词属性(属性名由多个单词构成,用 - 连接),使用小驼峰式。

<div class="box" style="background-color: aqua;">
 哈哈哈
</div>

<script>
 var boxEl = document.querySelector(".box")
 console.log(boxEl.style.backgroundColor)
</script>
  1. 如果将一个属性的值设置为空的字符串,那么使用默认值

  2. 可以使用cssText同时设置多个样式

    不推荐这种用法,因为它会替换整个字符串。

    <style>
    body { background-color: darkblue; }
    </style>
    <script>
      var stylesheet = document.styleSheets[0];
      alert(stylesheet.cssRules[0].cssText); // body { background-color: darkblue; }
    </script>
    
    boxEl.style.cssText = "font-size: 20px; color: blue"
    
8.7.3.2.2 style的读取
  1. 读取行内样式
  • 语法:element.style.propertyValue

    不能通过这种形式读取内部样式或外部样式,因为会返回空

    <style>
        .box {
            font-size: 20px;
        }
    </style>
    
<body>
    <div class="box" style="background-color: red;">
        哈哈哈
    </div>
    <script>
        var boxEl = document.querySelector(".box")
        console.log(boxEl.style.backgroundColor)    // red
        console.log(boxEl.style.fontSize)           // ""(空串)
    </script>
</body>
  1. 读取内部样式
  • Window.getComputedStyle()

    • 语法:let style = window.getComputedStyle(element, [pseudoElt]);
      • 参数(element):用于获取计算样式的 Element
      • 参数(pseudoElt):指定一个要匹配的伪元素的字符串。必须对普通元素省略(或null)。
    • 描述:返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有 CSS 属性的值。
    console.log(getComputedStyle(boxEl))
    

8.7.4 元素的dataset属性

对于自定义的标签属性,可以将其命名为 data-* 的形式,通过 dataset 属性获取。

  1. dataset 属性
  • 描述:HTMLElement 接口的只读属性 dataset 提供了对元素上 自定义数据属性data-*)读/写访问。它暴露了一个字符串映射(DOMStringMap),其中包含每个 data-* 属性条目。

注:dataset 属性本身可以被读取,但是不能直接写入。相反,所有写入都必须是写入 dataset 的单个属性,而 dataset 又表示这些数据的属性。

在 HTML

属性名以 data- 开头。它只能包含字母、数字、破折号(-)、句号(.)、冒号(:)和下划线(_)。任意的 ASCII 大写字母(AZ)都会转换为小写。

在 JavaScript

自定义 data 属性的属性名与没有 data- 前缀的 HTML 属性相同,并且在移除单个破折号(-)后,大写之后的字母以获得属性的“驼峰”命名。

  • 获取值

    • 属性可以驼峰名/键的方式作为 dataset 的对象属性设置和读取:element.dataset.keyname

    • 属性也可以使用方括号语法设置和读取:element.dataset['keyname']

    • 使用 in 操作符 可以检查一个给定的属性是否存在:'keyname' in element.dataset

<div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth>
  John Doe
</div>

const el = document.querySelector('#user');

// el.id === 'user'
// el.dataset.id === '1234567890'
// el.dataset.user === 'johndoe'
// el.dataset.dateOfBirth === ''

// set a data attribute
el.dataset.dateOfBirth = '1960-10-03';
// Result on JS: el.dataset.dateOfBirth === '1960-10-03'
// Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe" data-date-of-birth="1960-10-03">John Doe</div>

delete el.dataset.dateOfBirth;
// Result on JS: el.dataset.dateOfBirth === undefined
// Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe">John Doe</div>

if (!('someDataAttr' in el.dataset)) {
  el.dataset.someDataAttr = 'mydata';
  // Result on JS: 'someDataAttr' in el.dataset === true
  // Result on HTML: <div id="user" data-id="1234567890" data-user="johndoe" data-some-data-attr="mydata">John Doe</div>
}

8.7.5 对元素进行操作的一系列方法

  • 方法一:使用innerHTML属性

不推荐使用。详见官网文档。

  • 方法二:
    1. 真实创建一个DOM对象(创建元素);
    2. 将元素插入DOM中。

8.7.5.1 创建元素

  • Document.createElement()
    • 语法:var element = document.createElement(tagName[, options]);
    • 参数(tagName):指定要创建元素类型的字符串,创建元素时的 nodeName 使用 tagName 的值为初始化,该方法不允许使用限定名称 (如:"html:a")。
    • 描述:用于创建一个由标签名称 tagName 指定的 HTML 元素。
    • 返回值:新建的元素(Element)

8.7.5.2 插入元素(将元素插入到DOM)

  • Element.append()

    • 语法:Element.append((Node or DOMString)... nodes);
    • 描述:在 Element的最后一个子节点之后插入一组 Node 对象或 DOMString 对象。被插入的 DOMString 对象等价为 Text 节点【在Element末尾插入】。
    // 插入一个元素节点
    var parent = document.createElement("div");
    var p = document.createElement("p");
    parent.append(p);
    
    console.log(parent.childNodes); // NodeList [ <p> ]
    
    // 插入文本
    var parent = document.createElement("div");
    parent.append("Some text");
    
    console.log(parent.textContent); // "Some text"
    
  • Element.prepend()

    • 语法:Element.prepend((Node or DOMString)... nodes);
    • 描述:可以在父节点的第一个子节点之前插入一系列Node对象或者DOMString对象。DOMString会被当作Text节点对待(也就是说插入的不是 HTML 代码)。【在Element开头插入】
  • Element.before()ChildNode.before

    • 语法:Element.before((Node or DOMString)... nodes);
    • 描述:ChildNode.before 方法可以在ChildNode 这个节点的父节点中插入一些列的 Node 或者 DOMString 对象,位置就是在ChildNode 节点的前面,DOMString 对象其实和 Text 节点一样的方式来完成插入的。【在Element元素前面新插入一个Node】
  • Element.after()

    • 语法:Element.after(... nodes)
    • 描述:在其父节点的子节点列表中插入一些 NodeDOMString 对象。插入位置为该节点之后。DOMString 对象会被以 Text 的形式插入。【在Element后面新插入一个Node】
  • Element.replaceWith()ChildNode.replaceWith()

    • 语法:ChildNode.replaceWith((Node or DOMString)... nodes);
    • 描述:用一套 Node对象或者 DOMString 对象,替换了该节点父节点下的子节点。DOMString 对象被当做等效的Text 节点插入。
<div id="div1">The text above has been created dynamically.</div>

/*
	创建一个新的 <div> 并且插入到 ID 为“div1”的元素前。
*/
document.body.onload = addElement;

function addElement () {
  // 创建一个新的 div 元素
  let newDiv = document.createElement("div");
  // 给它一些内容
  let newContent = document.createTextNode("Hi there and greetings!");
  // 添加文本节点 到这个新的 div 元素
  newDiv.appendChild(newContent);

  // 将这个新的元素和它的文本添加到 DOM 中
  let currentDiv = document.getElementById("div1");
  document.body.insertBefore(newDiv, currentDiv);
}

8.7.5.3 移除元素

  • Element.remove()

    • 语法:node.remove();
    • 描述:把对象从它所属的 DOM 树中删除。
    <div id="div-01">Here is div-01</div>
    <div id="div-02">Here is div-02</div>
    <div id="div-03">Here is div-03</div>
    
    var el = document.getElementById('div-02');
    el.remove();	// id 为 'div-02' 的 div 被删掉了
    

8.7.5.4 克隆元素

  • Node.cloneNode()
    • 语法:var dupNode = node.cloneNode([deep]);
      • node:将要被克隆的节点
      • dupNode:克隆生成的副本节点
      • 参数(deep):可选。是否采用深度克隆,如果为 true,则该节点的所有后代节点也都会被克隆,如果为 false,则只克隆该节点本身。默认值为false。
    • 描述:返回调用该方法的节点的一个副本。

8.7.6 获取元素信息的一系列属性【了解】

8.7.6.1 获取元素的大小

  • clientWidth

    • 语法:element.clientWidth
    • 描述:对于内联元素以及没有 CSS 样式的元素为 0;否则,它是元素内部的宽度(以像素为单位)。该属性包括内边距(padding),但不包括边框(border)、外边距(margin)和垂直滚动条(如果存在)。【clientWidth = contentWidth + padding
  • clientHeight

    • 描述:元素内部的高度(以像素为单位),包含内边距,但不包括边框、外边距和水平滚动条(如果存在)。【clientHeight = contentWidth + padding - 水平滚动条高度
  • clientTop

    • 描述:一个元素顶部边框的宽度(以像素表示)。不包括顶部外边距或内边距。【clientTop = border - top的宽度
  • clientLeft

    • 描述:表示一个元素的左边框的宽度,不包括左外边距和左内边距。【clientLeft = border - left的宽度

8.7.6.2 获取元素的位置

  • offsetWidth

    • 描述:返回一个元素的布局宽度。一个典型的 offsetWidth 是测量包含元素的边框 (border)、水平线上的内边距 (padding)、竖直方向滚动条 (scrollbar)(如果存在的话)、以及 CSS 设置的宽度 (width) 的值。【元素完整的宽度】
  • offsetHeight

    • 描述:返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。【元素完整的高度】
  • offsetLeft

    • 描述:返回当前元素左上角相对于 HTMLElement.offsetParent 节点的左边界偏移的像素值。【距离父元素的x】
  • offsetTop

    • 描述:返回当前元素相对于其 offsetParent 元素的顶部内边距的距离。【距离父元素的y】

8.7.6.3 获取元素的滚动位置

  • scrollHeight

    • 描述:该属性是一个元素内容高度的度量,包括由于溢出导致的视图中不可见内容。【整个可滚动的区域高度】
  • scrollTop

    • 描述:可以获取或设置一个元素的内容垂直滚动的像素数。【滚动部分的高度】