本篇整理了一下DOM的一些基础知识,目前记录的知识还比较基础,更深的知识尚未整理。往后将继续学习和补充。
如有记录得不对的地方,欢迎探讨。
DOM
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。
- 我们获取过来的DOM元素是一个对象(Object),所以称为文档对象模型
- 顶级对象是document
DOM操作
元素操作
元素操作主要有创建、增、删、改、查
创建元素
-
document.write():如果页面文档流加载完毕再调用它,会导致页面重绘;(实际开发中不常用)
-
innerHTML:是将内容写入某个DOM节点,不会导致页面重绘;
-
createElement:不会导致页面重绘;
- 在页面中添加一个元素,往往需要两步:
- 创建节点:document.createElement(‘node’);
- 添加节点:node.appendChild 或 node.insertBefore
- 在页面中添加一个元素,往往需要两步:
-
经典面试题:innerHTML 和 createElement 的效率哪一个更高?
-
innerHTML创建多个元素效率更高(不要以拼接字符串的方式,以数组存储字符串(push),再填入innerHTML(join))
-
createElement 创建多个元素的效率稍微低一点,但是结构更为清晰。
添加节点
-
node.appendChild(child):后面追加元素
-
node.insertBefore(要插入的元素child, 指定元素):在指定元素前插入元素
-
node.cloneNode():
- 括号为空或里面是false,则是浅拷贝,只复制节点本身,不复制里面的内容(子节点);
- 括号里面为true,则是深拷贝。
删除元素
node.removeChild(child):删除一个子节点,返回删除的节点
修改元素
主要修改的是dom元素的属性,内容,表单的值,元素样式等。
- 修改元素属性:src、href、title等
- 修改普通元素内容:innerHTML、innerText
- innerText:
- 不识别html标签
- 读取时去除html标签,同时去除空格、换行
- innerHTML:
- 识别html标签
- 读取时包含html标签,同时保留空格、换行
- innerText:
- 修改表单元素:value、type、disabled等
- 该注意的是修改和获取表单元素的值用value,而不是innerHTML
- 修改元素样式:style、className
- style里面的属性采用驼峰写法
- 通过修改style属性,为行内样式,CSS权重高
- className会直接改变类名,覆盖原先的类名
获取元素
DOM提供的API:
-
getElementById():参数为字符串,需要加引号,找不到元素则返回null
-
getElementsByTagName()
-
getElementsByClassName()
H5提供的新方法:
-
querySelector()
-
querySelectorAll()
节点操作:
网页中所有内容都是节点(标签节点、属性节点、文本节点、注释节点等)
一般来说,节点至少拥有nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)
-
nodeType:
元素节点:nodeType = 1;
属性节点:nodeType = 2;
文本节点:nodeType = 3;(包括文字、空格、换行)
-
父级节点:node.parentNode
- 得到的是离元素最近的父节点(是爸爸不是爷爷)
- 若找不到,返回null
-
子节点:
-
node.childNodes(标准)
-
返回结果中包含元素节点、文本节点(如空格和换行)等
-
若想只获得元素节点,可通过for循环+nodeType判断获得
-
-
node.children(非标准)
-
我们往往只想获取子元素节点,不需要你把换行这种文本节点都获取过来
-
获取所有子元素节点(不包含文本节点),实际开发中常用
-
-
node.firstChild 和 node.lastChild
- 分别获取第一个子节点和最后一个子节点,包含元素节点、文本节点(如空格和换行)等
-
node.firstElementChild 和 node.lastElementChild
- 分别获取第一个子元素节点和最后一个子元素节点
-
node.children[0] 和 node.children[node.children.length - 1]
- node.firstElementChild 和 node.lastElementChild 的存在兼容性要求
- 因此实际开发中,我们常用的是node.children[],以伪数组获取值的方式
-
-
兄弟节点:
-
node.nextSibling:下一个兄弟节点
-
node.previousSibling:上一个兄弟节点
显而易见,上面两种获取方式也是会将除元素节点之外的节点获取过来的,于是有了另外两种获取方式:
- node.nextElementSibling:下一个兄弟元素节点
- node.previousElementSibling:上一个兄弟元素节点
不过后面两种同样存在兼容性要求,解决的思路是自行封装一个兼容性函数。
-
属性操作
-
获取属性
- 获取内置属性:ele.Attr
- 获取自定义属性(标准):ele.getAttribute(‘Attr’)
-
设置属性
-
ele.Attr = 'value’
-
ele.setAttribute(‘Attr’, ‘value’)
-
需要注意的是修改类名的时候,两种方法对类名属性要求不同:
- ele.className = 'newCLassName’
- ele.setAttribute(‘class’, ‘newClassName’)
这是由于在js中,class为保留字
-
-
移除属性
- ele.removeAttribute(‘Attr’)
-
获取自定义属性
-
ele.getAttribute(‘data-attr’):兼容性好
-
ele.dataset.attr 或 ele.dataset[‘attr’]
-
dataset 是一个对象, 存放所有以data开头的自定义属性
-
dataset只能获取“data-”开头的属性
-
如果自定义属性中有多个链接的单词,JS中采用驼峰命名法
-
-
事件操作
事件的三要素
- 事件源
- 事件类型
- 事件处理程序
事件注册
-
传统注册方式:
ele.onclick = function(){}
- 注册事件的唯一性:同一个元素同一个事件只可设置一个处理函数,后面注册的函数覆盖前面
-
事件监听方式:
ele.addEventListener('click', function(){}, false)
- 事件类型不带type
- 注册事件没有唯一性:同一个元素同一个事件可添加多个监听器(事件处理程序)
-
ie9以下:
ele.attachEvent('onclick', function(){})
删除事件(解绑事件)
-
传统方式:
e.onclick = null
-
事件监听:
e.removeEventListener('click', fn)
-
ie9以下:
e.detachEvent('onclick', fn)
事件类型
-
常用的鼠标事件:
鼠标事件 触发条件 onclick 鼠标点击左键触发 onmouseover 鼠标经过触发 onmouseout 鼠标离开触发 onfocus 获得鼠标焦点触发 onblur 失去鼠标焦点触发 onmousemove 鼠标移动触发 onmouseup 鼠标弹起触发 onmousedown 鼠标按下触发 除此之外,还有一些常用的:
-
禁止鼠标右键菜单:(主要用于程序员取消默认的上下文菜单)
document.addEventListener('contextmenu', function(e) { e.preventDefault(); })
-
禁止鼠标选中:
document.addEventListener('selectstart', function(e) { e.preventDefault(); })
-
-
常用的键盘事件:
键盘事件 触发条件 onkeyup 键盘弹起触发 onkeydown 键盘按下触发 onkeypress 键盘按下触发 onkeydown 和 onkeypress 区别:
- onkeypress不识别功能键,如ctrl、shift、上下左右箭头、删除键等
- onkeydown 和 onkeyup 的 keyCode 不识别大小写,a 和 A 返回的 keyCode 相同;onkeypress 识别大小写
事件调用顺序:keydown ---- keypress ---- keyup
DOM事件流
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点间按照特定的顺序传播,这个传播过程就是DOM事件流。
比如我们给一个div注册了事件,DOM事件流分为三个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
注意:
- JS代码中只可以执行捕获或冒泡其中一个阶段;
- onclick 和 attachEvent 只可以得到冒泡阶段;
- addEventListener 中:
- 第三个参数如果是false(默认),表示在冒泡阶段调用事件处理程序
- 第三个参数如果是true,表示在捕获阶段调用事件处理程序
- 有些事件没有冒泡,如:onfocus、onblur、onmouseenter、onmouseleave
事件对象
事件对象是事件的一系列信息数据的集合,与具体的事件有关
-
ie9以下只识别window.event,处理:
e = e || window.event
-
e.target 和 this 的区别:
-
e.target 返回的是触发事件的对象/元素(点击了谁)
-
this 返回的是绑定事件的对象/元素
如:
<ul> <li>1</li> <li>2</li> <li>3</li> </ul>
给ul绑定click事件,但点击的是li,则:e.target 返回的是li,this返回ul
-
-
currentTarget用法与this一样,且有兼容性要求,因此不常用,用this就可以了
-
e.type返回事件类型
-
阻止默认行为:e.preventDefault()
-
阻止事件冒泡:e.stopPropagation()
-
鼠标事件中:
- e.clientX / e.clientY:鼠标在可视区域坐标
- e.pageX / e.pageY:鼠标相对文档页面的坐标
- e.screenX / e.screenY:鼠标相对屏幕坐标
-
键盘事件中:keyCode可以获取按下键的ASCII值,可用于判断按下了什么键
事件委托
描述(面试):不是每个子节点单独设置事件监听器,而是把事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
BOM
-
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window。
-
BOM把「浏览器」当做一个「对象」来看待
-
BOM 学习的是浏览器窗口交互的一些对象
-
BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差
-
BOM由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。
-
window对象是浏览器的顶级对象,它具有双重角色:
-
它是JS访问浏览器窗口的一个接口
-
它是一个全局对象,定义在全局作用域中的变量、函数都会变成window对象的属性和方法
在调用的时候可以省略window,前面学习的对话框都属于window对象方法,如alert()、prompt()等。
注意:window下有个特殊的属性——window.name
-
window对象的常见事件
1 窗口加载事件load
window.onload = function() {}
window.addEventListener('load', function(){})
window.onload 是窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等),就调用的处理函数。
注意:
-
有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数。
-
window.onload 传统注册事件方式 只能写一次,如果有多个,会以最后一个 window.onload 为准。
-
如果使用 addEventListener 则没有限制
2 窗口加载事件DOMContentLoaded
document.addEventListener('DOMContentLoaded', function(){})
-
DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。
-
Ie9以上才支持
-
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适。
3 调整窗口大小事件resize
-
只要窗口大小改变就触发
-
我们经常利用这个事件完成响应式布局。可以通过 window.innerWidth 获取当前屏幕的宽度
定时器
setTimeout()
-
setTimeout执行函数的this指向window
-
一般会给定时器添加标识符(方便后面清除):
let timer = setTimeout(function() { console.log(1) }, 1000)
-
清除定时器:
window.clearTimeout(timer)
window可以省略
setInterval()
-
setInterval执行函数的this指向window
-
一般会给定时器添加标识符(方便后面清除)
-
清除定时器:
window.clearInterval(timer)
window可以省略
location对象
window 对象给我们提供了一个 location 属性用于获取或设置窗体的 URL,并且可以用于解析 URL 。 因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或设置整个URL |
loaction.host | 返回主机/域名 |
location.port | 返回端口号,如果未写返回空字符串 |
location.pathname | 返回路径 |
location.search | 返回参数 |
location.hash | 返回片段 #后面的内容 |
方法
location对象方法 | 返回值 |
---|---|
location.assign() | 和href一样,可以跳转页面(也称为重定向页面),有历史记录,可以返回和前进 |
location.replace() | 替换当前页面,没有历史记录,不能返回和前进 |
location.reload() | 刷新页面,可带参数false或true,默认为false,表示刷新,相当于F5;true表示强制刷新,相当于ctrl+F5 |
navigator对象
navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。
下面前端代码可以判断用户那个终端打开页面,实现跳转:
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = ""; //手机
} else {
window.location.href = ""; //电脑
}
history对象
history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面:
-
history.pushState()
history.pushState({},'','/foo')
-
history.replaceState()
history.replaceState({},'','/foo/bar')
-
history.go()
history.go(-1)//后退一个页面 history.go(1)//前进一个页面
-
history.back() 等价于 history.go(-1)
-
history.forward() 等价于 history.go(1)
screen对象
screen对象在编程中用处不大,基本上只用来表明客户端的能力,其中包括浏览器窗口外部的显示器的信息,如像素宽度和高度等,每个浏览器的screen对象都包含着各不相同的属性。