DOM操作

DOM

css文件的加载是与DOM的加载并行的,也就是说,css在加载时Dom还在继续加载构建,而过程中遇到的css样式或者img,则会向服务器发送一个请求,待资源返回后,将其添加到dom中的相对应位置中,由于js文件不会与DOM并行加载,因此需要等待js整个文件加载完之后才能继续DOM的加载,

js加载原理

​ 浏览器内核可以分成两部分:渲染引擎(Layout Engine 或者 Rendering Engine)和 JS 引擎。早期渲染引擎和 JS 引擎并没有十分明确的区分,但随着 JS 引擎越来越独立,内核也成了渲染引擎的代称(下文我们将沿用这种叫法)。渲染引擎又包括了 HTML 解释器、CSS 解释器、布局、网络、存储、图形、音视频、图片解码器等等零部件。

JS 引擎是独立于渲染引擎存在的。我们的 JS 代码在文档的何处插入,就在何处执行。当 HTML 解析器遇到一个 script 标签时,它会暂停渲染过程,将控制权交给 JS 引擎。JS 引擎对内联的 JS 代码会直接执行,对外部 JS 文件还要先获取到脚本、再进行执行。等 JS 引擎运行完毕,浏览器又会把控制权还给渲染引擎,继续 CSSOM 和 DOM 的构建。 因此与其说是 JS 把 CSS 和 HTML 阻塞了,不如说是 JS 引擎抢走了渲染引擎的控制权

  1. 正常引入js,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行
  2. async,script.js会被异步加载,即加载和渲染后续文档元素的过程将和 script.js 的加载并行进行(异步)。当 script.js加载完整立即执行script.js。执行script.js时,html解析暂停。从加载完成立即执行来看,async模式 执行顺序与写的顺序无关,不保证执行顺序

<script async src="script.js"></script>

  1. defer,script.js会被异步加载,即加载和渲染后续文档元素的过程将和 script.js 的加载并行进行(异步)。这一点与async模式一致。不同的是当 script.js加载完成并不会立即执行,而是在所有元素解析完成之后

<script defer src="script.js"></script>

  1. onload,你可以将你的js代码写在window.onload(()=>{……})中,会在页面渲染完执行js代码

  2. 使用时机

  • 当你的js是个独立的模块且不依赖任何js,使用 async;
  • 如果你的js依赖其他js或者被其他js 依赖,使用 defer;
  • 如果你对js文件很小且被 async script 依赖,使用正常模式的script且放在async script 前面。

document

使用console.dir(e) 可以查看元素的解构信息

1. 相关属性

  • title
  • url => http://127.0.0.1:8848/My/index3.html
  • domain => 127.0.0.1
  • charset => UTF-8
  • body,forms,head,links,images,documentElement(html节点),anchors(锚点)

2. 相关方法

2.1、HTMLCollection和NodeList
  • document.getElementsByTagName 返回匹配标签名的HTMLCollection类数组

  • document.querySelectorAll 返回匹配选择器的NodeList类数组

  • HTMLCollection提供通过name或id直接获取元素、item(index)通过下标选取元素以及namedItem(id/name)通过id或name获取元素的方法,

  • NodeList提供了同数组一样的entries,forEach,keys,values还有item,二者都可以通过Array.from或者三点符号转为数组

2.2、元素关系
  • 此处所说的子元素指的是直接子元素
  • 也有选取节点的方法,例如childNodes、parentNode、firstChild、lastChild、nextSibling、previousSibling,但获取的结果可能并不是我们想要的,因为会参杂文本注释等节点
节点属性说明返回值/不存在时候值
parentElement获取父元素Element/null
children获取所有子元素HTMLCollection/[]
childElementCount子标签元素的数量n/0
firstElementChild第一个子标签Element/null
lastElementChild最后一个子标签Element/null
previousElementSibling上一个兄弟标签Element/null
nextElementSibling下一个兄弟标签Element/null
contains返回布尔值,判断传入的节点是否为该节点或其的后代节点true/false
2.3、选取元素
  • 拥有id的元素可以直接作为window的属性来访问,但不能和window属性重名,也不建议直接使用,语义不明确
  • 以下前四种方法只支持document访问
  • document获取的集合顺序为元素在文档中的顺序
  • 使用getElement…返回的都是动态的集合,也就是说当添加或修改页面元素时,返回的集合也会同步改变,而使用querySelectorAll返回的是静态集合,页面修改返回集合也不会修改,相当于一个固定快照
方法名说明返回值
getElementById根据id唯一获取元素Element
getElementsByName获取设置了name属性的元素集合NodeList[]
getElementsByTagName按标签名获取元素集合,传入*获取全部HTMLCollection[]
getElementsByClassName按class样式属性值获取元素集合HTMLCollection[]
querySelectorAll根据CSS选择器获取Nodelist节点列表,支持元素获取NodeList[]
querySelectorquerySelector使用CSS选择器获取一个元素Element
matchs用于检测元素是否是指定的样式选择器匹配boolean
closest查找最近的符合选择器的祖先元素(包括自身)element
2.4、操作属性
  • 常见内置属性:className(指向class)、hidden、src 、alt、href、checked、value等

  • 遍历属性

for(let {name,value} of parent2.attributes){
	console.log(name,value)
}
方法说明
attributes获取全部属性列表NamedNodeMap(类数组)
getAttribute(name)获取指定属性value
setAttribute(name,value)设置属性undefined
removeAttribute(name)删除属性undefined
hasAttribute(name)检测属性boolean
  • 自定义属性
    • 元素中以data-为前缀的属性会添加到属性集中
    • 使用元素的dataset可获取属性集中的属性
    • 改变dataset的值也会影响到元素上
 <div data-wfl-img='myProp'>houdunren.com</div>
 const el = document.querySelector('.houdunren')
 console.log(el.dataset.wflImg) // myProp
 console.log(el.getAttribute('data-wfl-img')) // myProp
 el.dataset.wflImg = '666'
 console.log(el.dataset.wflImg) // 666
  • 特征和属性是记录元素属性的两个不同场所,大部分更改会进行同步操作,但有时侯不会,例如我们直接修改文本框的value后el.getAttribute(‘value’)并不会发生变化,反之亦然
<input type="text">
el.value = 100
console.log(el.getAttribute('value')) // null
2.5、操作节点
  • createElement:可以新建标签节点对象,
  document.createElement('div') //创建div
  document.createElement('script') //创建script
  document.createElement('link') // 创建外链css
  • cloneNode:克隆节点,是节点方法,当参数为true递归复制子节点即深拷贝;与之对应的还有document.importNode
const el = document.querySelector('#app')
const newEl = el.cloneNode(true) //还可以替换为:document.importNode(app, true)
document.body.append(newEl)
  • insertAdjacent

    • insertAdjacentText(location,text):插入文本,遇到html也不会解析
    • insertAdjacentHTML(location,htmlText):插入html文本,会解析html
    • insertAdjacentElement(location,element):插入节点元素
    location说明
    beforebegin元素本身前面
    afterend元素本身后面
    afterbegin元素内部前面
    beforeend元素内部后面
  • 推荐方法

    • 以下方法可以同时添加多个内容,包括字符串与元素标签
方法说明
append节点尾部添加新节点或字符串
prepend节点开始添加新节点或字符串
before节点前面添加新节点或字符串
after节点后面添加新节点或字符串
replaceWith将节点替换为新节点或字符串
remove将节点删除,午餐
// app内追加节点和文本,按照参数顺序添加
let app = document.querySelector('#app')
let h1 = document.createElement('h1')
h1.append('wfl')
app.append('@', h1,'com')
// 将h2移动到h1之前
<h1>@h1</h1>
<h2>@h2</h2>
let h1 = document.querySelector('h1')
let h2 = document.querySelector('h2')
h1.before(h2)
// 删除h1节点
h1.remove()
  • 古老方法(不建议)

    只能添加节点元素,不能添加文本,也不支持多个参数

方法说明
appendChild添加节点
insertBefore用于插入元素到另一个元素的前面
removeChild删除节点
replaceChild进行节点的替换操作
2.6 、节点内容
  • innerHTML
    • innerHTML中只解析HTML标签语法,所以其中的 script 不会做为JS处理
    • 使用innertHTML操作会重绘元素,重绘之后原元素的设置例如事件绑定就没有了
  • outerHTML
    • outerHTML与innerHTML的区别是包含父标签
    • outerHTML不会删除原来的旧元素,只是用新内容替换替换旧内容,旧内容(元素)依然存在,使用innerHTML内容是被删除然后使用新内容,而使用outerHTML是保留旧内容,页面中使用新内容
  • innerText和textContent
    • 获取时忽略所有标签,只获取文本内容
    • 设置时将内容中的标签当文本对待不进行标签解析
  • outerText
    • 同outerHTML,包括自身元素和只替换页面内容,但自身保留旧内容
2.7、操作样式

​ 两种方式:操作class和style

  1. class

    • 通过className或者通过setAttribute直接操作class属性,但建议使用classList

    • classList

      方法说明
      classList获取类列表,类数组
      classList.add添加类名
      classList.remove删除类名
      classList.toggle切换类名,boolean
      classList.contains类名检测,boolean
  2. style

    • style.样式名

      • 可以直接得到或设置单个样式,但只能得到行内样式的值,无法获取style标签或者link设置的值
      • 单个单词的属性通过驼峰进行命名,如backgroundColor
    • style.cssText

      • 可以通过字符串的方式批量获取或设置操作样式,但也只能得到行内样式的值
    • setAttribute

      • 通过setAttribute改变style特征来批量设置样式,只能行内样式
    • window.getComputedStyle

      • 上面几种方式都无法获取link或者style标签内的元素,而getComputedStyle(name)可以
      • 但不建议使用
        • 尺寸设置auto时获取结果不可用
        • 由于滚动条的存在,不同浏览器获取的返回结果也不同
        • 当元素没有设置CSS尺寸时,获取不到相应的尺寸内容
 #app{
 color: red;
 }
 <div id="app" style="display: flex;">
     app
 </div>
 const app = document.querySelector('#app')
 console.log(window.getComputedStyle(app).color) // rgb(255, 0, 0)
 console.log(window.getComputedStyle(app).height) // 21px
 console.log(app.offsetHeight) // 21

空间坐标

  • 视口尺寸即网页可见区域,不包括浏览器工具条、菜单、标签、状态栏等

1. 视口与文档尺寸

方法说明
window.screen.width/height屏幕分辨率的宽/高
window.innerWidth/innerHeight浏览器宽度/高度 ,包括滚动条
document.documentElement.clientWidth/clientHeight视口宽度/高度, 不包括滚动条
document.body.clientWidth/clientHeight网页正文宽度/高度
document.documentElement.scrollTop/scrollLeft视口距离顶部/左侧的距离,也是当前网页滚动的距离

2. 方法列表

方法说明
element.getBoundingClientRect返回元素在视口坐标及元素大小,包括外边距,width/height与offsetWidth/offsetHeight匹配
element.offsetWidth元素宽度尺寸,包括内边距与边框和滚动条
element.offsetHeight元素高度尺寸,包括内边距与边框和滚动条
element.offsetLeft元素到父元素左侧的距离
element.offsetTop元素到父元素顶部的距离
element.clientWidth元素宽度,不包含边框,只包含内容和内边距
element.clientHeight元素高度,不包含边框,只包含内容和内边距
element.clientLeft内容距离外部的距离,包含边框,滚动条在左侧时包括滚动条尺寸
element.clientTop内容距离顶部的距离,包含边框,滚动条在顶部时包括滚动条尺寸
element.scrollWidth元素宽度,内容+内边距+内容溢出的尺寸
element.scrollHeight元素高度,内容+内边距+内容溢出的尺寸
element.scrollLeft水平滚动条左侧已经滚动的宽度
element.scrollTop垂直滚动条顶部已经滚动的高度
window.pageXOffset获取当前页面距离文档左侧的位置
window.pageYOffset获取当前页面距离文档顶部的位置
// DOM元素到浏览器可视范围的距离
console.log(JSON.stringify(app.getBoundingClientRect(),null,4))
{
    "x": 18 等价top
    "y": 10, 等价left
    "width": 301, 自身高度
    "height": 4580, 自身宽度
    "top": 10, 元素上边距离可视区域上边高度
    "right": 319, 元素右边距离可视区域左边高度
    "bottom": 4590, 元素下边距离可视区域上边高度
    "left": 18 元素左边距离可视区域左边高度
}

图片懒加载

方式1:利用img到顶部的距离offsetTop与视口到顶部的距离scrollTop比较进行懒加载
lorem5000
	<img src="" alt="1" data-src='./img/2.jpg'>
lorem5000
<script>
let imgs = document.querySelectorAll('img')
function lazyLoad(imgs){
	let T = document.documentElement.scrollTop // 视口距离顶部的距离,也就是滚动条滚动的距离
	let H = document.documentElement.clientHeight // 视口高度
	imgs.forEach(i=>{
		if(T+H>i.offsetTop){ // 只要视口距离顶部的距离+视口高度就加载
			i.src = i.dataset.src
		}
	})
}
lazyLoad(imgs) // 初始加载
window.onscroll = function(){
	lazyLoad(imgs)
}
</script>
方式2:可以直接使用getBoundingClientRect获取img距离视口的高度top,只要top小于视口高度就加载
function lazyLoad(imgs){
	imgs.forEach(i=>{
		if(i.getBoundingClientRect().top <= document.documentElement.clientHeight){
			i.src = i.dataset.src
		}
	})
}

​ 不仅可以获取元素的坐标,还可用通过elementsFromPoint获取坐标上的元素集合,通过elementFromPoint获取坐标上的最底层元素

3. 滚动控制

  • scrollLeft、scrollTop可以获取水平和垂直滚动条所在的位置

监听窗口的滚动行为,并获得滚动的位置

window.addEventListener('scroll',function(){
    console.clear()
    console.log(document.documentElement.scrollTop)
    console.log(document.documentElement.scrollLeft)
    console.log(window.pageXOffset)
    console.log(window.pageYOffset)	
})

监听元素的滚动行为,并获得滚动的位置

#app{
    height: 200px;
    overflow: auto;
}
<div id="app">lorem1000</div>
let app = document.querySelector('#app')
app.onscroll = function(){
    console.log(app.scrollTop)
    console.log(app.scrollLeft)
}

网页顶部显示当前浏览的进度条

 .line{
  position: fixed;
  background-color: #1E9FFF;
  height: 1px;
  box-shadow: 0px 0px 1px #1E9FFF;
  top:0px
 }
 <div class="line"></div>
 <main>lorem1000</main>
 <script>
 let line = document.querySelector('.line')
 window.onscroll = function(){
	let T = document.documentElement.scrollTop // 视口距离顶部的距离,也就是滚动条滚动的距离
	let H = document.body.offsetHeight - document.documentElement.clientHeight // 网页总高度
	line.style.width = parseInt(T/H*100)+'%'
 }	
 </script>
  • scrollBy(options):按偏移量进行滚动内容,options参数有
    • top:垂直偏移量
    • left:水平偏移量
    • behavior:滚动方式,”smooth“为平滑滚动
  • scroll()或scrollTo():滚动到指定的具体位置, scrollTo(left,top) 或者scrollTo(options),options参数同上
 document.documentElement.scroll({ top: 30, behavior: 'smooth' })
 也可以使用 scrollTo(20) 
  • scrollIntoView:参数为true元素定位到窗口顶部,为false定位到窗口底部
document.documentElement.scrollIntoView(true)
document.documentElement.scrollIntoView({ block: 'start', behavior: 'smooth' })

事件监听

​ 捕获:从外道理,从上到下

​ 冒泡:从里到外,从下到上,使用e.stopPropagation()可以阻止冒泡

  • 使用e.preventDefault()可以组织事件得默认行为,例如href等
  • 同一个元素的相同事件是可以叠加了,会按照顺序执行回调

1. 绑定事件

  1. 直接在标签上绑定οnclick=fn(arg1,event,this),必须写括号,this代表事件源对象,event代表事件对象

  2. dom绑定,el.onclick = function(e){},e代表事件对象,可以直接在函数内使用this

  3. 事件监听,推荐

    • el.addEventListener(‘listerenName’,function(e){})绑定事件

    还可以指定第三个参数,当第三个参数设置true或false等价于{ capture: true/false}

    选项参数说明
    oncebooleantrue时只执行一次事件,默认false
    captureboolean事件是在捕获/冒泡哪个阶段执行,true:捕获阶段 false:冒泡阶段
    passiveboolean声明事件里不会调用 preventDefault(),可以减少系统默认行为的等待
    • el.removeEventListener(‘listerenName’,function(e){})移除事件,但必须保证删除的事件函数与监听的事件函数是同一函数才可以删除

2. 事件对象

执行事件处理程序时,会产生当前事件相关信息的对象,即为事件对象event。系统会自动做为参数传递给事件处理程序

属性说明
type事件类型
target事件目标对象
x,y相对窗口的X,Y坐标
clientX,clientY相对窗口的X,Y坐标
screenX,screenY相对计算机屏幕的X,Y坐标
pageX,pageY相对于文档的X,Y坐标
offsetX,offsetY相对于事件对象的X,Y坐标
layerX,layerY相对于父级定位的X,Y坐标
path冒泡的路径
altKey,shiftKey,metaKey是否按了alt,shift,mate键

3. 事件类型

事件名说明
window.onload文档解析及外部资源加载后
DOMContentLoaded文档解析后执行,不需要等待图片/样式文件等外部资源加载,该事件只能通过addEventListener设置
window.beforeunload文档刷新或关闭时
window.unload文档卸载时
scroll页面滚动时
// 需要等外部图片、样式文件、JS文件等资源加载
window.addEventListener('load', (event) => {
    console.log('load')
})
// 文档标签解析后执行,不需要等外部图片、样式文件、JS文件等资源加载
window.addEventListener('DOMContentLoaded', (event) => {
    console.log('DOMContentLoaded')
})
// 当浏览器窗口关闭或者刷新时,会触发beforeunload事件,可以取消关闭或刷新页面
window.onbeforeunload = function (e) {
  return '真的要离开吗?'
}

4. 鼠标事件

  • 通过which可以用户按的键,1左键,2中键,3右键
  • element.click()会触发element的click事件,模拟单击效果
事件名说明
click鼠标单击事件,同时触发 mousedown/mouseup
dblclick鼠标双击事件
contextmenu点击右键后显示的所在环境的菜单
mousedown鼠标按下
mouseup鼠标抬起时
mousemove鼠标移动时
mouseover鼠标移动时
mouseout鼠标从元素上离开时
mouseup鼠标抬起时
mouseenter鼠标移入时触发,不产生冒泡行为
mosueleave鼠标移出时触发,不产生冒泡行为
oncopy复制内容时触发
scroll元素滚动时,可以为元素设置overflow:auto; 产生滚动条来测试

5. 键盘事件

  • 给那个元素绑定键盘事件必须要元素获取焦点才能触发
事件名说明
keydown键盘按下时,一直按键不松开时keydown事件会重复触发
keyup按键抬起时
属性说明
keyCode返回键盘的ASCII字符数字
code按键码,字符以Key开始,数字以Digit开始,特殊字符有专属名子。左右ALT键字符不同。 不同布局的键盘值会不同
key按键的字符含义表示,大小写不同。不能区分左右ALT等。不同语言操作系统下值会不同
altKey是否按了alt键
ctrlKey是否按了ctlr键
shiftKey是否按了shift键
metaKey是否按了媒体键
// 以shift+a举例
document.documentElement.addEventListener('keydown',e=>{
    console.log(e.keyCode) // 65
    console.log(e.code) // KeyA
    console.log(e.key) // A
    console.log(e.shiftKey) //true
})

6. 表单事件

事件类型说明
focus获取焦点事件
blur失去焦点事件
element.focus()让元素强制获取焦点
element.blur()让元素失去焦点
change文本框在内容发生改变并失去焦点时触发,select/checkbox/radio选项改变时触发事件
inputInput、textarea或 select 元素的 value 被修改时,会触发 input 事件。而 change 是鼠标离开后或选择一个不同的option时触发。
submit提交表单
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信息技术王凤龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值