Element 节点
1.简介
Element
节点对象对应网页的 HTML 元素。每一个 HTML 元素,在 DOM 树上都会转化成一个Element
节点对象(以下简称元素节点)。
元素节点的nodeType属
性都是1。
var p = document.querySelector('p');
p.nodeName // "P"
p.nodeType // 1
Element
对象继承了Node
接口,因此Node
的属性和方法在Element
对象都存在。
此外,不同的 HTML 元素对应的元素节点是不一样的,浏览器使用不同的构造函数,生成不同的元素节点,比如<a>
元素的构造函数是HTMLAnchorElement(),<button>
是HTMLButtonElement()
。因此,元素节点不是一种对象,而是许多种对象,这些对象除了继承Element
对象的属性和方法,还有各自独有的属性和方法。
2.实例属性
2.1元素特性的相关属性
(1)Element.id
Element.id
属性返回指定元素的id
属性,该属性可读写。
// HTML 代码为 <p id="foo">
var p = document.querySelector('p');
p.id // "foo"
注意,id
属性的值是大小写敏感,即浏览器能正确识别<p id="foo">
和<p id="FOO">
这两个元素的id属性,但是最好不要这样命名。
(2)Element.tagName
Element.tagName
属性返回指定元素的大写标签名,与nodeName
属性的值相等。
/ HTML代码为
// <span id="myspan">Hello</span>
var span = document.getElementById('myspan');
span.id // "myspan"
span.tagName // "SPAN"
(3)Element.title
Element.title属性用来读写当前元素的 HTML 属性title。该属性通常用来指定,鼠标悬浮时弹出的文字提示框。
2.2元素状态的相关属性
(1)Element.hidden
Element.hidden
属性返回一个布尔值,表示当前 HTML 元素的hidden
属性的值。该属性可读写,用来控制当前元素是否可见。
var btn = document.getElementById('btn');
var mydiv = document.getElementById('mydiv');
btn.addEventListener('click', function () {
mydiv.hidden = !mydiv.hidden;
}, false);
注意,该属性与 CSS 设置是互相独立的。CSS 对当前元素可见性的设置,Element.hidden
并不能反映出来。也就是说,这个属性并不能用来判断当前元素的实际可见性。
CSS 设置的优先级高于Element.hidden
。如果 CSS 指定了该元素不可见(display: none
)或可见(visibility: visible
),那么Element.hidden
并不能改变该元素实际的可见性。换言之,这个属性只在 CSS 没有明确设定当前元素的可见性时才有效。
(2)Element.contentEditable,Element.isContentEditable
HTML 元素可以设置contentEditable
属性,使得元素的内容可以编辑。
<div contenteditable>123</div>
上面代码中, <div>
元素有 contenteditable
属性,因此用户可以在网页上编辑这个区块的内容。
Element.contentEditable
属性返回一个字符串,表示是否设置了 contenteditable
属性,有三种可能的值。该属性可写。
"true"
:元素内容可编辑"false"
:元素内容不可编辑"inherit"
:元素是否可编辑,继承了父元素的设置
Element.isContentEditable
属性返回一个布尔值,同样表示是否设置了 contenteditable
属性。该属性只读。
2.3Element.attributes
Element.attributes
属性返回一个类似数组的对象,成员是当前元素节点的所有属性节点。
var p = document.querySelector('p');
var attrs = p.attributes;
for (var i = attrs.length - 1; i >= 0; i--) {
console.log(attrs[i].name + '->' + attrs[i].value);
}
上面代码遍历p元素的所有属性。
2.4 Element.className,Element.classList
className
属性用来读写当前元素节点的 class
属性。它的值是一个字符串,每个 class
之间用空格分割。
classList
属性返回一个类似数组的对象,当前元素节点的每个 class
就是这个对象的一个成员。
// HTML 代码 <div class="one two three" id="myDiv"></div>
var div = document.getElementById('myDiv');
div.className
// "one two three"
div.classList
// {
// 0: "one"
// 1: "two"
// 2: "three"
// length: 3
// }
上面代码中, className
属性返回一个空格分隔的字符串,而 classList
属性指向一个类似数组的对象,该对象的 length
属性(只读)返回当前元素的 class
数量。
classList
对象有下列方法。
add()
:增加一个 class。remove()
:移除一个 class。contains()
:检查当前元素是否包含某个 class。toggle()
:将某个 class 移入或移出当前元素。item()
:返回指定索引位置的 class。toString()
:将 class 的列表转为字符串。
var div = document.getElementById('myDiv');
div.classList.add('myCssClass');
div.classList.add('foo', 'bar');
div.classList.remove('myCssClass');
div.classList.toggle('myCssClass'); // 如果 myCssClass 不存在就加入,否则移除
div.classList.contains('myCssClass'); // 返回 true 或者 false
div.classList.item(0); // 返回第一个 Class
div.classList.toString();
下面比较一下, className
和 classList
在添加和删除某个 class 时的写法。
var foo = document.getElementById('foo');
// 添加class
foo.className += 'bold';
foo.classList.add('bold');
// 删除class
foo.classList.remove('bold');
foo.className = foo.className.replace(/^bold$/, '');
toggle
方法可以接受一个布尔值,作为第二个参数。如果为true
,则添加该属性;如果为 false
,则去除该属性。
el.classList.toggle('abc', boolValue);
// 等同于
if (boolValue) {
el.classList.add('abc');
} else {
el.classList.remove('abc');
}
2.5 Element.dataset
网页元素可以自定义 data-
属性,用来添加数据。
<div data-timestamp="1522907809292"></div>
上面代码中, <div>
元素有一个自定义的 data-timestamp
属性,用来为该元素添加一个时间戳。
Element.dataset
属性返回一个对象,可以从这个对象读写 data-
属性。
// <article
// id="foo"
// data-columns="3"
// data-index-number="12314"
// data-parent="cars">
// ...
// </article>
var article = document.getElementById('foo');
article.dataset.columns // "3"
article.dataset.indexNumber // "12314"
article.dataset.parent // "cars"
注意, dataset
上面的各个属性返回都是字符串。
HTML 代码中, data-
属性的属性名,只能包含英文字母、数字、连词线( -
)、点( .
)、冒号( :
)和下划线( _
)。它们转成 JavaScript 对应的dataset属性名,规则如下。
- 开头的
data-
会省略。 - 如果连词线后面跟了一个英文字母,那么连词线会取消,该字母变成大写。
- 其他字符不变。
因此, data-abc-def
对应dataset.abcDef
, data-abc-1
对应 dataset["abc-1"]
。
除了使用 dataset
读写 data-
属性,也可以使用 Element.getAttribute()
和 Element.setAttribute()
,通过完整的属性名读写这些属性。
var mydiv = document.getElementById('mydiv');
mydiv.dataset.foo = 'bar';
mydiv.getAttribute('data-foo') // "bar"
2.6Element.innerHTML
Element.innerHTML
属性返回一个字符串,等同于该元素包含的所有 HTML 代码。该属性可读写,常用来设置某个节点的内容。它能改写所有元素节点的内容,包括 <HTML>
和 <body>
元素。
如果将 innerHTML
属性设为空,等于删除所有它包含的所有节点。
el.innerHTML = '';
上面代码等于将 el
节点变成了一个空节点, el
原来包含的节点被全部删除。
注意,读取属性值的时候,如果文本节点包含 &
、小于号( <
)和大于号( >
), innerHTML
属性会将它们转为实体形式 &、<、>
。如果想得到原文,建议使用 element.textContent
属性。
// HTML代码如下 <p id="para"> 5 > 3 </p>
document.getElementById('para').innerHTML
// 5 > 3
写入的时候,如果插入的文本包含 HTML 标签,会被解析成为节点对象插入 DOM。注意,如果文本之中含有 <script>
标签,虽然可以生成 script
节点,但是插入的代码不会执行。
var name = "<script>alert('haha')</script>";
el.innerHTML = name;
上面代码将脚本插入内容,脚本并不会执行。但是,innerHTML
还是有安全风险的。
var name = "<img src=x οnerrοr=alert(1)>";
el.innerHTML = name;
上面代码中,alert
方法是会执行的。因此为了安全考虑,如果插入的是文本,最好用textContent
属性代替innerHTML
。
2.7 Element.outerHTML
Element.outerHTML
属性返回一个字符串,表示当前元素节点的所有 HTML 代码,包括该元素本身和所有子元素。
// HTML 代码如下
// <div id="d"><p>Hello</p></div>
var d = document.getElementById('d');
d.outerHTML
// '<div id="d"><p>Hello</p></div>'
outerHTML
属性是可读写的,对它进行赋值,等于替换掉当前元素。
// HTML 代码如下
// <div id="container"><div id="d">Hello</div></div>
var container = document.getElementById('container');
var d = document.getElementById('d');
container.firstChild.nodeName // "DIV"
d.nodeName // "DIV"
d.outerHTML = '<p>Hello</p>';
container.firstChild.nodeName // "P"
d.nodeName // "DIV"
上面代码中,变量d
代表子节点,它的outerHTML
属性重新赋值以后,内层的div
元素就不存在了,被p
元素替换了。但是,变量d依然指向原来的div
元素,这表示被替换的DIV
元素还存在于内存中。
注意,如果一个节点没有父节点,设置outerHTML
属性会报错。
var div = document.createElement('div');
div.outerHTML = '<p>test</p>';
// DOMException: This element has no parent node.
上面代码中,div
元素没有父节点,设置outerHTML
属性会报错。