系统化学习前端之JavaScript(DOM)
前言
学习了 JavaScript,如何关联 HTML 和 CSS 呢?没错,DOM 就是干这个的。
DOM
Document Object Model,文档对象模型,专门操作网页内容的 API 标准。
DOM 操作页面内容
网页内容是由多个 DOM 元素以树结构组合而成,也称为 DOM tree。DOM 元素包含 HTML标签,标签属性,内容以及样式。简而言之,一组标签元素就是一个 DOM 元素,标签内可以有内容、属性,也可以有样式,如 <div></div>
。
DOM 操作页面内容就是 JavaScript 利用 DOM API 操作 HTML标签,内容以及样式(CSS)。
注意:很多文章会由 Node 节点介绍页面内容,其实 Node 节点和 DOM 元素是一致的,唯一的不同在于 Node 节点包含空白节点,即 Node 节点 = DOM 元素 + 空白节点。
DOM 元素新增
-
创建元素
var elem = document.createElement('a'); // <a></a>
document.createElement()
接收 HMTL 标签名作为参数,返回 HTML 标签元素,即 DOM 元素。 -
添加属性
elem.href = 'https://www.baidu.com'
elem
元素更应该看作是对象,通过.
的方式设置添加属性。 -
添加内容
elem.innerHTML = '百度' elem.textContent = '百度'
elem.innerHTML
既可以添加文本内容,也可以添加标签元素,如elem.innerHTML = '<span>百度</span>'
。elem.textContent
只能添加文本内容,添加标签元素无法解析成 HTML 标签。注意:
elem.outerHTML
是指包含标签的文本字符串,如在<span>百度</span>
中elem.outerHTML
为'<span>百度</span>'
,而elem.innerHTML
只是'百度'
。 -
添加样式
elem.style.color = 'red' elem.style.fontSize = '20px' elem.style.cssText = 'color: red; font-size: 20px' // 复合写法
elem.style.attr
的方式可以为标签元素添加样式,添加的样式为行内式。 -
挂载元素
根据元素挂载位置不同,可以选择不同的 API 。
-
末尾追加
parent.appendChild(elem) // parent 为 elem 元素的父元素,即 elem 元素添加至 parent 元素内的末尾
-
中间插入
parent.insertBefore(elem, x) // elem 元素添加至 parent 元素内,且在 x 元素之前
注意:可以通过
x.previousElementSibling
和x.nextElementSibling
来选择插入 x 元素的上一个兄弟元素或下一个兄弟元素之前(x 元素之后)。 -
替换
parent.replaceChild(elem, x) // 在 parent 元素内,使用 elem 元素替换 x 元素
注意:上述方式只能无法一次添加多个元素,多次添加的话,会造成 DOM 树多次重排,影响性能。
-
-
批量挂载
使用文档片段的方式批量添加,将多个 DOM 元素添加至文档片段中,最后将文档片段添加至DOM tree 中。
var frag = document.createDocumentFragment() frag.appendChild(elem1) // 添加 elem1 元素 frag.appendChild(elem2) // 添加 elem2 元素 parent.appendChild(frag)
DOM 元素删除
-
删除元素
parent.removeChild(elem) // 从 parent 元素中删除 elem 元素。
-
删除元素属性
-
DOM 对象的方式
elem.id=''
-
DOM API 的方式
elem.removeAttribute('id')
-
-
删除元素内容
elem.innerHTML = '' elem.textContent = ''
-
删除元素样式
elem.style.color = '' elem.style.fontSize = '' elem.style.cssText = ''
DOM 元素修改
-
修改元素
修改元素:先删除,再新增即可。
-
修改元素属性
-
DOM 对象的方式
elem.className = 'wrapper'
注意:
class
属性在 DOM 对象方式下,需要变为className
,表单的for
属性需要变为hmlFor
。 -
DOM API 的方式
elem.setAttribute('class', 'wrapper')
注意:
setAttribute()
第一个参数为属性名,第二个参数为属性值,属性名不需要改变。表单属性中的状态属性:disabled
,checked
,selected
只能通过 DOM 对象的方式修改,不能使用 DOM API方式。
-
-
修改元素内容
elem.innerHTML = 'baidu' elem.textContent = 'baidu'
-
修改元素样式
elem.style.color = 'blue' elem.style.fontSize = '16px' elem.style.cssText = 'color: blue; font-size: 16px;'
DOM 元素查询
-
查询元素
-
直接查询元素
document.documentElement
即html
元素。document.head
即head
元素。document.body
即body
元素。 -
关系查询
elem.parentElement
即elem
的父元素。elem.children
即elem
的子元素,返回子元素构成的类数组对象。elem.previousElementSibling
即elem
的前一个兄弟元素。elem.nextElementSibling
即elem
的后一个兄弟元素。 -
DOM API 查询
document.getElementById()
按 id 查询单个元素,返回最先找到的结果,如document.getElementById('app')
。parent.getElementsByClassName()
按 class 查询,返回父元素下相同类名的动态结果集,如parent.getElementsByClassName('wrapper')
。parent.getElementsByTagName()
按 标签名 查询,返回父元素下相同标签名的动态结果集,如parent.getElementsByTagName('div')
。parent.querySelector()
按 选择器 查询单个元素,返回父元素下最先找到的结果,如parent.querySelector('#app')
。parent.querySelectorAll()
按 选择器 查询,返回父元素下满足选择器的静态结果集,如parent.querySelectorAll('.wrapper')
。注意:
a. 只有
getElementById()
是仅能用过document
调用的。b.
querySelector()
和querySelectorAll()
参数是需要添加选择器标识的。c.
getElementById()
和querySelector()
是查询单个元素的,均为非贪婪查询。d. 动态结果集是指查询完成以后,
parent
继续新增元素,当元素满足时,结果集依然能够体现;静态不可以。
-
-
查询元素属性
-
DOM 对象的方式
elem.title // 返回 undefined 表示属性不存在
-
DOM API 的方式
var isHas = elem.hasAttribute('title') // 返回 bool 值,表示是否具有 title 属性 var val = elem.getAttribute('title')
-
自定义属性
定义自定义属性
<div data-count="3"></div>
查询自定义属性
elem.dataset.count // DOM 对象 var val = elem.getAttribute('data-count') // DOM API
修改自定义属性
elem.dataset.count = 4 // DOM 对象 elem.setAttribute('data-count', 4) // DOM API
-
-
查询元素内容
elem.innerHTML elem.textContent
-
查询元素样式
-
查询行内样式
elem.style.color elem.style.fontSize elem.style.cssText
-
查询计算后样式(实际应用样式)
var style = getComputedStyle(elem) style.color // DOM 对象方式 var value = style.getPropertyValue('color') // DOM API 方式
注意:计算后样式只能读取,不能修改。
-
DOM 操作页面交互
页面交互是指用户或浏览器执行一些操作,触发 JavaScript 通过 DOM API 操作页面给予反馈。
DOM 操作页面交互就是 JavaScript 通过事件触发执行处理函数进行页面内容改变,达到交互目的。
事件流程
事件是由浏览器定义的触发机制,可以完成一个由人操作到计算机操作的过程。当用户执行一定的操作(人操作)时,事件会触发,执行事件回调函数进行处理操作(计算机操作)。
-
绑定事件
-
HTML 绑定
<div onclick="handleClick()">点击事件</div> <script type="text/javascript"> function handleClick() { console.log(123) } </script>
注意:
click
为事件名,handleClick
为事件回调函数。 -
DOM 对象绑定
<div id="app">点击事件</div> <script type="text/javascript"> var div = document.getElementById('app') div.onclick = function () { console.log(123) } </script>
-
DOM API 绑定
<div id="app">点击事件</div> <script type="text/javascript"> var div = document.getElementById('app') function handleClick() { console.log(123) } div.addEventListener('click', handleClick) </script>
注意:HTML 方式和 DOM 对象方式都是
on + 事件名
的形式绑定事件, -
-
移除事件
-
DOM 对象移除
div.onclick = null
-
DOM API 移除
div.removeEventListener('click', handleClick)
-
-
事件回调函数
事件回调函数是一个特殊的函数,需要通过事件触发去调用,并且当不传参的时候,事件回调函数默认会传入一个事件对象作为参数。
<div id="app">点击事件</div> <script type="text/javascript"> var div = document.getElementById('app') function handleClick(event) { console.log(event) // PointerEvent } function fun(event) { console.log(event) // undefined } div.addEventListener('click', handleClick) fun() </script>
注意:
PointerEvent
为事件对象的一种类型,事件对象还有其他类型,如keyboradEvent
,MouseEvent
等。事件对象是指包含事件过程所有详细信息的对象,包括触发事件的元素,元素的 x,y 位置信息等。事件对象的重要方法:
-
event.stopPropagation()
中断嵌套元素的事件冒泡。低版本浏览器使用
window.event.cancelBubble = true
。 -
event.preventDefault()
阻止元素的默认行为,如
a
标签的默认链接跳转行为。低版本浏览器使用e.returnValue = false
。 -
event.stopImmediatePropagation()
元素绑定事件有多个事件回调函数,默认事件触发会执行多个事件回调函数,stopImmediatePropagation 会阻止其他事件回调函数执行,只执行当前事件回调函数。
-
事件模型
嵌套元素的父、子元素均绑定事件,事件触发以后如何执行事件回调函数呢?
<style type="text/css">
#app {
width: 300px;
height: 300px;
border: 1px solid #ccc;
}
#wrapper {
width: 100px;
height: 100px;
margin: 100px auto 0;
background-color: skyblue;
}
</style>
<div id="app">
<div id="wrapper"></div>
</div>
<script type="text/javascript">
var app = document.getElementById('app')
var wrapper = document.getElementById('wrapper')
app.onclick = function () {
console.log('app')
}
wrapper.onclick = function () {
console.log('wrapper')
}
// 点击 wrapper 执行结果为 wrapper app
</script>
嵌套元素的绑定事件涉及到了 JavaScript 的事件模型,事件模型包含三个阶段:捕获阶段、触发阶段、冒泡阶段。
-
捕获阶段
JavaScript 执行以后,根据嵌套元素的嵌套层次,按照由外向内的捕获事件,并将事件回调函数添加至函数调用栈。
-
触发阶段
事件触发,根据事件触发的元素,函数调用栈指针移动至对应事件回调函数,执行对应事件回调函数。
-
冒泡阶段
执行完事件触发元素的事件回调函数后,函数调用栈执行会自动向栈底移动,依次执行到栈底的所有事件回调函数。
注意:
a. 在子元素的事件回调函数中,通过事件对象的方法event.stopstopPropagation()
可以中断事件模型中的冒泡阶段 。b. 在父元素的事件绑定中,通过
elem.addEventListener()
的第三个参数可以改变冒泡顺序,前面两个参数分别为事件名和事件处理函数,第三个参数可以缺省,参数值是 boolean 类型,默认是 false,表示嵌套元素的事件回调函数由内向外依次执行,设置为 true,表示事件回调函数由外向内依次执行。
事件委托
事件委托利用了事件模型中的冒泡特性,采取将嵌套元素中子元素的事件绑定到父元素上,子元素触发事件会冒泡执行父元素的事件回调函数。
<div id="app">
<div class="wrapper">1 号元素</div>
<div class="wrapper">2 号元素</div>
<div class="wrapper">3 号元素</div>
</div>
<script type="text/javascript">
var app = document.getElementById('app')
function handleClick (event) {
console.log(event)
}
app.addEventListener('click', handleClick)
</script>
以上,点击任意一个子元素均会触发父元素的 click 事件,并执行事件回调函数,这种模式被称为事件委托。事件委托可以减少事件监听的个数,此外,也具备动态性(新增子元素也可以触发事件)。
注意:可以通过事件对象
event.target
获取触发事件的元素。
常见事件
-
点击事件
click
鼠标单击时触发。dblclick
鼠标双击时触发。touch
移动端事件,触摸屏幕触发。touchstart
移动端事件,触摸按下时触发。touchmove
移动端事件,触摸移动时触发。touchend
移动端事件,触摸抬起时触发。注意:
移动端重叠元素 A 和 B ,A 在 B 之上,A 绑定
touchstart
事件,B 绑定click
事件,点击 A 以后,会触发 B 的click
事件,这种现象被称点击穿透现象。造成点击穿透的原因: 移动端
touchstart
触发以后,300ms 内会自动触发一个click
事件,延迟 300ms 是为了判断是否是双击放大功能。解决点击穿透的方法:
-
在移动端不要混合使用
touchstart
和click
事件。 -
使用
event.preventDefault()
阻止touchstart
的默认行为。 -
绑定
touchstart
事件的元素设置pointer-events: auto;
属性。 -
设置延迟 300ms 后执行
touchstart
事件。 -
设置
touch-action:manipulation;
属性,取消延迟。
-
-
键盘事件
keypress
键盘按键时触发。keydown
键盘按键按下时触发。keyup
键盘按键弹起时触发。 -
鼠标事件
mouseenter
和mouseover
鼠标移入时触发,mouseover
鼠标在移入目标元素嵌套的元素时会再次触发。mouseleave
和mouseout
鼠标移出时触发,mouseout
鼠标从嵌套的元素移出到目标元素时会再次触发。mousemove
鼠标移动时触发。mousedown
鼠标按下时触发。mouseup
鼠标弹起时触发。mousewheel
鼠标滚轮滚动时触发。 -
页面事件
load
页面加载完成时触发。pagehide
页面隐藏时触发。pageshow
页面显示时触发。resize
页面缩放时触发。scroll
页面滚动时触发。注意:
scroll
也可以监听区域内容滚动,需要设置overflow: auto
或overflow: scroll
。popstate
页面回退时触发。注意:popstate 只能监听页面有刷新的后退操作,如
history.go(-1)
,history.back()
,无法监听无刷新页面的操作,如history.pushState()
,history.replaceState()
,可参考 BOM 中的 history 对象。 -
动画事件
animationstart
动画开始时触发。animationend
动画结束时触发。transitionstart
过渡开始时触发。transitionend
过渡结束时触发。 -
拖放事件
参考 HTML5 拖放 API。
-
表单事件
input
表单元素 input 输入时触发。blur
表单元素 input 失焦时触发。focus
表单元素 input 聚焦时触发。change
表单元素 input 输入值改变时、select option改变时、radio、box选中改变时触发。submit
表单元素 form 提交时触发。reset
表单元素 form 重置时触发。 -
媒体事件
参考 HTML5 音视频。
自定义事件
-
定义事件对象
var e = new Event('customClick') // customClick 为自定义事件名称 var e = new CustomEvent('customClick', { detail: 'ming' })
注意:
CustomEvent()
可以通过detail
属性传递数据,通过事件对象event.detail
可以接受数据。 -
绑定事件对象
var app = document.getElementById('app') function handleClick(event) { console.log(event) } app.addEventListener('customClick', handleClick)
-
触发事件对象
app.dispatchEvent(e)
注意:自定义事件需要调用触发。
-
移除事件对象
app.removeEventListener('customClick', handleClick)
后记
DOM 文档对象模型,提供了丰富的 API,利用这些 API 可以完成 JavaScript 与 HTML、CSS 的勾连。正式 DOM 的存在才使得 JavaScript 能够操作页面内容,完成页面复杂的交互。
本文来自博客园,作者:深巷酒,转载请注明原文链接:https://www.cnblogs.com/huangminghua/p/17197791.html