JS 的组成
Web API
Web API 是浏览器提供的一套操作浏览器功能和页面元素的 API ( BOM 和 DOM )。
现阶段我们主要针对于浏览器讲解常用的 API , 主要针对浏览器做交互效果。
比如我们想要浏览器弹出一个警示框, 直接使用 alert(‘弹出’)
MDN 详细 API : https://developer.mozilla.org/zh-CN/docs/Web/API
因为 Web API 很多,所以我们将这个阶段称为 Web APIs
什么是DOM?
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口。
W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
① 对于JavaScript,为了能够使JavaScript操作HTML,JavaScript就有了一套自己的DOM编程接口。
② 对于HTML,DOM使得HTML形成一棵DOM树,包括文档、元素、节点。我们获取过来的DOM元素是一个对象(object),所以称为文档对象模型。
- 文档:一个页面就是一个文档,DOM中使用document表示
- 元素:页面中的所有标签都是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
DOM把以上内容都看作是对象。
关于DOM操作,主要是针对于元素的操作。主要有创建、增、删、改、查、复制、属性操作、事件操作。
1. 创建
- document.write()
- element.innerHTML
- document.createElement()
三种动态创建元素的区别:
① document.write是直接将内容写入页面的内容流,但是页面文档流加载完毕,再调用这句话会导致页面全部重绘。
② innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘。
③ innerHTML创建多个元素效率更高(不要拼接字符串,而是采取数组形式拼接好后再赋值给innerHTML),结构稍微复杂
④ createElement()创建多个元素效率稍微低一点点,但是结构更清晰。
总结:不同浏览器下,innerHTML(以数组形式拼接的方式)效率要比createElement高。
2. 增
① node.appendChild(child); 该方法将一个节点添加到指定父节点的子节点列表末尾。类似于CSS里面的after伪元素。
② node.insertBefore(child, 指定元素); 该方法将一个节点添加到父节点的指定子节点前面。类似于CSS里面的before伪元素。
3. 删
node.removeChild(child); 该方法从DOM中删除一个子节点,返回删除的节点。
4. 改
JavaScript的DOM操作可以改变网页内容、结构和样式,我们可以利用DOM操作元素来改变元素里面的内容、属性表单的值等。
① 修改元素属性:src、href、id、alt、title等
<script>
// 修改元素属性
// 1. 获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2. 注册事件 处理程序
zxy.onclick = function() {
img.src = 'images/zxy.jpg';
img.title = '张学友';
}
ldh.onclick = function() {
img.src = 'images/ldh.jpg';
img.title = '刘德华';
}
</script>
② 修改普通元素内容:
- element.innerText:从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉。
- element.innerHTML:起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行。
innerText与innerHTML的区别:innerText不识别html标签,非标准;innerHTML识别html标签,W3C标准,保留空格和换行。这两个属性是可读写的,可以获取元素里面的内容。
③ 修改表单元素:type、value、checked、selected、disabled等
④ 修改元素样式:
- element.style 行内样式操作。该方式获得修改元素样式,如果样式比较少或者功能简单的情况下使用。
- element.className 类名样式操作。 当样式比较多或功能复杂的时候,可以通过修改className来更改元素的样式。
例如:element.className = 'new'; 如果想要保留原先的类名,可以这样改:element.className = 'old new';(中间用空格隔开)
注意:
- JS里面的样式采取驼峰命名法,比如 fontSize、backgroundColor
- JS修改style样式操作,产生的是行内样式,css权重比较高
排他思想:如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法,分为以下四步:
- 获取元素
- 为每个元素添加相应事件(for循环)
- 所有元素全部清除样式(干掉其他人,本质也是需要循环遍历)
给当前元素设置样式(留下我自己)
// 1.获取元素
let lis = document.querySelectorAll('li')
// 2.遍历伪数组,为其中的每个元素绑定单击事件
for (let i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', function() {
// 3.1 找到当前有active样式的li元素,清除它的active样式
// li.active:交集选择器:要求它是li元素的同时还要拥有active样式
document.querySelector('li.active').classList.remove('active')
// 3.2 为当前元素添加active样式
// lis[i].classList.add('active')
this.classList.add('active')
})
}
5. 查
获取页面中查询DOM的元素可以使用以下几种方式:
① DOM提供的API方法(这些用法太古老,不太推荐):
- 根据ID获取:document.getElementById(id);
- 根据标签名获取:
document.getElementsByTagName('tag name');
element.getElementsByTagName('tag name'); 可以得到这个元素里面的某些标签
② HTML5提供的新方法(提倡):
- 根据类名获得某些元素集合:document.getElementsByClassName('class name');
- 指定选择器的第一个元素对象,注意,里面的选择器需要加符号:'.box' '#an' 等:document.querySelector('.box');
- 指定选择器的所有元素对象集合:document.querySelectorAll('.box');
③ 利用节点操作获取元素(提倡):利用父子兄层级关系获取元素逻辑性强,但是兼容性差。在DOM树中,节点使用node来表示。
HTML的DOM树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。
一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
- 元素节点 nodeType 为1
- 属性节点 nodeType 为2
- 文本节点 nodeType 为3(文本节点包含文字、空格、换行等)
我们在实际开发中,节点操作主要操作的是元素节点。
利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。
- 父级节点:node.parentNode ,可返回某节点的父节点,注意是最近的一个父节点。如果指定的节点没有父节点则返回null。
- 子节点:
1) parentNode.childNodes(标准),返回包含指定节点的子节点的集合,该集合为即使更新的集合。注意:返回值里面包含了所有的子节点,包括元素节点,文本节点等。如果只想要获得里面的元素节点,则需要专门处理。所以一般不提倡使用childNodes。
var ul = document.querySelector('ul');
for (var i = 0; i < ul.childNodes.length; i++) {
if (ul.childNodes[i].nodeType == 1) {
// ul.childNodes[i]是元素节点
console.log(ul.childNodes[i]);
}
}
2) parentNode.children(非标准),是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(重点)。虽然children是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用。
3) parentNode.firstChild,firstChild返回第一个子节点,找不到则返回null。
4) parentNode.lastChild返回最后一个子节点,找不到则返回null。
5) parentNode.firstElementChild返回第一个子元素节点,找不到则返回null。该方法有兼容性问题,IE9以上才支持。
6) parentNode.lastElementChild返回最后一个子元素节点,找不到则返回null。该方法有兼容性问题,IE9以上才支持。
实际开发中,firstChild和lastChild包含其他节点,操作不方便,而firstElementChild和lastElementChild又有兼容性的问题,那么我们如何获取第一个子元素节点和最后一个子元素节点呢?
解决方案:
如果想要得到第一个子元素节点,可以使用parentNode.children[0]
如果想要得到最后一个子元素节点,可以使用parentNode.children[parentNode.children.length-1](length是子元素的个数)
- 兄弟节点:
1) node.nextSibling返回当前元素的下一个兄弟节点,找不到则返回null。同样,也是包含所有的节点。
2) node.previousSibling返回当前元素上一个兄弟节点,找不到则返回null。同样,也包含所有的节点。
3) node.nextElementSibling返回当前元素下一个兄弟元素节点,找不到则返回null。该方法有兼容性问题,IE9以上才支持。
4) node.previousElementSibling返回当前元素上一个兄弟节点,找不到则返回null。该方法有兼容性问题,IE9以上才支持。
如何解决兼容性问题?自己封装一个兼容性的函数:
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
④ 特殊元素的获取:
- 获取body元素:document.body;
- 获取html元素:document.documentElement;
这几种方式都可以获取元素节点,但是节点操作会更简单。网页中的所有内容都是节点(标签、属性、文本、注释等)
6. 复制
复制节点(克隆节点/拷贝节点):node.cloneNode(); 该方法返回调用该方法的节点的一个副本。
注意:
① 如果括号参数为空或者为false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。
② 如果括号参数为true,则是深度拷贝,会赋值节点本身以及里面所有的子节点。
7. 属性操作
① 获取属性值:
- element.属性,获取内置属性值(元素本身自带的属性)
- element.getAttribute('属性'); 主要获得自定义的属性(标准),程序员自定义的属性
② 设置属性值:
- element.属性 = '值'; 设置内置属性值
- element.setAttribute('属性', '值'); 主要设置自定义的属性(标准)
③移除属性值:element.removeAttribute('属性');
H5自定义属性:
自定义属性的目的是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性是通过getAttribute('属性')获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
H5增加了自定义属性:
① 设置H5自定义属性:H5规定自定义属性以data-开头作为属性名并且赋值。
比如:<div data-index="1"></div>
或者使用JS设置:element.setAttribute('data-index', '2');
② 获取H5自定义属性:
- 兼容性获取:element.getAttribute('data-index');
- H5新增 element.dataset.index 或者 element.dataset[ 'index' ] IE11才开始支持
8. 事件操作
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。
简单理解:触发---响应机制。
网页中的每个元素都可以产生某些可以触发JavaScript的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
事件三要素:事件源、事件类型、事件处理程序。
执行事件的步骤:①获取事件源 ②注册事件(也称绑定事件,采取 事件源.事件类型 = 事件处理程序) ③添加事件处理程序(采取函数赋值形式)
常见的鼠标事件:
//例如click事件
element.onclick=function(){
//处理函数
}
element.onclick
方法监听注册方式
(同个元素和事件可以添加多个侦听器)
addEventListener(type,listener[,useCapture])
具体的后面再起一篇吧~