dom简介
- dom是文档对象模型(Document Object Model,简称dom),是w3c组织推荐的可处理可扩展编辑语言(HTML或XML)的标准编程接口
- w3c已经定义了一系列的dom接口,通过这些dom接口可以改变网页的内容、结构和样式
- dom在实际开发中主要用来操作元素
- 对于javascript,为了能够使javascript操作HTML,javascript有了一套自己的dom编程接口
- 对于HTML,dom使得html形成一棵dom树,包含文档、元素、节点
- 我们获取过来的dom元素是一个对象(object),所以称为文档对象模型
dom树
- 文档:一个页面就是一个文档,dom中使用document表示
- 元素:页面中的所有逼啊钱都是元素,dom中使用element表示),dom中使用node来表示
- dom把以上内容都看作是对象
一、获取元素
- 根据ID获取
document.getElementById('id')- 根据标签名获取
document.getElementByTagName('标签')- 根据HTML5新增的方法获取-类名/选择器
document.getElementsByClassName('类名')/document.querySelector('选择器')- 特殊元素获取-body/html
document.body/document.documentElement
1.document.getElementById('id')
- 通过ID获取元素
- id是大小写敏感的字符串,需要加引号
- 返回的是dom的一个document对象
2.document.getElementByTagName('标签')
- 返回带有指定标签名的对象的集合
- 以伪数组的形式存储,即使只有一个元素,也是以伪数组的形式存储,假如找不到元素,则以空数组的形式存储
- 还可以获得某个父元素内部所有指定标签名的子元素
element.getElementsByTagName()- 父元素必须是单个对象(必须指明是哪一个元素对象)获取的时候不包括父元素自己
3.document.getElementsByClassName('类名')
- 通过类名获取元素,根据类名返回元素对象集合
4.document.querySelector('选择器')
- 根据制定选择器返回第一个元素对象
document.querySelectorAll('选择器')根据指定选择器返回所有元素对象集合,以伪数组的形式存储
二、事件三要素
- 事件源:事件被触发的对象
- 事件类型: 事件如何触发
- 事件处理程序:通过一个函数赋值的方式完成
例如
<button id="btn">qaq</button>
var btn = document.getElementById('btn')//事件源
btn.onclick/*事件类型*/ = function(){
alert('qaq')
}//事件处理程序
执行事件的步骤
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值形式)
修改元素的内容
element.innerText从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉element.innerHTML起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
修改表单属性
- 利用dom可以操作如下表单元素的属性
- type、value、checked、selected、disabled
className修改元素样式
修改元素样式的两种方法:
element.style行内样式操作element.className类名样式操作(当前元素的类名改为某个类)
注意:
- 如果样式较多,可以采取操作类名方式更改元素样式
- 因为class是个保留子,因此使用className来操作元素类名属性
- className会直接更改元素的类名,会覆盖原先的类名,如果想要保留原先的类名可以
this.className = '原先的类名 覆盖的类名'
三、获得自定义的属性值
element.属性获得内置属性值(元素本身自带的属性)element.getAttribute('属性')主要获得自定义的属性(程序员自定义的属性)data-index="1"就是自定义属性(程序员自己添加的属性)
设置属性值
element.属性 = '值'设置内置属性值element.setAttribute('属性','值')主要针对于自定义属性
移除属性
element.removeAttribute('属性')
自定义属性
- 自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中
- 自定义属性值从0开始编号
- 有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性
- H5新增了自定义属性规范,规定自定义属性
data-开头作为属性名并赋值,比如data-index="1"- 或者使用js设置
element.setAttribute('data-index,2')- 兼容性获取
element.getAttribute('data-index')- H5新增获取
element.dataset.index或者element.dataset['index'](ie11才开始支持)- H5新增的方法只能获取data-开头的自定义属性
四、节点
- 利用dom提供的方法获取元素逻辑性不强,非常繁琐。利用节点层级关系获取元素(父子兄弟关系),逻辑性强,但是兼容性差
- 网页中所有的内容都是节点(标签、属性、文本、注释等),在dom中,节点用
node来表示,html dom树中所有节点都可以通过javascript进行访问,所有html元素(节点)都可以被修改,也可以创建或删除- 一般情况,节点至少有nodeType节点类型,nodeName节点名称和nodeValue节点值这三个基本属性
- 元素节点nodeType为1,属性节点nodeType为2,文本节点nodeType为3(文本节点包括文字、空格、换行等)
- 实际开发中,节点操作主要操作的是元素节点
节点操作之父节点
node.parentNode得到是离元素最近的父节点,不是爷爷节点,如果找不到父节点就返回为空null
节点操作之子节点
parentNode.childNodes返回包括指定节点的子节点的集合,该集合为即时更新的集合,包含元素节点文本节点等等- 如果只想要获得里面的元素节点,则需要专门处理,所以一般不提倡使用childNodes
var ul = document.querySelector('ul')
for(var i = 0;i < ul.childNodes.length;i++){
if(ul.childNodes[i].nodeType == 1){
console.log(ul.childNodes[i])
}
}
parentNode.children只返回所有的子元素节点,是一个只读属性
节点操作之第一个子节点和最后一个
parentNode.firstChild返回第一个子节点,找不到则返回null,同样也是包含所有节点parentNode.lastChild返回最后一个子节点,其余同上parentNode.firstElementChild返回第一个子元素节点,找不到则返回null,有兼容性问题,ie9以上才支持parentNode.lastElementChild返回最后一个子元素节点,其余同上- 解决方案:如果想要获得第一个子元素节点可以使用
parentNode.children[0]parentNode.children[parentNode.children.length - 1]获得最后一个子元素节点,例如ol.children[ol.children.length - 1]
节点操作之兄弟节点
node.nextSibling返回当前元素的下一个兄弟节点,找不到则返回null,同样,也是包含所有节点node.previousSibling返回当前元素的上一个兄弟节点,其余同上node.nextElementSibling返回当前元素的下一个兄弟元素节点,找不到则返回null,有兼容性问题ie9以上才支持node.previousElementSibling返回当前元素的上一个兄弟元素节点,其余同上- 解决兼容性问题只能自己封装一个兼容性函数
function getNextElementSibling(element){
var el = element;
while (el = el.nextSibling){
if(el.nodeType === 1){
return el;
}
}
return null;
}
节点操作之创建和添加节点
document.createElement('tagName')创建由tagName指定的HTML元素,因为这些元素原先并不存在,是根据我们的需求动态生成的,所以也称为动态创建元素节点,接受的参数是字符串node.appendChild(child)将创建的节点添加到指定父节点的子节点的列表末尾,类似于css里面的after伪元素,类似于数组中的push,node是父级,child是子级,接受的参数是变量node.insertBefore(child,指定元素)例如ul.insertBefore(li,ul.children[0]将一个节点添加到父节点的指定子节点前面,类似于before伪元素- 想要页面添加一个新的元素需要两步:1.创建元素 2.添加元素
节点操作之删除节点
node.removeChild(child)从dom中删除一个子节点,返回删除的节点
节点操作之复制节点
node.cloneNode()返回调用该方法的节点的一个副本,也称为克隆节点/拷贝节点- 注意:如果括号参数为空或者false,是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点(只复制标签不复制文本等内容)
- 深拷贝括号里为true
三种动态创建元素的区别
document.write()是直接将内容写入页面的内容流,但是如果文档流执行完毕,它会导致页面全部重绘element.innerHTML是将内容写入某个dom节点不会导致页面全部重回,创建多个元素时效率比较低,时间比较慢,解决方案,不要拼接字符串,采取数组醒睡拼接,效率会更高,结构稍微复杂document.createElement()创建多个元素时效率比较高,时间比较快,结构更清晰
五、事件高级
1.1 注册事件
- 给元素添加事件,称为注册事件或者绑定事件
- 注册事件有两种方式:传统方式和方法监听注册方式
1.2 传统注册方式
- 利用on开头的事件 比如onclick
- 特点是注册事件的唯一性,同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
1.3 方法监听注册方式
- 是w3c标准推荐的方式
addEventListener()它是一个方法- ie9之前不支持此方法,可使用
attachEvent()代替- 特点是同一个元素同一个事件可以注册多个监听器,按注册顺序依次执行
eventTarget.(addEventListener(type,listener[,useCapture])例如btns[1].addEventListener('click',function(){alert(22);})- eventTarget.addEventListener()方法是将指定的监视器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
- 该方法接受三个函数,type、listener、useCapture
- type:事件类型字符串,比如click、mouseover、注意这里不要带on,要加引号
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是false
1.4 attachEvent 事件监听方式
- 该特性是非标准的,请尽量不要在生产环境中使用它,这是ie9之前的浏览器专有的替代性标准
2.1 删除事件
- 传统方式删除事件
eventTarget.onclick = null- 方法监听删除事件
eventTarget.removeEventListener(type,listener[,useCapture])例如
divs[1].addEventListener('click',fn)
function fn(){
alert(22)
divs[1].removeEventListener('click',fn)
}
六、dom事件流
- 事件流描述的是从页面中接收事件的顺序,事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即dom事件流
- dom事件流分为3个阶段,分别是捕获阶段、当前目标阶段、冒泡阶段
- 事件捕获:网景最早提出,由dom最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程
- 事件冒泡:由ie最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到dom最顶层的节点的过程
- 注意:js代码中只能执行捕获或者冒泡其中一个阶段
- 注意:onclick和attachEvent只能得到冒泡阶段
- 注意:addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序,如果是false(不写默认是false)表示在事件冒泡阶段调用事件处理程序
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
- 注意:有些事件是没有事件冒泡的,比如onclick、onfocus、onmouseenter、onmouseleave
七、事件对象
- 事件对象写到侦听函数的小括号里,是形参
- 事件对象只有有了事件才会存在,是系统自动创建的,不需要我们传递参数
- 事件对象代表事件的状态。事件对象是我们事件的一系列相关数据的集合,跟事件相关,比如鼠标点击事件包含了鼠标的相关信息,鼠标坐标等,键盘事件包含了键盘的信息,比如判断用户按下了哪个键盘
- 这个事件对象我们可以自己命名,通常命名为event、evt、e
- 事件对象也有兼容性问题,ie678只能通过window.event,兼容性写法为e = e || window.event
事件对象的常见属性和方法
e.target返回触发事件的对象(注意:与this不同,this返回的是绑定事件的对象)(了解:currentTarget是一个与this非常相似的属性)e.srcElement返回触发事件的对象 非标准 ie678使用e.type返回事件的类型,比如click、mouseover、不带one.cancelBubble = true该属性阻止冒泡。非标准 ie678使用e.returnValue该属性阻止默认事件(默认行为)非标准 ie678使用 比如不让链接跳转e.preventDefault()该方法阻止默认事件,标准,比如不让链接跳转,让提交按钮不提交e.stopPropagation()阻止冒泡 标准
事件委托
- 事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
- 比如给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器
- 事件委托的作用:只操作了一次dom,提高了程序的性能