一、DOM
DOM,全称是Document Object Model 文档对象模型 DOM的本质是一棵节点树
1. 节点
节点:Node,是构成HTML文档最基本的单元 通常可以分为四类:
文档节点:整个HTML文档 元素节点:html中的标签 属性节点:元素的属性 文本节点:标签中的文本内容
2. 节点的属性
- nodeName nodeType nodeValue 文档节点 #document 9 null 元素节点 标签名 1 null 属性节点 属性名 2 属性值 文本节点 #text 3 文本内容
3. 获取DOM节点的方法
方法 描述 补充 document.getElementById() 通过id获取一个元素 在实际开发中较少使用,选择器中多用class, id一般只用在顶级层存在 不能太过依赖id document.getElementsByTagName(); 通过标签名获取元素集合 返回符合tagName的所有元素的类数组对象,尽管只找到一个元素也会存到类数组 document.getElementsByClassName(); 通过类名获取元素集合 返回符合className的所有元素的类数组对象 document.getElementsByName(); name属性值 一般不用 document.querySelector(); css选择符模式 返回与该模式匹配的第一个元素,结果为一个元素;如果没找到匹配的元素,则返回null document.querySelectorAll() css选择符模式 返回与该模式匹配的所有元素,结果为一个类数组
4. 节点间的关系
关系 考虑所有节点 只考虑元素节点 子节点 childNodes children 父节点 parentNode parentNode 第一个子节点 firstChild firstElementChild 最后一个子节点 lastChild lastElementChild 前一个兄弟节点 previousSibling previousElementSibling 后一个兄弟节点 nextSibling nextElementSibling
< div class = " box" >
< p class = " item" > 段落1</ p>
< p class = " item" > 段落2</ p>
< p class = " item" > 段落3</ p>
</ div>
< script>
let box = document. querySelector ( '.box' )
console. log ( box. childNodes)
console. log ( box. children) ;
console. log ( box. firstChild)
console. log ( box. firstElementChild) ;
console. log ( box. lastChild) ;
console. log ( box. lastElementChild) ;
</ script>
4.1 封装常见的节点关系函数
返回元素的所有子元素节点(兼容到IE6)
function getChildren ( node ) {
let children = [ ]
for ( let i = 0 ; i < node. childNodes. length; i++ ) {
if ( node. childNodes[ i] . nodeType === 1 ) {
children. push ( node. childNodes[ i] )
}
}
return children
}
获取元素前一个兄弟元素节点,类似于 previousElementSibling
function getElementPrevSibling ( node ) {
while ( node. previousSibling !== null ) {
if ( node. previousSibling. nodeType === 1 ) return node. previousSibling
node = node. previousSibling
}
}
获取所有兄弟元素节点
function getAllElementSibling ( node ) {
let prevs = [ ]
let nexts = [ ]
while ( node. previousSibling !== null ) {
if ( node. previousSibling. nodeType === 1 ) {
prevs. unshift ( node. previousSibling)
}
node = node. previousSibling
}
while ( node. nextSibling !== null ) {
if ( node. nextSibling. nodeType === 1 ) {
nexts. push ( node. nextSibling)
}
node = node. nextSibling
}
return prevs. concat ( nexts)
}
5. 节点的操作
5.1 改变元素节点的内容
属性 说明 innerHTML 以HTMl语法设置节点内容 innerText 以纯文本形式设置节点内容
5.2 改变css样式
语法:元素.style.属性名 = '属性值',属性名是驼峰格式的
let box = document. querySelector ( '.box' )
box. style. color = 'skyblue'
box. style. fontSize = '18px'
5.3 改变元素节点的HTML属性
更改标准W3C属性(如src、herf等):元素.属性名 = '属性值'
let img = document. getElementById ( 'img' )
img. src = 'https://img.mukewang.com/szimg/620b43350928ec7140000576.jpg'
更改非标准W3C属性,要使用 setAttribute、getAttribute
5.4 节点的创建、移除、克隆
方法 说明 document.createElement(‘tagName’) 创建一个指定tagName的HTML元素(孤儿节点) 父节点.appendChild(孤儿节点) 将孤儿节点插入父节点的最后,使其成为最后一个子节点 父节点.insertBefore(孤儿节点,标杆节点) 将孤儿节点插入到标杆节点前面,使其成为标杆节点的前一个兄弟节点 新父节点.appendChild(已经有父亲的节点) 将节点移动到新父节点 新父节点.insertBefore(已有父亲的节点, 标杆子节点) 将节点移动到新父节点 父节点.removeChild(子节点) 将子节点从父节点中删除 cloneNode() 克隆节点,克隆出的节点是孤儿节点。参数表示是否要深度克隆,如果参数为true表示该节点及其后代节点都会被克隆,参数为false表示只克隆节点本身
6. DOM 性能优化
对DOM进行缓存 将频繁的操作改为一次操作或少量操作
二、BOM
BOM(Browser Object Model,浏览器对象模型),JS与浏览器窗口交互的接口
1. window 对象
window对象,是当前JS脚本运行所在的窗口 window.document对象,即document对象 全局变量是window对象的属性,多个JS文件之间共享全局作用域,不会有作用域隔离内置函数一般都是window的方法,如setInterval()、alert()
1.1 窗口尺寸相关属性
属性 描述 innerHeight 浏览器窗口内容区的高度,包含水平滚动条 innerWidth 浏览器窗口内容区的宽度,包含垂直滚动条 outerHeight 浏览器窗口的外部高度 outerWidth 浏览器窗口的外部宽度 document.documentElement.clientHeight 窗口不包含滚动条的高度 document.documentElement.clientWidth 窗口不包含滚动条的宽度 scrollY 垂直方向滚动的距离(只读) document.documentElement.scrollTop 垂直方向滚动的距离 offsetTop 当前元素到定位祖先元素的垂直距离
scrollTop = window. screenY || document. documentElement. scrollTop
1.2 resize事件
窗口大小改变后会触发resize事件 window.onresize 或 window.addEventListener('resize') 绑定窗口改变事件
1.3 scroll事件
窗口滚动时会触发scroll事件 window.onscroll 或 window.addEventListener('scroll') 绑定scroll事件
2. Navigator 对象
window.navigator 包含浏览器的相关属性和标识
属性 说明 appName 浏览器官方名称 appVersion 浏览器版本 userAgent 浏览器用户代理(内核信息和封装壳信息等) platform 用户操作系统
3. history对象
window.hstory 浏览器会话历史 浏览器回退:history.back() 或 history.go(-1)
4.location 对象
window.location 当前所在的网址,可以通过给该属性赋值进行页面跳转 window.location.reload() 重新加载当前页面,可以设置参数,当参数为 true 表示强制从服务器加载widow.location.search 给当前浏览器的get请求查询参数
5. 案例一 —— 返回顶部
<! DOCTYPE html >
< html lang = " en" >
< head>
< meta charset = " UTF-8" >
< meta http-equiv = " X-UA-Compatible" content = " IE=edge" >
< meta name = " viewport" content = " width=device-width, initial-scale=1.0" >
< link rel = " stylesheet" href = " https://at.alicdn.com/t/font_3279057_d1pzygibna.css" >
< title> Document</ title>
< style>
html {
height : 5000px;
}
.top-box {
width : 50px;
height : 50px;
text-align : center;
line-height : 50px;
border-radius : 50%;
background-color : #fff;
box-shadow : 0 2px 4px 0 rgba ( 0, 0, 0, .05) ;
cursor : pointer;
position : fixed;
right : 20px;
bottom : 20px;
display : none;
}
</ style>
</ head>
< body>
< div class = " top-box" >
< span class = " iconfont icon-top" > </ span>
</ div>
< script>
let oTop = document. querySelector ( '.top-box' )
window. onscroll = function ( ) {
let height = document. documentElement. clientHeight
let scrollTop = window. screenY || document. documentElement. scrollTop
if ( height < scrollTop) {
oTop. style. display = 'block'
} else {
oTop. style. display = 'none'
}
}
let timer
oTop. onclick = function ( ) {
clearInterval ( timer)
timer = setInterval ( ( ) => {
document. documentElement. scrollTop -= 200
if ( document. documentElement. scrollTop <= 0 ) clearInterval ( timer)
} , 20 ) ;
}
</ script>
</ body>
</ html>
6. 案例 —— 楼层导航
< ! DOCTYPE html>
< html lang= "en" >
< head>
< meta charset= "UTF-8" >
< meta http- equiv= "X-UA-Compatible" content= "IE=edge" >
< meta name= "viewport" content= "width=device-width, initial-scale=1.0" >
< title> Document< / title>
< style>
* {
padding: 0 ;
margin: 0 ;
}
li {
list- style: none;
}
body {
font: 12 px/ 1.5 Microsoft YaHei, Heiti SC , tahoma, arial, Hiragino Sans GB , "\5B8B\4F53" , sans- serif;
color: #666 ;
}
. right- menu {
position: fixed;
right: 20 px;
top: 100 px;
z- index: 19 ;
width: 50 px;
background- color: #fff;
box- shadow: 0 2 px 4 px 0 rgba ( 0 , 0 , 0 , .05 ) ;
padding: 5 px;
text- align: center;
}
. menu- item {
cursor: pointer;
line- height: 30 px;
}
. menu- item. active {
color: tomato;
}
. line {
width: 30 px;
height: 1 px;
margin: 0 px auto;
background- color: #eee;
}
. content- part {
width: 800 px;
height: 500 px;
background- color: tomato;
margin: 30 px auto;
font- size: 20 px;
color: #fff;
}
< / style>
< / head>
< body>
< ! -- 楼层导航 -- >
< ul class = "right-menu" >
< li data- n= "导航1" class = "menu-item active" > 导航1 < / li>
< li class = "line" > < / li>
< li data- n= "导航2" class = "menu-item" > 导航2 < / li>
< li class = "line" > < / li>
< li data- n= "导航3" class = "menu-item" > 导航3 < / li>
< li class = "line" > < / li>
< li data- n= "导航4" class = "menu-item" > 导航4 < / li>
< li class = "line" > < / li>
< li data- n= "导航5" class = "menu-item" > 导航5 < / li>
< / ul>
< ! -- 内容区 -- >
< div class = "container" >
< div data- n= "导航1" class = "content-part" > 内容区1 < / div>
< div data- n= "导航2" class = "content-part" > 内容区2 < / div>
< div data- n= "导航3" class = "content-part" > 内容区3 < / div>
< div data- n= "导航4" class = "content-part" > 内容区4 < / div>
< div data- n= "导航5" class = "content-part" > 内容区5 < / div>
< / div>
< script>
let oMenu = document. querySelector ( '.right-menu' )
oMenu. onclick = function ( e ) {
if ( e. target. tagName. toLowerCase ( ) === 'li' ) {
let n = e. target. getAttribute ( 'data-n' )
let contentPart = document. querySelector ( ` .content-part[data-n= ${ n} ] ` )
document. documentElement. scrollTop = contentPart. offsetTop
}
}
let menuArr = [ ]
let conParts = document. querySelectorAll ( '.content-part' )
for ( let i = 0 ; i< conParts. length; i++ ) {
menuArr. push ( conParts[ i] . offsetTop)
}
menuArr. push ( Infinity )
let curFloor = - 1
let lis = document. querySelectorAll ( '.menu-item' )
window. onscroll = function ( ) {
let scrollTop = window. screenY || document. documentElement. scrollTop
for ( let i = 0 ; i < menuArr. length; i++ ) {
if ( scrollTop >= menuArr[ i] && scrollTop < menuArr[ i+ 1 ] ) break
if ( curFloor != i) {
curFloor = i
for ( let j = 0 ; j < lis. length; j++ ) {
if ( j === i) {
lis[ j] . className = 'menu-item active'
} else {
lis[ j] . className = 'menu-item'
}
}
}
}
}
< / script>
< / body>
< / html>
三、事件
1. DOM0 级事件监听: onxxx
直接在HTML标签内部书写
< button onclick = " alert(' hello,你找我有啥事啊?' )" > 点我</ button>
通过绑定处理函数的形式
< button class = " btn" id = " btn" > 点我</ button>
< script>
let btn = document. querySelector ( '.btn' )
btn. onclick = function ( ) {
alert ( '你好!!' )
}
</ script>
1.1 常见的鼠标事件
事件 描述 onclick 单击 ondblclick 双击 onmousedown 按下鼠标 onmouseup 松开鼠标 onmousemove 移动鼠标 onmouseenter 鼠标移入(相似事件onmouseover) onmouseleave 鼠标移出(相似事件onmouseout) onmousewheel 鼠标滚动
onmouseenter和onmouseover 都表示鼠标移入,但onmouseenter 不会冒泡,onmouseover 会冒泡
1.2 常见的键盘事件
事件 描述 onkeypress 按下键盘按钮,不能识别系统按钮,如:箭头键、功能键等 onkeydown 按下键盘按钮,可以识别系统按钮,且先于keypress onkeyup 按键被松开
1.3 常见的表单事件
事件 描述 onchange 内容改变 onfocus 获得焦点时 onblur 失去焦点 onsubmit 提交表单 onreset 重置表单
1.4 常见的页面事件监听
事件 描述 onload 页面或图像加载完毕 onunload 退出页面
2. DOM2 级事件监听:addEventListener
2.1 事件传播
事件传播是先从外到内(捕获阶段),再从内到外(冒泡阶段) onxxx只能监听冒泡阶段
2.2 addEventListener
语法: 元素.addEventListener('事件名',function(){},true)
第一个参数是要触发的事件,此时不加 on 第二个参数是事件处理函数 第三个参数为布尔值,true表示监听捕获阶段,false监听冒泡阶段 最内部元素不在区分捕获和冒泡,会先执行前面的监听,后执行后面的监听
同名时,DOM0 中后面的会覆盖前面的;DOM2 级会按顺序执行
3. 事件对象
事件处理函数中提供了一个形参(e 或 event),该形参封装了本次事件的细节,称为“事件对象”
3.1 鼠标位置的相关属性
属性 描述 clientX 鼠标指针相对于浏览器的水平坐标 clientY 鼠标指针相对于浏览器的垂直坐标 pageX 鼠标指针相对于整张网页的水平坐标 pageY 鼠标指针相对于整张网页的垂直坐标 offsetX 鼠标指针相对于事件源元素的水平坐标 offsetY 鼠标指针相对于事件源元素的垂直坐标
3.2 键盘事件中的相关属性
属性 描述 e.charCode 返回 onkeypress 事件中用户输入字符的字符码 e.keyCode onkeydown、onkeyup中,用户按下的键码
字符 字符码 数字 0 ~ 9 48 ~ 57 大写字母 A ~ Z 65 ~ 90 小写字母 a ~ z 97 ~ 122
按键 键码 数字 0 ~ 9 48 ~ 57 不分大小写的字母 a ~ z 65 ~ 90 方向键 ← ↑ → ↓ 37、38、39、40 回车键 13 空格键 32
< body>
< div id = " box" class = " box" > </ div>
< script>
let box = document. getElementById ( 'box' )
let l = 200
let t = 50
document. onkeydown = function ( e ) {
switch ( e. keyCode) {
case 37 :
l -= 5
break
case 38 :
t -= 5
break
case 39 :
l += 5
break
case 40 :
t += 5
break
}
box. style. left = l + 'px'
box. style. top = t + 'px'
}
</ script>
</ body>
3.3 e.perventDefault()
3.4 e.stopPropagation()
4. 事件委托
事件委托:利用事件冒泡机制,将后代元素的事件委托给祖先元素 事件委一般要和 e.target 搭配使用
属性 描述 target 触发此事件最早的元素,即“事件源元素” currentTarget 事件处理程序附加到的元素
应用场景:批量事件监听、新增元素动态绑定事件 事件委托不能委托给不冒泡的(如onmouseenter) 使用事件委托时,最内层元素不能再有额外元素
5. 定时器和延时器
5.1 定时器
setInterval(),定时器可以重复调用一个函数,每次调用之间的时间间隔固定 语法:setInterval(()=>{},time),第一个参数是函数,第二个参数是时间间隔,单位为毫秒,1000ms = 1s,从第三个参数开始表示要传入第一个函数的参数 清除定时器: clearInterval()
< h3 class = " info" > 0</ h3>
< button class = " btn start-btn" > 开始</ button>
< button class = " btn end-btn" > 暂停</ button>
< script>
let oInfo = document. querySelector ( '.info' )
let oStart = document. querySelector ( '.start-btn' )
let oEnd = document. querySelector ( '.end-btn' )
let a = 0
let timer
oStart. onclick = function ( ) {
clearInterval ( timer)
timer = setInterval ( ( ) => {
oInfo. innerHTML = ++ a
} , 1000 )
}
oEnd. onclick = function ( ) {
clearInterval ( timer)
}
</ script>
5.2 延时器
setTimeout(),到达指定时间后会执行一次,不再重复 clearTimeout(),清除延时器
5.3 案例 —— 无缝连续滚动特效动画
< ! DOCTYPE html>
< html lang= "en" >
< head>
< meta charset= "UTF-8" >
< meta http- equiv= "X-UA-Compatible" content= "IE=edge" >
< meta name= "viewport" content= "width=device-width, initial-scale=1.0" >
< title> Document< / title>
< style>
* {
padding: 0 ;
margin: 0 ;
}
li {
list- style: none;
}
. container {
width: 300 px;
height: 50 px;
margin: 50 px auto;
overflow: hidden;
}
. animation- box {
width: 2200 px;
height: 500 px;
margin: 0 auto;
position: relative;
}
. animation- item {
width: 50 px;
height: 30 px;
line- height: 30 px;
text- align: center;
border: 1 px solid tomato;
float: left;
margin- right: 10 px;
}
< / style>
< / head>
< body>
< div class = "container" >
< ul class = "animation-box" >
< li class = "animation-item" > 1 < / li>
< li class = "animation-item" > 2 < / li>
< li class = "animation-item" > 3 < / li>
< li class = "animation-item" > 4 < / li>
< li class = "animation-item" > 5 < / li>
< / ul>
< / div>
< script>
let container = document. querySelector ( '.container' )
let listBox = document. querySelector ( '.animation-box' )
listBox. innerHTML += listBox. innerHTML
let left = 0
let timer
function move ( ) {
clearInterval ( timer)
timer = setInterval ( ( ) => {
left -= 4
if ( left < - 300 ) left = 0
listBox. style. left = left + 'px'
} , 50 )
}
move ( )
container. onmouseenter = function ( ) {
clearInterval ( timer)
}
container. onmouseleave = function ( ) {
move ( )
}
< / script>
< / body>
< / html>