API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
Web API的概念是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)。JavaScript是由ECMAScript,DOM,BOM组成,在本关卡主要学习Web API中的DOM对象。
一套操作页面元素的API,DOM可以把HTML看成文档树,通过DOM提供的API可以对树上的结点进行操作。
一、DOM简介
1、什么是DOM?
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言(html或者xhtml)的标准编程接口;W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式。
2、DOM树
DOM树,又称为文档树模型,把文档映射成树形结构,通过节点对象对其处理,处理的结果可以加入到当前的页面。
- 文档
一个页面就是一个文档,DOM中使用document表示
- 节点
网页中的所有内容,在文档树中都是节点(标签、属性、文本、注释等),使用node表示
- 标签节点
网页中的所有标签,通常称为元素节点,又简称为“元素”,使用element表示
DOM把文档、节点和标签节点都看做是对象
3、DOM 重点核心
1.创建
- document.write
- innerHTML
- createElement
2.增
- appendChild
- insertBefore
3.删
- removeChild
4.改
主要修改dom的元素属性,dom元素的内容、属性, 表单的值等
- 修改元素属性: src、href、title等
- 修改普通元素内容: innerHTML 、innerText
- 修改表单元素: value、type、disabled等
- 修改元素样式: style、className
5.查
主要获取查询dom的元素
- DOM提供的API 方法: getElementById、getElementsByTagName 古老用法 不太推荐
- H5提供的新方法: querySelector、querySelectorAll 提倡
- 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
6.属性操作
主要针对于自定义属性
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute移除属性
7.事件操作(重点)
给元素注册事件:事件源.事件类型 = 事件处理程序
二、DOM节点
1、节点概述
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
- 元素节点 nodeType 为 1
- 属性节点 nodeType 为 2
- 文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)
在实际开发中,节点操作主要操作的是元素节点。
2、节点层级
利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
1.父级节点 node.parentNode
parentNode 属性可返回某节点的父节点,注意是最近的一个父节点,如果指定的节点没有父节点则返回 null 。
2.子节点
- 所有子节点 parentNode.childNodes(标准)
返回包含指定节点的子节点的集合,该集合为即时更新的集合;
返回值里面包含了所有的子节点,包括元素节点,文本节点等;
如果只想要获得里面的元素节点,则需要专门处理。 所以一般不提倡使用childNodes。
- 子元素节点 parentNode.children(非标准)
children 是一个只读属性,返回所有的子元素节点;它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的)。
虽然 children 是一个非标准,但得到了各个浏览器的支持,因此可以放心使用。
- 第1个子节点 parentNode.firstChild
firstChild 返回第一个子节点,找不到则返回null;同样,也是包含所有的节点。
- 最后1个子节点 parentNode.lastChild
lastChild 返回最后一个子节点,找不到则返回null;同样,也是包含所有的节点。
- 第1个子元素节点(IE9 以上才支持) parentNode.firstElementChild
firstElementChild 返回第一个子元素节点,找不到则返回null。
- 最后1个子元素节点(IE9 以上才支持) parentNode.lastElementChild
lastElementChild 返回最后一个子元素节点,找不到则返回null。
如何获取第一个子元素节点或最后一个子元素节点?
- 如果想要第一个子元素节点,可以使用 parentNode.chilren[0]
- 如果想要最后一个子元素节点,可以使用 parentNode.chilren[parentNode.chilren.length - 1]
3.兄弟节点
- 下一个兄弟节点 node.nextSibling
返回当前元素的下一个兄弟元素节点,找不到则返回null;同样,也是包含所有的节点。
- 上一个兄弟节点 node.previousSibling
返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点。
- 下一个兄弟元素节点(IE9 以上才支持) node.nextElementSibling
返回当前元素下一个兄弟元素节点,找不到则返回null。
- 上一个兄弟元素节点(IE9 以上才支持) node.previousElementSibling
返回当前元素上一个兄弟节点,找不到则返回null。
解决兼容性问题
自己封装一个兼容性的函数
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
3、节点操作
1.创建节点
- document.createElement('tagName')
document.createElement() 方法创建由 tagName 指定的 HTML 元素;因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。
2.添加节点
- node.appendChild(child)
node.appendChild() 方法将一个节点添加到指定父节点的子节点列表末尾。类似于 CSS 里面的after 伪元素。
- node.insertBefore(child, 指定元素)
node.insertBefore() 方法将一个节点添加到父节点的指定子节点前面。类似于 CSS 里面的 before 伪元素。
3.删除节点
- node.removeChild(child)
node.removeChild() 方法从 DOM 中删除一个子节点,返回删除的节点
4.复制节点(克隆节点)
- node.cloneNode()
node.cloneNode() 方法返回调用该方法的节点的一个副本。 也称为克隆节点/拷贝节点
注意:如果括号参数为空或者为 false ,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点;如果括号参数为 true ,则是深度拷贝,会复制节点本身以及里面所有的子节点。
5.三种动态创建元素区别
- document.write()
- element.innerHTML
- document.createElement()
区别:
- document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
- innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
- innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高。
- innerHTML字符串拼接方式(效率低)
- createElement方式(效率一般)
- innerHTML数组方式(效率高)
三、DOM的查询方法
DOM在实际开发中主要用来操作元素。
1、为什么要获取页面元素?
我们想要操作页面上的某部分(显示/隐藏,动画),需要先获取到该部分对应的元素,再对其进行操作。
2、如何获取页面元素?
1.根据ID获取
- 语法:document.getElementById(id)
- 作用:根据ID获取元素对象
- 参数:id值,区分大小写的字符串
- 返回值:元素对象 或 null
2.根据标签名获取元素
- 语法:document.getElementsByTagName('标签名') 或element.getElementsByTagName('标签名')
- 作用:根据标签名获取元素对象
- 参数:标签名
- 返回值:元素对象集合(伪数组,数组元素是元素对象)
注意:
- document.getElementsByTagName('标签名')
因为得到的是一个对象的集合,所以想要操作里面的元素就要遍历;
getElementsByTagName() 获取到是动态集合,即:当页面增加了标签,这个集合中也就增加了元素;
如果获取不到元素,则返回为空的伪数组(因为获取不到对象)。
- element.getElementsByTagName('标签名')
父元素必须是单个对象(必须指明是哪一个元素对象). 获取的时候不包括父元素自己。
3.H5新增获取元素方式
- document.getElementsByClassName('类名'); 根据类名获得某些元素对象集合
- document.querySelector('选择器');返回指定选择器的第一个元素对象
- document.querySelectorAll('选择器');返回指定选择器的所有元素对象集合
注意:切记 querySelector 和 querySelectorAll 里面的选择器必须要加符号 .box #nav
4.获取特殊元素(body,html)
- document.body 返回 body 元素对象
- document.documentElement 返回 html 元素对象
四、事件的使用
1、事件基础
1.事件概述
JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为;简单来说就是: 触发——响应机制。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,比如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
2.事件三要素
- 事件源(谁):触发事件的元素
- 事件类型(什么事件): 例如 click 点击事件
- 事件处理程序(做什么):事件触发后要执行的代码(函数形式),事件处理函数
执行事件的步骤:
- 获取事件源
- 绑定事件(注册事件)
- 添加事件处理程序(采取函数赋值形式)
4.常见的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
2、事件对象的三个属性和两个方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准 IE6~8使用 |
e.type | 返回事件的类型 比如 click、mouseover 不带 on |
e.cancelBubble | 该属性阻止冒泡 非标准 IE6~8使用 |
e.returnValue | 该属性阻止默认事件(默认行为) 非标准 IE6~8使用 比如不让链接跳转 |
e.preventDefault () | 该方法阻止默认事件(默认行为) 标准 比如不让链接跳转 |
e.stopPropagation () | 阻止冒泡 标准 |
1.e.target 和 this 的区别
- this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
- e.target 是事件触发的元素
通常情况下 terget 和 this 是一致的,但在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行),this指向的是父元素,因为它是绑定事件的元素对象,而target指向的是子元素,因为他是触发事件的那个具体元素对象.
2.阻止默认行为
html中一些标签有默认行为,例如a标签被单击后,默认会进行页面跳转
<a href="http://www.baidu.com">百度</a>
<script>
// 阻止默认行为 让链接不跳转
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
});
// 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
e.returnValue = false;
// 我们可以利用return false 也能阻止默认行为 没有兼容性问题
return false;
}
</script>
3.阻止事件冒泡
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点。
事件冒泡本身的特性,会带来的坏处,也会带来的好处。
阻止冒泡的两种方式
- 标准写法:利用事件对象里面的 stopPropagation()方法
e.stopPropagation()
- 非标准写法:IE 6~8 利用事件对象 cancelBubble 属性
e.cancelBubble = true;
<div class="parent">
<div class="children">子</div>
</div>
<script>
var children = document.querySelector('.children');
// 给children注册单击事件
children.addEventListener('click', function(e) {
alert('children');
e.stopPropagation(); // stop 停止 Propagation 传播
window.event.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
var parent = document.querySelector('.parent');
// 给parent注册单击事件
parent.addEventListener('click', function() {
alert('parent');
}, false);
// 给document注册单击事件
document.addEventListener('click', function() {
alert('document');
})
</script>
兼容性解决方案
if(e && e.stopPropagation){
e.stopPropagation();
}else{
window.event.cancelBubble = true;
}
3、事件委托(代理、委派)
1.什么是事件委托
事件委托也称为事件代理,在 jQuery 里面称为事件委派。通俗来讲就是,不给子元素注册事件,给父元素注册事件,把处理代码在父元素的事件中执行。
2.事件委托的原理
- 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
- 给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素
3.事件委托的作用
- 只操作了一次 DOM ,提高了程序的性能
- 动态新创建的子元素,也拥有事件