第十二章,BOM
散碎
属性
window {
self 自己窗口
parent 父窗口
top 顶层窗口
devicePixelRatio 通过这个判断是否高分辨率屏幕
...// MDN
}
方法
window {
moveTo(x, y) 移动到指定位置(单位px(只对 window.open打开窗口有效
moveBy(x, y) 移动指定距离(单位px(只对 window.open打开窗口有效
... // MDN
}
定时器(setInterval、setTimeOut、clearInterval、clearTimeOut
第一个参数可以传 js 代码字符串
setTimeOut('alert()', 1000)
模态框
同步对话框(alert、confirm、prompt
- 无法通过 css 修改,
- 显示时阻塞 js 运行
alert(tip) // 单纯只警告
confirm(tip):boolean // 按钮返回布尔值
prompt(tip, inputDefault) // 返回输入框内容
异步对话框(find、print
- 无法通过 css 修改,
- 显示时不会阻塞 js 运行
find(msg) // 返回布尔值,等价于 ctrl + F
print() // 打印窗口
location
属性
原生的解析方法 window.URLSearchParams
简单重写
class URLSearchParams {
params = {}
constructor(qs) {
if (typeof qs !== 'string') throw new TypeError('option must be a string')
qs = qs.substring(1)
qs.split('&').forEach(item => {
const [key, value] = item.split('=')
this.params[encodeURIComponent(key)] = encodeURIComponent(value)
})
}
has(key) {
return this.params[key] !== undefined
}
get(key) {
return this.params[key]
}
delete(key) {
delete this.params[key]
}
[Symbol.iterator] = () => {
return Object.entries(this.params)[Symbol.iterator]()
}
}
操作
- window.location & location.href
window.location = 'http://www.baidu.com'
location.href = 'http://www.baidu.com'
location.assign('http://www.baidu.com')
因为前两句改变后会触发 location.assign 同样的,改变其他属性也是如此;都是 push 模式
- replace(替换,无法后退
- reload(刷新,接受一个 boolean 参数,是否强制刷新,不用缓存
navigator
主要是一些浏览器信息,比如版本号,所在环境,GPU...
screen
显示器信息,什么位深,色深...
history
- 前进后退
.go(step: number) // 前进 or 回退 step 步
.back() // 回退
.forward() // 前进
- 历史状态管理
由于以前地址栏变化,一定会引起重新请求,后来推出了 历史状态管理 概念,也就是通过 history 的 pushState,replaceState 来改变地址栏而不发起请求。
.pushState(
state: {data: 'data'}, // 序列化对象
title: string, // 页面标题,目前大部分浏览器忽略此参数,任然需要但不起效
href: string // 必须与源地址同源的地址,可以之间传文档路径
)
.replaceState // 同上,但不添加而是覆盖当前记录
既然这种方式替换路径不会引起请求,那么就适合用作单页应用的路由管理 但刷新后会真实请求当前路径,需要后端做重定向处理。
- 其他
.length // 会话历史长度
.state // 当前会话状态对象
第十三章,客户端检测
主要是一些
- 能力检测:支不支持脚本啦,支不支持什么功能啦...
- 用户代理检测:浏览器的信息,什么名字,版本,...
- 一些操作系统、浏览器、硬件、设备位置、电池状态...
第十四章,DOM
散碎
NodeList 与 HTMLCollection、NamedNodeMap
- 类数组
- 实时数组,随文档变化
- HTMLCollection 多一个 namedItem 方法(以 name 属性值访问节点)
- querySelectorAll 返回 NodeList 快照,并非实时
Node 类型
DOM 一共有 12 中类型,以此为基类,确定类型的方法如下: Node.类型名 === node.nodeType
类型名如下:
Element 类型(nodeType = 1
- 随便打印一个 div 元素,他的原型链是这样的:
HTMLDivElement --> HTMLElement --> Element --> Node --> EventTarget --> Object
- tagName 返回 标签名的大写形式
节点关系
.childNodes
- NodeList 类数组(这个有:forEach、values、keys、entries
- 实时反应此节点的子节点情况,并非快照
- 代码换行和空格会成为 text 节点出现在内(.children 不会)
- 里面的节点保持有双链表关系(非循环)(指针为:.previousSibling 和 .nextSibling)
.firstChild 和 .lastChild
分别指向 .childNodes[0] 和 .childNodes[childNodes.length - 1]
.hashChildNodes
是否有子节点;返回布尔值
由于空白节点会成为节点出现在 childNodes 上,所以在定位的时候会很麻烦 之前的 childNodes、firstChild、lastChild、previousSibling、nextSibling都有了替换项 分别是 children、firstElementChild、lastElementChild、previousElementSibling、nextElementSibling
节点操作
注:如果添加的节点已经存在文档中,那么会移动此节点
同一个节点不会在文档中同时出现在两个或更多个地方
parentNode.appendChild(newNode):newNode // 添加节点到所有子节点最后面
parentNode.insertBefore(newNode, childNode):childNode // 添加到指定节点最前面
parentNode.insertBefore(newNode, null):childNode // 添加到子节点最后面
parentNode.replaceChild(newChild, childNode):childNode // 替换子节点
parentNode.removeChild(childNode):childNode // 删除子节点
node.cloneNode(isDeep) // 拷贝节点(不会复制 js 添加的属性 和 事件处理程序
node.createElement('tagName') // 创建 Element 节点
//节点就可以使用(缩小范围),不一定非得 document.
node.getElementByClassName('className')
node.querySelector('css选择器')
//......
属性
下面两种属性大部分都是相通的,互相影响;特殊情况已列出
DOM 属性
const container = document.querySelector('.container')
container.xxx
HTML 属性
<div class="container" dir="rtl" style="color: red;" onclick="test()"></div>
HTML 属性操作(一般都用于自定义属性,其他用到的地方很少;但其实自定义属性也一般用 DOM 属性的 dataset 了。
container.getAttribute('key') // 获取
container.setAttribute('key', value) // 添加/替换
container.removeAttribute('key')
DOM 属性 与 HTML 属性差异
- class
container.className === container.getAttribute('class') // true
container.getAttribute('className') // null
- style
container.style // CSSStyleDeclaration 对象
container.getAttribute('style') // "color: red;"
- 事件处理程序
container.onclick // test 函数引用,没有则是 null
container.getAttribute('onclick') // "test()"
- 自定义属性
- 自定义属性不会成为 DOM 属性(但会体现在 attributes 属性上)
- HTML5 规定自定义属性以 data- 开头,不然不会添加到 DOM 属性的 dataset 对象中
<div class="container" data-self="msg"></div>
container.getAttribute('data-selef') === container.dataset['self'] // true
attributes
HTML 属性会反映在 DOM 属性 attributes 上
Document 类型(nodeType = 9
全局 document 原型链
HTMLDocument --> Document --> Node
子节点类型
document 的子节点类型只能是 DocumentType(比如) Element(html) ProcessingInstruction(xml) Comment(注释)
iframe 文档跨域
取决于响应头中的 Content-Security-Policy字段
其他集合
实时集合
- .anchors 所有带有 name 属性的 a 元素
- forms 所有 forms 元素
- images 所有 images 元素
- links 所有带有 href 的 a 元素
文档写入
document.write/writeln/open/close
write 和 writeln 就是后者写入后会多个换行;调用如果在加载页面后调用,页面则会被输出内容重写
调用 open 和 close 可以更好的控制何时写入何时结束,open 调用后文档子节点会清空
Text 类型(nodeType = 3
一般来说,大部分业务场景都能用 innerText 代替文本节点的操作方法 echars 的大量数据就用的 appendData
- 对于相邻的文本节点,可以执行以下 normalize 方法,将相邻文本节点合成一个
parentNode.normalize()
- 操作
textNode.appendData(text) // 往后增加 text
textNode.deleteData(start, count) // 从 start 出开始删除 count 个字符
textNode.insertData(start, text) // 在 start 前添加 text
textNode.replaceData(start, count, text) // 用法类似 array.splice。替换 start 到 start + count 为 text(左闭右开
textNode.splitText(offset) // 从 offset 位置拆分文本,原文本节点保留 [0, offset),返回 [offset, length - 1]
textNode.substringData(start, count) // 从 start 开始提取 count 个字符 [)
doc.createTextNode()
Comment 类型 (nodeType = 8
注释节点,和 Text 节点拥有类似方法,因为他们继承同一基类 CharacterData
document.createComment() // 创建注释
CDATSection 类型 (nodeType = 4
继承 Text 类型;只在 XML 中有效
DocumentType 类型(nodeType = 10
<!DOCTYPE xxx>
**DocumentFragment **类型(nodeType = 11
- 继承自 Node 所以可以像 document 那样使用,但是他只作为一个存放节点的仓库
- 如果文档中有节点被添加到文档片段,那么这个节点会在文档树中被删除
<div class="pop">hello</div>
//
const pop = document.querySelector('.pop')
const documentFragment = document.createDocumentFragment()
documentFragment.appendChild(pop)
// pop 会在页面被移除
- 添加进文档的时候,文档片段本身不会被添加,只是他的子节点会被添加,且文档片段的子节点会被清空
console.log(documentFragment.childNodes) // NodeList[div.pop]
parentNode.appendChild(documentFragment)
console.log(documentFragment.childNodes) // NodeList[]
Attr 类型(nodeType = 2
一般就是 attributes 属性
document.createAttribute() // 创建属性节点
表现形式:
将属性作为节点来访问多数情况下并无必要。推荐使用 getAttribute()、 removeAttribute() 和 setAttribute() 方法操作属性,而不是直接操作属性节点。
DOM 编程
动态脚本
- 添加外部 js
const script = document.createElement('script')
script.src = 'demo.js'
document.body.appendChild(script)
- 添加 js 源代码
const script = document.createElement('script')
script.text = 'function test(){ alert(1) }; test()'
document.body.appendChild(script)
用 innerHTML 添加的 script 代码永远不会执行
动态样式
也是同上可以通过创建 link 或者 style 节点进行添加,往 style 中添加内容可以用 innerText 或者 文本节点的方式都行。
操作表格
同上,但是相当繁琐,所以 table 元素自带了很多操作函数和访问属性
MutationObserver
MutationEvent 已废弃
切勿以为每次改变后回调都会执行,他的形式是 回调+记录队列 的形式;也就是每次改变都会添加到记录队列 mutationRecords 里,回调只在本次执行上下文观察到改变后执行一次
<div class="container"></div>
<div class="footer"></div>
<script>
const container = document.querySelector('.container')
const footer = document.querySelector('.footer')
// Boolean 配置默认值都是 false,至少有一个 Boolean 配置为 true
const MutationObserverInit = {
subtree: false, // 是否观察子节点的各种变化
characterData: false, // 是否观察文本节点变化(注:是文本节点的文本,不是节点的文本
attributes: true, // 是否观察属性值变化,不包括自定义 DOM 属性;包括 DOM、HTML、自定义 HTML 属性
childList: false, // 是否观察子节点变化(自身的 childNodes
characterDataOldValue: false, // 是否需要旧值,体现在 mutatedRecord 实例的 oldValue 上
attributeOldValue: false // 是否需要旧值,体现在 mutatedRecord 实例的 oldValue 上
// attributeFilter: [] // 字符串数组,指定需要观察的属性
}
// 异步回调,微任务;会在观察的对象发生范围内的变化时添加到微任务队列中
const observer = new MutationObserver((mutationRecords, _observer) => {
console.log(mutationRecords, _observer === observer) // ⑤:[MutationRecord, MutationRecord, MutationRecord] true
})
// ①每次改变,改变记录会被存在记录列表,当异步回调执行时传递记录列表过去
observer.observe(container, MutationObserverInit)
observer.observe(footer, MutationObserverInit)
container.className = 'newClass'
container.id = 'app'
container.dataset.msg = 'msg'
container.自定义DOM属性 = '自定义DOM属性值' // 不会被观察到
// ②取消观察,属于一刀切,会断开一切观察关系;前面的改变也不会被观察到了;不会结束实例生命周期
observer.disconnect()
container.className = 'disconnect-container' // 不会被观察到
footer.className = 'discooent-footer' // 不会被观察到
// ③任然可以继续观察
observer.observe(container, MutationObserverInit)
container.className = 'newClass' // 至于是在这段代码后执行后添加异步回调,还是同步代码执行完添加,这不重要!
container.id = 'app'
container.dataset.msg = 'msg'
// ④提前取出记录列表,取出后回调不执行,但并未断开连接
console.log(observer.takeRecords()) // [MutationRecord, MutationRecord, MutationRecord]
// ⑤这才是回调所打印到的记录
container.className = 'newClass'
container.id = 'app'
container.dataset.msg = 'msg'
</script>
- mutationRecords
设置元素文本内容的标准方式是 textContent 属性,innerText 的定义不严谨,浏览器间的实现也存在兼容性问题,因此不建议再使用了。
第十五章,DOM扩展
元素查找
querySelectorAll 返回 NodeList 快照,并非实时 matches 返回 boolean 是否有这个元素
HTML5
- classList 不是数组
DOMTokenList实例
- document.activeElement
始终指向目前的焦点,默认情况下页面加载前为 null ,页面加载完后指向 body
多用于无障碍功能
- document.readyState
loading:文档正在加载
complete:文档加载完成
- document.compatMode
CSS1Compat:标准模式
BackCompat:混杂模式
- outerHTML
返回包括自身的序列化 DOM
<div class="box">1</div>
<script>
const box = document.querySelector('.box')
box.outerHTML = '<h1>he</h1>' // 会取代 <div class="box">1</div>
</script>
- scrollIntoView
相对于第一个可滚动容器
/**
option 为布尔值
true: 滚动到顶部
false: 滚动到底部
option 为配置对象
{
behavior: 'auto', // 滚动动画 smooth auto
block: 'start', // 滚动到容器中垂直位置 start center end nearest
inline: 'nearest' // 滚动到容器中水平位置 start center end nearest
}
*/
element.scrollIntoView(option)
当元素聚焦时,聚焦元素也会滚动到可视范围,默认无动画,居中
- contains 与 compareDocumentPosition
判断参数和调用者关系
parentNode.contains(child: Node): boolean // 是否为后代
parentNode.compareDocumentPosition(child: Node): number
// 相对于 child 而言
0x1 不在
0x2 在前面
0x4 在后面
0x8 包含
0x10 被包含
child 是 parentNode 的后代, compareDocumentPosition 会返回 20,0x14; 异于常规思想;因为 child 既被包含,也在parentNode后面
- innerText 和 outerText
非标准 在用于读取值时, innerText 会按照深度优先的顺序将子树中所有文本节点的值拼接起来。在用于写入值时,innerText 会移除元素的所有后代并插入一个包含该值的文本节点。
第十六章,DOM2和DOM3
XML:一种数据格式,多用于存储数据,配置(类似 JSON 的功能
HTML:一种数据格式,多用于定义页面
XHTML:HTML 的严格子集,比如必须闭合标签、必须小写....
本章关于 XML 和 XHTML 略
node.style.float // ❌
node.style.cssfloat // ✔
// 节点
node.isSameNode(node: Node): boolean // 是否相同节点(引用相同
node.isEqualNode(node: Node): boolean // 节点是否相等(深克隆
// iframe
iframe.contentDocument
iframe.contentWindow
......