啥是DOM?
- The Document Object Model
- JS可修改和查询HTML文档
- Accessible via the JS global scope, aliases:
window
- 批注:
console.log(window) // 返回window对象
- 批注:
this
(When not using'use strict';
)- 批注:
console.log(this) // 返回window对象
- 批注:
'use strict';
(严格模式) - 批注:
this
的指向- 全局作用域或者普通函数中的
this
指向window
- e.g. setInterval中的
this
指向window
- e.g. 全局变量
this
指向window
- e.g. setInterval中的
- 构造函数中,this指向构造函数的实例
e.g.function Fun() {console.log(this); // this 指向的是fun 实例对象 }
- 方法调用时,谁调用
this
指向谁
- 全局作用域或者普通函数中的
- 批注:
sayHi: function() {
console.log(`o:`+this); // this指向的是 o 这个对象
}
}
DOM hierarchy(层次结构)
-
Rooted at
window.document (html tag)
批注:返回#document
文档对象(<!DOCTYPE html> <html>...</html>
)- 批注: 使用时可省略
window
,直接写document
- 批注: 使用时可省略
-
Follows HTML document structure
window.document.head
批注: // 返回<head>...</head>
window.document.body
批注: // 返回<body>...</body>
- 批注:
document.documentElement
返回<html>...</html>
- 批注:
-
Tree nodes (DOM objects) have tons(~250) of properties, most private
- Objects(representing elements, raw, text, etc.) have a common set of properties and methods called a DOM “Node”
- 批注:节点包含
nodeType
,nodeName
, nodeValue 三个基本属性 - 批注:元素节点的
nodeType = 1
,属性节点的nodeType = 2
,文本节点的nodeType = 3
- 批注:节点包含
- Objects(representing elements, raw, text, etc.) have a common set of properties and methods called a DOM “Node”
DOM Node properties and methods
- Identification
nodeName
property is element type- 批注:返回节点名称。元素节点返回标签名,文本节点返回
#text
字符串。只读属性。
- 批注:返回节点名称。元素节点返回标签名,文本节点返回
- Encode(编码) document’s hierachical structure
parentNode, nextSibling, previousSibling, firstChild, lastChild
- 批注:
parentNode
返回最近的父级,找不到父级则返回null
offsetParent
返回定位过的父级,否则返回body
nextSibling
返回下一个兄弟节点(非下一个元素节点)- 下一个元素节点:
nextElementSibling
- 下一个元素节点:
previousSibling
返回上一个兄弟节点- 上一个元素节点:
previousElementSibling
- 上一个元素节点:
firstChild
返回第一个子级节点(注意:不是返回第一个元素节点)。- 想要返回第一个元素子节点,请用
firstElementChild
或者children[0]
,前者IE9以上支持,后者无兼容性问题。
- 想要返回第一个元素子节点,请用
lastChild
返回最后一个子级节点(注意:不是返回第一个元素节点)- 返回最后一个元素节点请用:
lastElementChild
(IE9以上支持)或者`children[parentNode.children.length - 1]
- 返回最后一个元素节点请用:
- 补充:
parentNode.children
返回所有的元素子节点,将之存放在数组中
- 批注:
- Provide accessor and mutator methods(访问和修改)
- E.g.
getAttribute, setAttribute
methods, etc.
- E.g.
访问DOM 节点
- 遍历DOM层级(不推荐)
element = document.body.firstChild.nextSibling.firstChild;
element.setAttribute(...
- 使用DOM查找方法
- HTML:
<div id = "div42">...</div>
element = document.getElementById("div42");
element.setAttribute(...
- 批注:直接查找DOM节点的方法:
document.getElementById
document.querySelector
- 以上直接返回元素对象
- 批注:直接查找DOM节点的方法:
- HTML:
- 查找多个DOM节点
- 通过
getElementsByClassName(), getElementsByTagName(),...
- 能从头查找任何元素
document.body.firstChild.getElementsByTagName()
- 批注:查找多个DOM节点的方法:
getElementsByClassName()
getElementsByTagName()
document.querySelectorAll()
getElementsByClassName()
,getElementsByTagName()
返回对象集合,以伪数组的形式存储,如果找不到符合要求的元素,返回空的伪数组document.querySelectorAll()
返回节点列表,找不到符合要求的元素,返回空的节点列表- 要访问其中所有元素,可遍历数组或者列表。如果访问其中一个元素,
arr[index]
- 批注:查找多个DOM节点的方法:
- 能从头查找任何元素
- 通过
更常用的节点属性/方法
- textContent - 节点及其后代的文本内容
- 批注:包含空格和换行,包括隐藏元素,防止XSS攻击
- innerHTML - HTML syntax describing the element’s descendants(描述元素后代)
<p>Sample<b>bold</b>display</p>
p.innerHTML
返回Sample<b>bold</b>display
- outerHML - 和innerHTML类似,但是包含元素本身
<p>Sample<b>bold</b>display</p>
p.outerHTML
返回<p>Sample<b>bold</b>display</p>
- getAttribute() / setAttribute() - 获取元素、设置元素属性
- 批注:
- 获取属性值
- 写法:
element.getAttribute('id')
- 写法:
- 自定义属性
- 写法:
element.setAttribute('attribute','value')
(常用) - H5新增的获取自定义属性的方法:
- 添加自定义属性:
element.setAtribute('data-attribute', 'value')
- 以
data-
开头的自定义属性被存放在dataset中
- 以
- 获取自定义属性:
1.element.dataset
(返回自定义属性集合)
2. 获取其中一个自定义属性:
1.element.dataset.attribute
2.element.dataset['attribute']
- 添加自定义属性:
- 写法:
- 修改元素属性值:
- 写法:
element.attribute = 'value'
- 写法:
- 移除属性
- 写法:
element.removeAttribute(属性)
- 写法:
- 获取属性值
- 批注:
常见的DOM mutating operations (修改操作)
- 改变元素内容
element.innerHTML = "this text is <i>important</i>" ;
- 替换内容,保留属性。DOM节点structure (结构)被更新
- 改变标签的属性:
img.src = 'newImage.jpg';
- 使元素可见或者不可见:
- 不可见:
element.style.display = 'none';
- 可见:
element.style.displya = 'block';
- 不可见:
DOM和CSS交互
- 更新元素的class属性
element.className = 'new';
- 批注:会替换原先类名
- 如果想添加class值,可使用
element.classList
- classList 只读属性,返回DOMTokenList
- 可以使用
add(), remove(), replace(), toggle()
方法修改其DOMTokenList的值。
-add(cls1, cls2, cls3)
添加类remove(cls,cls1)
移除类replace(cls,cls2)
将cls
替换为cls2
toggle(cls)
如果cls
已存在,则移除,不存在则添加- 可使用展开语法添加/移除多个类值
const cls = ['foo', 'bar']
div.classList.add(...cls);
div.classList.remove(...cls);
- 如果想添加class值,可使用
- 批注:会替换原先类名
- 更新元素的样式
element.style.color = '#000' // 不是首选方式
- 通过CSS选择器查询DOM
document.querySelector()
和element.querySelectorAll()
更改节点结构
- 创建新元素
element = document.createElement('p');
或者element = document.createTextNode('My text');
- 也可通过
cloneNode()
克隆已经存在的节点- 批注:
- cloneNode(true) 深拷贝- 复制标签以及里面的内容
- cloneNode(false) 浅拷贝 - 复制标签,不复制里面的内容(默认值)
- 批注:
- 将创建的节点添加到已有的节点中
parent.appendChild(element);
或者parent.insertBefore(element, sibling);
- 批注:
appendChild(element)
将元素插入到父级末尾parent.insertBefore(element, sibling)
将元素插入到指定的兄弟节点前面
- 批注:
- 移除节点:
node.removeChild(child);
- 批注:返回被删除的子节点,上面写法不会保留对child的引用,短时间内会被内存管理回收。如果写为
let oldChild = node.removeChild(child)
则会保留对child
的引用。
- 批注:返回被删除的子节点,上面写法不会保留对child的引用,短时间内会被内存管理回收。如果写为
- 虽然但是,用
innerHTML
做这些修改更简单效率也更高- 以数组而不是以字符串拼接的方式
其他DOM操作
- 重定向到一个新页面:
window.location.href = "newPage.html";
- 注意:可能导致JS脚本执行终止
- 批注:
location
其他常见的方法location.assign(url)
- 记录浏览历史,可以回退location.replace(url)
- 不记录浏览历史,不可回退location.reload()
- 强制刷新location.search
- 获取url中的键值对(位于端口后面,?起头)
- 批注:
history
相关的方法history.forward()
- 前进一页history.backward()
- 后退一页history.go(1)
- 前进一页history.go(-1)
- 后退一页
- 和用户交流(communicating with the user)
console.log("Read point A"); // message to browser log
alert("wow!"); confirm("ok?") // 弹出对话框
- 批注:
window.confirm(message)
message
对话框中的可编辑字符串result
是布尔值,表示选择确定还是取消(true表示ok)
DOM坐标系
- 屏幕原点在左上方,垂直方向下降,y值增加(y increase as you go down)
- 元素的位置由其左上角坐标决定
- 用
element.offsetLeft
,element.offsetTop
读取位置 - 坐标相对于
element.offsetParent
, 而其并不完全等价于element.parentNode
- 批注:位置相对于有定位的父级定位,无父级或者父级无定位,以body为准
- 图解如下:
定位元素
- 通常,元素被浏览器自动定位位文档的一部分
- 定位一个脱离文档流的元素:
element.style.position = "absolute" ;
element.style.left = 40px;
element.style.top = "10px";
- 绝对定位的元素会脱离文档流,不在页面中占据空间
- The origin inside an offsetParent (for positioning descendants) is just inside the upper-left corner of its border. offsetParent 中的原点(⽤于定位后代),正好在其边框的左上角内
positioning context
- 每个元素都有一个
offsetParent
,(有些是父级,有些是祖先) - 对于定位过的元素,坐标系(比如:
element.style.left
)返回的是相对于其offsetParent
的位置 - 默认的
offsetParent
是<body>
元素 - 一些元素定义了一个新的positioning context:
position
CSSattribute
isabsolute
(element is explicitly positioned)- 批注:绝对定位的元素相对于最近定位的父级定位,父级祖级无定位,以initial containing block为基准进行定位
position
CSSattribute
isrelative
(element is positioned automatically by the browser in the usual way)- 批注:相对定位的元素针对自身在文档流中的位置进行偏移
- This element will become the
offsetParent
for all its decendents(unless overridden by another positioning context)- 批注:这些已经定位的元素会称为其后代元素的的
offsetParent
- 批注:这些已经定位的元素会称为其后代元素的的
定位子级
-
图解如下:
-
注意:
offsetTop
,offsetLeft
是子级margin
距父级border
的距离
元素尺寸(dimensions)
- 读取尺寸:
element.offsetWidth
和element.offsetHeight
- 返回数值包含元素的:
contents, padding, border,
但是不包含margin
- 返回数值包含元素的:
- 更新尺寸:
element.style.width
和element.style.height
- 批注:
element.offsetWidth
和element.offsetHeight
- 只读属性,不可修改
- 返回值 = 内容区宽高 + padding + border
element.style.width
和element.style.height
- 可修改
- 返回值 = 内容区宽高
document.clientWidth
和document.clientHeight
- 只读,不可修改
- 返回值 = 内容区宽高+padding
- 批注: