DOM
DOM0 到 DOM3 区别?
答案
级别 | 标准化 | 主要内容与特性 | 事件处理方式 | 事件类型扩展 |
---|---|---|---|---|
DOM0 | 否 | 早期浏览器私有API,未标准化,仅支持基本DOM操作 | 直接赋值事件属性(如onclick) | 少量,类型有限 |
DOM1 | 是 | W3C首个标准,定义DOM核心(XML结构)和DOM HTML模块,支持基本节点操作 | 同DOM0 | 基本事件 |
DOM2 | 是 | 扩展节点API,新增视图、事件、遍历、样式等模块,首次引入标准事件模型 | addEventListener/removeEventListener,支持捕获/冒泡 | 类型增多,支持多监听 |
DOM3 | 是 | 增加XPath、加载/保存、验证等模块,事件类型更丰富,支持自定义事件 | 同DOM2 | UI、键盘、合成等更多 |
事件模型与事件流
- DOM2/3 标准事件模型支持捕获、目标、冒泡三阶段,事件流顺序为:捕获 → 目标 → 冒泡。
- 事件捕获:事件从最外层向目标元素传递。
- 事件冒泡:事件从目标元素向外层父节点传递。
Event对象常见应用
- 获取事件目标(event.target)
- 阻止默认行为(event.preventDefault)
- 阻止冒泡(event.stopPropagation)
自动化事件与遍历函数实现
// 遍历DOM树并对每个节点执行回调
function Traverse (parentElement, visit_callback) {
visit_callback(parentElement)
for (const child of parentElement.children) {
Traverse(child, visit_callback)
}
}
延伸阅读
dom.contains
答案
在 DOM(文档对象模型)中,要判断元素 a
是否是元素 b
的子元素,您可以使用以下的 JavaScript 代码:
function isChildElement (a, b) {
return b.contains(a)
}
可以这样使用上述函数:
const elementA = document.getElementById('elementA')
const elementB = document.getElementById('elementB')
if (isChildElement(elementA, elementB)) {
console.log('元素 A 是元素 B 的子元素')
} else {
console.log('元素 A 不是元素 B 的子元素')
}
scrollIntoView api
scrollIntoView api
scrollIntoView
是一个 Web API,允许网页开发者控制元素如何被滚动到浏览器的可视区域。这个方法可以对任何 Element
使用,以改变窗口的滚动位置,以便最终元素位于屏幕可见范围内。它对于某些需要用户立即看到的表单错误、警告,或者在执行完某些操作后需要用户注意的元素比如通知提示尤为有用。
基本用法
element.scrollIntoView(smoothScrollingOptions)
参数说明
smoothScrollingOptions
是一个可选对象。当设定为 false
、undefined
或一个计算值为 false
的值(比如 0
)的时候,滚动操作将以最简单的方式立即执行,而不会平滑过渡。
当为 true
或者一个与滚动行为不冲突的对象时,浏览器会执行一个平滑的滚动动作,逐渐将元素滚动到视野内。
选项
该方法接受一个可选的 ScrollIntoViewOptions
对象,它包含以下属性:
- block: 描述元素应当在其块级方向上的对齐方式。可以是
"start"
、"center"
、"end"
或"nearest"
中的一个。
start
— 元素顶部与包含块的顶部对齐,只有块级元素会被滚动到这个位置。center
— 元素将尽可能被居中对齐地显示。end
— 元素底部将与包含块的底部对齐。nearest
— 元素将滚动到最近的边缘。
-
inline: 描述在元素行进方向的对齐方式。同样可以是
"start"
、"center"
、"end"
或"nearest"
中的一个。 -
behavior: 描述滚动行为。设置为
"auto"
时将使用默认滚动,设置为"smooth"
时将平滑滚动。
例子
document.getElementById('myElement').scrollIntoView({
behavior: 'smooth', // 平滑滚动
block: 'start' // 元素顶部与包含块顶部对齐
})
请注意,scrollIntoView
只能够使元素完全可见,但仍需留意元素灵感中其他内容可能超出视口之外。此外,滚动的方式也可能会受到 Web 浏览器和平台的不同而有所不同,例如一些浏览器可能有最高滚动速度的限制。
基本原理
页面是用户与程序进行交互的界面,在对应表单校验场景中,通常会因为有填写错误需要用户进行修改。为了提高用户体验,可以将页面滚动至对应表单报错的位置,使得用户立即可见错误并进行修改。这通常可以通过 JavaScript 编程实现。
要注意的是,实现滚动至错误表单,一般需要几个步骤:
- 记录表单元素的位置:在表单提交前的适当时间里记录所有表单元素的错误位置。
- 滚动到特定错误:错误发生时,滚动到第一个错误的表单元素位置。
- 优化:可为同一元素多次错误滚动优化,避免不必要的用户干扰。
以下是这些步骤的代码示例
HTML
<form id="myForm" onsubmit="return false;">
<input type="text" id="name" name="name" />
<input type="text" id="age" name="age" />
<!-- ... 其他表单元素 ... -->
<button type="submit" onclick="handleValidation()">Submit</button>
</form>
JavaScript
// 一个假设的表单验证函数
function validateInput (inputId) {
// 调用此处的校验逻辑,返回是否存在错误
// 这里以ID "inputId"来获取对应的DOM对象
const el = document.getElementById(inputId)
// 此处只是示例, 实际上应根据具体的校验逻辑返回一个布尔类型
return el.value === '预期值'
}
function handleValidation () {
let valid = true;
['name', 'age'].forEach((key) => {
// 进行校验判断
if (!validateInput(key)) {
console.error(`Validation failed for: ${key}`)
// 标记校验失败
valid = false
// 滚动到出现问题的元素位置
const element = document.getElementById(key)
element.scrollIntoView({ block: 'center', behavior: 'smooth' })
// 增加一些提示效果, 比如错误边框, 可按需实现
// element.classList.add('error-highlight');
}
})
// 检查是否验证失败,如果失败则不提交表单
return valid
}
// 处理表单提交事件,与HTML中的onclick绑定
document.getElementById('myForm').addEventListener('submit', (e) => {
e.preventDefault() // 阻止表单默认提交行为
handleValidation()
})
documentFragment api 是什么, 有哪些使用场景
DocumentFragment
是 Web API 中的一部分,它是 DOM
(文档对象模型)的一个非常轻量级的节点,代表一组 DOM
节点的集合。它不是一个真实存在于 DOM
中的实体,因此被认为是“没有名字”的节点,或者说它不在文档的主体中渲染,通常用来作为临时的 DOM
节点仓库。
对于 DocumentFragment
的一部分内容,当它们在 DocumentFragment
之外操作时,并不会引起主 DOM 树的直接重排或重绘。然而,一旦你将整个 DocumentFragment
插入到 DOM 的一个永久节点上,那么在 DocumentFragment
内进行的更改将会触发 DOM 的重新渲染。
DocumentFragment API 有几个关键的特点和用途:
-
轻量级:
DocumentFragment
不会引起布局重排,因为其不是真实渲染的一部分。 -
节点集合:可以在
DocumentFragment
中节点集合进行分组,这个集合可以一次性插入到DOM
的某一部分中。 -
性能优化:通过在一个
DocumentFragment
中构建好一大块DOM
树,然后将它整体插入到主DOM
中,从而减少重排次数,提高效率。 -
事件不冒泡:因为
DocumentFragment
不是真实渲染的一部分,所以它的事件不会冒泡到上层的 DOM 元素,除非它被插入到了DOM
中。
使用场景
以下是一些使用 DocumentFragment
的常见场景:
-
批量操作:当你想要一次性添加多个节点到
DOM
树中时,使用DocumentFragment
可以将这些节点预先堆放在一个轻量级对象中,然后一次性添加。 -
离屏操作:如果你需要创建复杂的
DOM
结构,可以通过DocumentFragment
在不触发页面重排和重绘的情况下进行。 -
内容填充:在填充
DOM
元素内容之前,可以先创建一个DocumentFragment
完成所有节点的添加和排序,然后把它添加到DOM
树中。 -
避免内存泄漏:在某些情况下,它可以作为防止因移动节点而造成的内存泄漏的一个办法。
示例代码
// 创建 DocumentFragment
const fragment = document.createDocumentFragment()
// 创建多个节点或元素
const div = document.createElement('div')
const p = document.createElement('p')
// 将节点添加到 DocumentFragment 上
fragment.appendChild(div)
fragment.appendChild(p)
// 一次性将 DocumentFragment 添加到 DOM 的某个部分
const body = document.querySelector('body')
body.appendChild(fragment)
// 这时 div 和 p 被添加至 body 元素,而不会触发额外的布局重排。
DocumentFragment
提供了一个高效的方式去操作 DOM
而不影响页面的渲染性能,在很多需要进行批量 DOM 操作的场合非常有用。