...
document.getElementById('myDiv').scrollHeight // 356
```
上面代码中,即使`myDiv`元素的 CSS 高度只有200像素,且溢出部分不可见,但是`scrollHeight`仍然会返回该元素的原始高度。
### Element.scrollLeft,Element.scrollTop
`Element.scrollLeft`属性表示当前元素的水平滚动条向右侧滚动的像素数量,`Element.scrollTop`属性表示当前元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。
如果要查看整张网页的水平的和垂直的滚动距离,要从`document.documentElement`元素上读取。
```javascript
document.documentElement.scrollLeft
document.documentElement.scrollTop
```
这两个属性都可读写,设置该属性的值,会导致浏览器将当前元素自动滚动到相应的位置。
### Element.offsetParent
`Element.offsetParent`属性返回最靠近当前元素的、并且 CSS 的`position`属性不等于`static`的上层元素。
```html
```
上面代码中,`span`元素的`offsetParent`属性就是`div`元素。
该属性主要用于确定子元素位置偏移的计算基准,`Element.offsetTop`和`Element.offsetLeft`就是`offsetParent`元素计算的。
如果该元素是不可见的(`display`属性为`none`),或者位置是固定的(`position`属性为`fixed`),则`offsetParent`属性返回`null`。
```html
```
上面代码中,`span`元素的`offsetParent`属性是`null`。
如果某个元素的所有上层节点的`position`属性都是`static`,则`Element.offsetParent`属性指向``元素。
### Element.offsetHeight,Element.offsetWidth
`Element.offsetHeight`属性返回一个整数,表示元素的 CSS 垂直高度(单位像素),包括元素本身的高度、padding 和 border,以及水平滚动条的高度(如果存在滚动条)。
`Element.offsetWidth`属性表示元素的 CSS 水平宽度(单位像素),其他都与`Element.offsetHeight`一致。
这两个属性都是只读属性,只比`Element.clientHeight`和`Element.clientWidth`多了边框的高度或宽度。如果元素的 CSS 设为不可见(比如`display: none;`),则返回`0`。
### Element.offsetLeft,Element.offsetTop
`Element.offsetLeft`返回当前元素左上角相对于`Element.offsetParent`节点的水平位移,`Element.offsetTop`返回垂直位移,单位为像素。通常,这两个值是指相对于父节点的位移。
下面的代码可以算出元素左上角相对于整张网页的坐标。
```javascript
function getElementPosition(e) {
var x = 0;
var y = 0;
while (e !== null) {
x += e.offsetLeft;
y += e.offsetTop;
e = e.offsetParent;
}
return {x: x, y: y};
}
```
### Element.style
每个元素节点都有`style`用来读写该元素的行内样式信息,具体介绍参见《CSS 操作》一章。
### Element.children,Element.childElementCount
`Element.children`属性返回一个类似数组的对象(`HTMLCollection`实例),包括当前元素节点的所有子元素。如果当前元素没有子元素,则返回的对象包含零个成员。
```javascript
if (para.children.length) {
var children = para.children;
for (var i = 0; i < children.length; i++) {
// ...
}
}
```
上面代码遍历了`para`元素的所有子元素。
这个属性与`Node.childNodes`属性的区别是,它只包括元素类型的子节点,不包括其他类型的子节点。
`Element.childElementCount`属性返回当前元素节点包含的子元素节点的个数,与`Element.children.length`的值相同。
### Element.firstElementChild,Element.lastElementChild
`Element.firstElementChild`属性返回当前元素的第一个元素子节点,`Element.lastElementChild`返回最后一个元素子节点。
如果没有元素子节点,这两个属性返回`null`。
### Element.nextElementSibling,Element.previousElementSibling
`Element.nextElementSibling`属性返回当前元素节点的后一个同级元素节点,如果没有则返回`null`。
```javascript
// HTML 代码如下
//
Here is div-01
//
Here is div-02
var el = document.getElementById('div-01');
el.nextElementSibling
//
Here is div-02
```
`Element.previousElementSibling`属性返回当前元素节点的前一个同级元素节点,如果没有则返回`null`。
## 实例方法
### 属性相关方法
元素节点提供六个方法,用来操作属性。
- `getAttribute()`:读取某个属性的值
- `getAttributeNames()`:返回当前元素的所有属性名
- `setAttribute()`:写入属性值
- `hasAttribute()`:某个属性是否存在
- `hasAttributes()`:当前元素是否有属性
- `removeAttribute()`:删除属性
这些方法的介绍请看《属性的操作》一章。
### Element.querySelector()
`Element.querySelector`方法接受 CSS 选择器作为参数,返回父元素的第一个匹配的子元素。如果没有找到匹配的子元素,就返回`null`。
```javascript
var content = document.getElementById('content');
var el = content.querySelector('p');
```
上面代码返回`content`节点的第一个`p`元素。
`Element.querySelector`方法可以接受任何复杂的 CSS 选择器。
```javascript
document.body.querySelector("style[type='text/css'], style:not([type])");
```
注意,这个方法无法选中伪元素。
它可以接受多个选择器,它们之间使用逗号分隔。
```javascript
element.querySelector('div, p')
```
上面代码返回`element`的第一个`div`或`p`子元素。
需要注意的是,浏览器执行`querySelector`方法时,是先在全局范围内搜索给定的 CSS 选择器,然后过滤出哪些属于当前元素的子元素。因此,会有一些违反直觉的结果,下面是一段 HTML 代码。
```html
```
那么,像下面这样查询的话,实际上返回的是第一个`p`元素,而不是第二个。
```javascript
var outer = document.getElementById('outer');
outer.querySelector('div p')
//
Hello
```
### Element.querySelectorAll()
`Element.querySelectorAll`方法接受 CSS 选择器作为参数,返回一个`NodeList`实例,包含所有匹配的子元素。
```javascript
var el = document.querySelector('#test');
var matches = el.querySelectorAll('div.highlighted > p');
```
该方法的执行机制与`querySelector`方法相同,也是先在全局范围内查找,再过滤出当前元素的子元素。因此,选择器实际上针对整个文档的。
它也可以接受多个 CSS 选择器,它们之间使用逗号分隔。如果选择器里面有伪元素的选择器,则总是返回一个空的`NodeList`实例。
### Element.getElementsByClassName()
`Element.getElementsByClassName`方法返回一个`HTMLCollection`实例,成员是当前元素节点的所有具有指定 class 的子元素节点。该方法与`document.getElementsByClassName`方法的用法类似,只是搜索范围不是整个文档,而是当前元素节点。
```javascript
element.getElementsByClassName('red test');
```
注意,该方法的参数大小写敏感。
由于`HTMLCollection`实例是一个活的集合,`document`对象的任何变化会立刻反应到实例,下面的代码不会生效。
```javascript
// HTML 代码如下
//
var element = document.getElementById('example');
var matches = element.getElementsByClassName('foo');
for (var i = 0; i< matches.length; i++) {
matches[i].classList.remove('foo');
matches.item(i).classList.add('bar');
}
// 执行后,HTML 代码如下
//
```
上面代码中,`matches`集合的第一个成员,一旦被拿掉 class 里面的`foo`,就会立刻从`matches`里面消失,导致出现上面的结果。
### Element.getElementsByTagName()
`Element.getElementsByTagName()`方法返回一个`HTMLCollection`实例,成员是当前节点的所有匹配指定标签名的子元素节点。该方法与`document.getElementsByClassName()`方法的用法类似,只是搜索范围不是整个文档,而是当前元素节点。
```javascript
var table = document.getElementById('forecast-table');
var cells = table.getElementsByTagName('td');
```
注意,该方法的参数是大小写不敏感的,因为 HTML 标签名也是大小写不敏感。
### Element.closest()
`Element.closest`方法接受一个 CSS 选择器作为参数,返回匹配该选择器的、最接近当前节点的一个祖先节点(包括当前节点本身)。如果没有任何节点匹配 CSS 选择器,则返回`null`。
```javascript
// HTML 代码如下
//
// Here is div-01
//
Here is div-02
//
Here is div-03
//
//
//
var div03 = document.getElementById('div-03');
// div-03 最近的祖先节点
div03.closest("#div-02") // div-02
div03.closest("div div") // div-03
div03.closest("article > div") //div-01
div03.closest(":not(div)") // article
```
上面代码中,由于`closest`方法将当前节点也考虑在内,所以第二个`closest`方法返回`div-03`。
### Element.matches()
`Element.matches`方法返回一个布尔值,表示当前元素是否匹配给定的 CSS 选择器。
```javascript
if (el.matches('.someClass')) {
console.log('Match!');
}
```
### 事件相关方法
以下三个方法与`Element`节点的事件相关。这些方法都继承自`EventTarget`接口,详见相关章节。
- `Element.addEventListener()`:添加事件的回调函数
- `Element.removeEventListener()`:移除事件监听函数
- `Element.dispatchEvent()`:触发事件
```javascript
element.addEventListener('click', listener, false);
element.removeEventListener('click', listener, false);
var event = new Event('click');
element.dispatchEvent(event);
```
### Element.scrollIntoView()
`Element.scrollIntoView`方法滚动当前元素,进入浏览器的可见区域,类似于设置`window.location.hash`的效果。
```javascript
el.scrollIntoView(); // 等同于el.scrollIntoView(true)
el.scrollIntoView(false);
```
该方法可以接受一个布尔值作为参数。如果为`true`,表示元素的顶部与当前区域的可见部分的顶部对齐(前提是当前区域可滚动);如果为`false`,表示元素的底部与当前区域的可见部分的尾部对齐(前提是当前区域可滚动)。如果没有提供该参数,默认为`true`。
### Element.getBoundingClientRect()
`Element.getBoundingClientRect`方法返回一个对象,提供当前元素节点的大小、位置等信息,基本上就是 CSS 盒状模型的所有信息。
```javascript
var rect = obj.getBoundingClientRect();
```
上面代码中,`getBoundingClientRect`方法返回的`rect`对象,具有以下属性(全部为只读)。
- `x`:元素左上角相对于视口的横坐标
- `y`:元素左上角相对于视口的纵坐标
- `height`:元素高度
- `width`:元素宽度
- `left`:元素左上角相对于视口的横坐标,与`x`属性相等
- `right`:元素右边界相对于视口的横坐标(等于`x + width`)
- `top`:元素顶部相对于视口的纵坐标,与`y`属性相等
- `bottom`:元素底部相对于视口的纵坐标(等于`y + height`)
由于元素相对于视口(viewport)的位置,会随着页面滚动变化,因此表示位置的四个属性值,都不是固定不变的。如果想得到绝对位置,可以将`left`属性加上`window.scrollX`,`top`属性加上`window.scrollY`。
注意,`getBoundingClientRect`方法的所有属性,都把边框(`border`属性)算作元素的一部分。也就是说,都是从边框外缘的各个点来计算。因此,`width`和`height`包括了元素本身 + `padding` + `border`。
另外,上面的这些属性,都是继承自原型的属性,`Object.keys`会返回一个空数组,这一点也需要注意。
```javascript
var rect = document.body.getBoundingClientRect();
Object.keys(rect) // []
```
上面代码中,`rect`对象没有自身属性,而`Object.keys`方法只返回对象自身的属性,所以返回了一个空数组。
### Element.getClientRects()
`Element.getClientRects`方法返回一个类似数组的对象,里面是当前元素在页面上形成的所有矩形(所以方法名中的`Rect`用的是复数)。每个矩形都有`bottom`、`height`、`left`、`right`、`top`和`width`六个属性,表示它们相对于视口的四个坐标,以及本身的高度和宽度。
对于盒状元素(比如`