JavaScript BOM&DOM

160 阅读18分钟

1 BOM

1.1 BOM 的概念

(1) 什么是 BOM

BOM 全称 Browser Object Model,译为浏览器对象模型。

BOM 是浏览器为 JavaScript 提供的能够对浏览器进行相关操作的 API。

(2) BOM 的作用

1)弹出新浏览器窗口的能力。

2)移动、关闭和更改浏览器窗口大小的能力。

3)可提供WEB浏览器详细信息的导航对象。

4)可提供浏览器载入页面详细信息的本地对象。

5)可提供用户屏幕分辨率详细信息的屏幕对象;

6)支持Cookies。

(3) BOM 对象

浏览器对象模型提供了独立于内容的、可以与浏览器窗口进行互动的对象结构,一共有 5 个对象:

1)window

2)location

3)history

4)navigator

5)screen

1.2 window

① 弹框

alert()		   警告框
confirm()		确认框,返回布尔值
prompt()		输入框,返回用户输入的内容

② 打开新窗口

// 打开新的空白页面窗口
window.open('');	

// 在新窗口打开指定的页面
window.open('http://www.baidu.com');

// 在指定的窗口打开页面
window.open('http://www.baidu.com', '窗口的名字');

// 打开新窗口并指定窗口大小
window.open('./01-window的属性.html', '', 'width=400,height=300');

③ 页面滚动

滚动到页面中的某个坐标:

window.scrollTo( 0, 1000 );

// 设置滚动行为改为平滑的滚动
window.scrollTo({ 
    top: 1000, 
    behavior: "smooth" 
});

在窗口中按指定的偏移量滚动文档:

// 向下滚动一页:
window.scrollBy(0, window.innerHeight);

// 向上滚动一页:
window.scrollBy(0, -window.innerHeight);

// 平滑滚动
window.scrollBy({   
  top: 100,
  left: 100,   
  behavior: "smooth" 
});

④ 定时器

多次定时:

// 开启定时器 第一个参数可以是字符串,字符串中写代码
setInterval('console.log("hello world")', 2000);

// 开启定时器,第一个参数是回调函数,第二个参数间隔时间,单位是毫秒
setInterval(function(){
    
}, 2000);

// 开启定时器,回调函数可以有形参。
setInterval(function(val) {
    
}, 2000, '朦朦');

// setInterval 的返回值就是该定时器的唯一标识
// 取消定时器 需要指定定时器唯一标识
clearInterval(定时器ID)

单次定时:

// 开启单次定时 setTimeout 与 setInterval 的语法一模一样
setTimeout(function(){
    
}, 2000)

// 清除单次定时器
clearTimeout(单次定时器ID);

⑤ window 对象属性和方法总结

属性:
	name	当前的窗口的名字,可读可写
	innerWidth		视口宽度,只读
	innerHeight		视口高度,只读
	document
	location
	history
	screen
	navigator
	
	
方法:
	alert()		警告框
	confirm()	确认框
	prompt()	输入框
	open()		打开新窗口
	close()		关闭窗口(窗口必须是被 open 打开的)
	print()		开启打印预览
	scrollTo()	滚动到页面指定位置
	scrollBy()	滚动一定的距离
	setInterval()	开启多次定时器
	clearInterval()		清除多次定时器
	setTimeout()	开启单次定时器
	clearTimeout()	清除单次定时器

1.3 history

history 用于描述本窗口的历史记录。

属性:
	length		获取本窗口历史记录的个数
	
方法:
	back()		跳转到历史记录中的上一个页面
	forward()	跳转到历史记录中的下一个页面
	go()		跳转到历史记录中的上n个或下n个页面,指定数字作为参数,正数下n个,负数上n个

1.4 location

location 对象用于描述当前页面的地址信息

属性:(可读可写)
	href	完整的地址
	protocol	协议部分
	host		主机名+端口号
	hostname	主机名部分
	port		端口号部分
	pathname	路径部分
	hash		锚点部分
	search		查询部分
	
方法:
	reload()		重新加载
	assign()		页面跳转,保留历史记录
	replace()		页面跳转,原网页不在历史记录保留

1.5 navigator

navigator 对象用于描述浏览器以及系统的信息。

属性:
	userAgent		获取浏览器信息

1.6 screen

screen 对象用于描述屏幕信息

属性:
	width	屏幕的宽度
	height	屏幕的高度

2 DOM 操作

2.1 DOM 介绍

**MDN 文档对象模型手册:**developer.mozilla.org/zh-CN/docs/…

2.2 Node 节点

(1) 五大节点类型

元素节点 	element
属性节点 	attribute
文本节点	text
注释节点	comment
文档节点	document

(2) 节点的属性

nodeName	节点名,元素节点的节点名是标签名。
nodeValue	节点值。
nodeType	节点类型。 
元素:1,属性:2,文本:3,注释:8document9

2.3 获取元素

① 通过 ID 名

document.getElementById('ID名');

返回对应的元素对象,如果没有找到该 ID 名的元素,返回 null

② 通过标签名

// document 的方法,从document的后代中查找(整个文档)
document.getElementsByTagName()

// 元素对象的方法,从指定元素的后代中查找
element.getElementsByTagName()

注意:

getElementsByTagName() 方法返回一个 HTMLCollection 对象,里面是所有满足条件的元素的集合,是个伪数组。

如果没有满足条件的元素,返回空的 HTMLCollection 对象。

③ 通过类名(了解,IE8 + 支持)

// document 的方法,从document的后代中查找(整个文档)
document.getElementsByClassName()

// 元素对象的方法,从指定元素的后代中查找
element.getElementsByClassName()

注意:

getElementsByClassName() 方法返回一个 HTMLCollection 对象,里面是所有满足条件的元素的集合,是个伪数组。

如果没有满足条件的元素,返回空的 HTMLCollection 对象。

④ 通过 name 属性值 (了解)

document.getElementsByName('name值');

返回一个 NodeList 对象,与 HTMLCollection 类似,也是伪数组,也是由满足条件的元素组成。

⑤ 通过选择器获取元素 (推荐)

// 从整个文档中获取
document.querySelector('css 选择器');	// 返回一个元素; 如果满足选择器条件的元素有多个,只返回第一个元素;如果没有满足条件的元素,返回 null。
document.querySelectorAll('css 选择器');  // 返回一个 NodeList 对象,是一个右所有满足条件的元素组成的集合,是个伪数组。

// 从某个元素的后代中获取
element.querySelector('css 选择器');
element.querySelectorAll('css 选择器');

⑥ 获取所有的元素

document.all

document.all 是一个语法糖,可以用来判断浏览器是 IE 还是 非IE

if (document.all) {
// IE10 以及以下
alert('啊,我是IE浏览器');
} else {
// chrome firefox safari opera Edge IE11
alert('嘿嘿,我不是IE浏览器!');
}

2.4 文档结构(元素关系)

(1) 节点树

parentNode		返回父节点

firstChild		第一个子节点
lastChild		最后一个子节点
childNodes		所有子节点组成的集合(NodeList 对象)

nextSibling		紧邻在后面的兄弟节点
previousSibling		紧邻在前面的兄弟节点

(2) 元素树

parentElement		返回父元素

firstElementChild		第一个子元素
lastElementChild		最后一个子元素
children				所有子元素组成的集合(HTMLCollection 对象)

nextElementSibling		紧邻在后面的兄弟元素
previousElementSibling		紧邻在前面的兄弟元素

所有的元素,除了 html 元素,父节点和父元素是一样的; html 元素没有父元素,但是父节点是 document

2.5 属性操作

(1) 读写内置属性

element.属性名;
element['属性名'];

(2) 读写自定义属性

// 读取属性的值
element.getAttribute('属性名');

// 设置属性的值
element.setAttribute('属性名', '值');

该方法不分属性是内置的还是自定义的,只要写在元素上的就可以操作!

(3) data-* 形式的自定义属性

<div data-name="" data-spm-age=""></div>
// 读写属性
divBox.dataset.name;
divBox.dataset.spmAge;

2.6 样式操作

(1) 操作行内样式

// 设置样式
ele.style.width = '100px';  // 带单位
ele.style.backgroundColor = '#f90';  // 带 - 的css属性名自动转为小驼峰
ele.style['background-color'] = 'red';  // 带 - 的css属性,可以使用 []

// 获取样式	
ele.style.height;
ele.style.backgroundColor;
ele.style['border-width'];

注意:

  1. .style 方式设置的样式,设置在行内。
  2. .style 方式获取元素某个样式,只能获取设置在行内的样式,其他地方的样式得到空字符串。

(2) 读取计算样式

所谓计算样式,指的是所有作用在元素上的样式,不论是设置到哪里; 哪怕没有设置该样式,还可以得到默认值。 元素的计算样式是只读的

// 非 IE (包括 IE11 和 Edge)
window.getComputedStyle(元素).属性名

// IE 浏览器
元素.currentStyle.属性名
/**
 * 兼容性得获取元素的计算样式
 * @param element  HTML 元素对象
 * @param attrName string   css的属性名
 * @return css属性值
*/
function getStyle(ele, attrName) {
    if (window.getComputedStyle) {
        // 非IE浏览器(包括IE11 和 EDGE)
        return getComputedStyle(ele)[attrName];
    } else if (ele.currentStyle) {
        // IE 浏览器
        return ele.currentStyle[attrName];
    }
}

(3) 通过类名操作

① className

ele.className;  // 可读可写

② classList

ele.classList.add('类名');		// 在原有类型的基础上添加类名
ele.classList.remove('类名');		// 移除指定的类名,其他类名不受影响
ele.classList.toggle('类名');		// 如果存在类名就移除,如果没有类名就添加
ele.classList.length;			 // 属性,表示元素类名的个数

元素的 classList 属性可以得到一个对象,有类名组成的伪数组。

2.7 元素的文本内容(可读可写)

ele.innerHTML		读取或设置元素中的 html 内容(读取:标签代码能够读取到;设置:标签代码能被解析)
ele.outerHTML		相对于 innerHTML,读写的时候包括自己在内的 html 代码。
ele.innerText		读取元素中的文字内容(读取:标签代码被去掉;设置:标签代码变为实体)
ele.textContentinnerText类似,保留内容中的缩进格式。

2.8 元素的尺寸位置(只读)

(1)元素的尺寸

offsetWidth		获取元素的宽度(内容宽+左右内边距+左右边框宽度)
offsetHeight	获取元素的高度(内容高+上下内边距+上下边框宽度)

clientWidth		获取宽度(内容宽+左右内边距)
clientHeight	获取高度(内容高+上下内边距)

scrollWidth		在 clientWidth 的基础上添加溢出内容的宽度
scrollHeight	在 clientHeight 的基础上添加溢出内容的高度

getBoundingClientRect()		返回一个对象,对象中有 width 属性和 height 属性,分别获取元素的宽高(同 offsetWidth 和 offsetHeight 一致)

快速获取 html 元素和 body 元素的方式:

document.documentElement 可以得到 html 根元素。

document.body 可以得到 body 元素。

获取视口的宽高:

window.innerWidthwindow.innerHeight, 会算上滚动条自身的大小。

document.documentElement.clientWidthdocument.documentElement.clientHeight

(2) 元素的位置 (只读)

offsetLeft		获取元素在第一个定位的祖先元素上的 x 坐标; 如果祖先元素没有定位,参考根元素
offsetTop		获取元素在第一个定位的祖先元素山的 y 坐标; 如果祖先元素没有定位,参考根元素

clientLeft		元素左边框的宽度
clientTop		元素上边框的宽度

getBoundingClientRect()	返回对象,对象中具有如下属性
	left:	元素在视口上的 x 坐标
	top:    元素在视口上的 y 坐标
	x:		 left
	y:		 top
	right:	元素右下角在视口上的 x 坐标
	bottom: 元素右下角在视口上的 y 坐标

(3) 内容的位置(可读可写)

scrollLeft		内容向左偏移的距离
scrollTop		内容向上偏移的距离

内容可以滚动的生效前提: 元素的 overflow 属性的值不是 visible

2.9 节点(元素)的创建添加删除替换克隆

(1) 创建元素节点

document.crateElement('标签名')

方法返回创建好的元素对象; 新创建的元素不会出现在文档结构中。

(2) 添加子节点

parentElement.appendChild(新节点);		// 新节点会作为父元素的最后一个节点
parentElement.insertBefore(新节点,旧节点);	// 指定位置添加子节点;新节点出现在旧节点的前面

(3) 删除子节点

parentElement.removeChild(要删除的节点);		// 删除指定的子节点

(4) 替换子节点

parentElement.replaceChild(新节点,旧节点);		

(5) 节点克隆

ele.cloneNode(true);		// 返回元素的克隆版, 参数指定为 true,连同元素的内容以及后代一起克隆;默认是 false,只克隆元素本身不包括内容和后代

2.10 documnt 对象

document 对象表示整个文档,不是元素,是节点; document 是 html 根元素的父节点。

属性:
lastModified	代码最后一次修改时间(只读)
title			页面标题(可读可写)
documentElement	获取 html 根元素(只读)
body			获取 body 元素(只读)
head			获取 head 元素(只读)
all				获取所有元素的集合,返回 HTMLCollection 对象。(只读)

方法:
write()			将内容写入文档流

2.11 documentFragment 对象

(1) 创建 documentFragment 对象

document.createDocumentFrament();  // 该方法返回一个新创建的 documentFragment 对象

(2) documentFragment 对象的特点

documentFragment 对象也是一种节点,nodeType 是 11。

documentFragment 对象不会出现在页面结构中,但是可以作为一个容器拥有子节点。

把 documentFragment 对象作为子节点添加到一个页面的元素中,documentFragment 对象会把自己的子节点作为元素的子节点。

(3) documentFragment 对象的应用

  1. 批量添加子节点,可以先把子节点添加到 documentFragment 对象中,再把documentFragment 对象一次性添加要添加的元素中。可以提高浏览器渲染效率。
  2. 借助于documentFragment 对象实现元素的翻转。

3 HTML DOM

3.1 表单相关元素

① form 元素

方法:
submit()	form 元素对象调用该方法,表单会提交
reset()		form 元素对象调用该方法,表单会重置

② 文本输入框和文本域(input 和 textarea)

方法:
focus()		获取焦点
blur()		失去焦点
select()	选中里面的文字

③ select 元素

属性:
value	获取选中的选项的 value 值
length	获取拉下选选项的数量
selectedIndex	获取选中的选项的索引

方法:
add(option元素)	添加一个 option 元素
remove(index)	删除一个选项,指定要删除选项的索引

创建 option 元素的方式:
new Option(中间的内容,value值)

3.2 表格相关元素

① table 元素

属性:
rows	获取表格中所有 tr 元素的集合
cells	获取表格中所有 tdth 元素的集合

方法:
insertRow()		向表格中插入一行,可以指定位置
deleteRow()		删除一行,指定要删除行的索引

② tableRow 元素(tr 元素)

属性:
rowIndex	返回当前行的索引
cells		返回本行内所有单元格集合

方法:
insertCell()	向行内添加一个单元格,可以指定位置
deleteCell()	删除行内的一个单元格,指定要删除单元格的索引

③ tableCell 元素 (td 或 th)

属性:
cellIndex	本单元格在行里的索引

3.3 快速创建 img 元素

new Image();

所创建的 img 元素与 document.createElement('img') 一样。

4 事件

4.1事件的监听(绑定)方式

① 第一种方式 把事件作为标签的属性

<button onclick="js代码..."></button>

② 第二种方式 把事件作为元素对象的方法

// 获取到元素对象
// 给元素对象监听事件
element.onclick = function(){
    js 代码....
}

③ 第三种方式 使用 AddEventListener

// 获取到元素对象
// 给元素对象监听事件
element.addEventListener('click', function(){
    js 代码...
});

第三种方式监听事件的特定:

  1. 事件名是不包括 on 的,前两种监听事件的方式需要在事件名前面添加on,addEventListener 方式不需要添加 on
  2. 前两种方式同一种事件无法监听多次;addEventListener 方式可以监听多次同一种事件。
  3. addEventListener 方式需要 IE8 以上浏览器支持; 前两种兼容性非常好。

4.2 解除事件的监听(绑定)

① 解除第一种方式和第二种方式监听的事件

// 重新设置事件,覆盖前面
element.onclick = null;

② 解除第三种方式监听的事件

// 使用方法
element.removeEventListener('click', 回调函数名);

注意: addEventListener 监听的事件如果将来打算取消监听,回调函数就不能是匿名的。

4.3 事件流

事件的触发会经过三个阶段:

捕获阶段: 从 window 开始到 document,到 html,到 body 一直到目标元素(发生事件动作的元素)

目标阶段: 找到目标元素了,标志着捕获阶段的结束,冒泡阶段的开始。

冒泡阶段: 从目标元素开始,层层向上,一直到 body、html、document、window。

给元素监听了事件,事件默认会在冒泡阶段触发!

addEventListener() 第三个参数如果设置为 true,表示该事件在捕获阶段触发!第一种和第二种监听事件的方式只能在冒泡阶段触发。

4.4 事件回调函数中 this 的指向

  1. this 的指向规则,仍然是谁调用了方法,方法中的 this 就执行谁。
  2. 触发事件的元素调用了对应的回调函数。 事件回调函数中的 this 指向触发事件的元素!

4.5 常用事件

(1) 鼠标事件

click			单击
dblclick		双击
contextmenu		右击
mousedown		鼠标按键按下
mouseup			鼠标按键抬起
mousemove		鼠标按键移动
mouseenter		鼠标进入元素(IE9+) 代替 mouseover
mouseleave		鼠标离开元素(IE9+) 代替 mouseout

(2) 键盘事件

keydown		键盘按键按下,所有按键都可以触发
keyup		键盘按键抬起,所有按键都可以触发
keypress	键盘按键按下,但是只有非控制字符按键才可以触发

如何获取到按的是哪个按键?

  1. 通过 event.keyCode 属性得到按键对应的 acsii 值。
  2. keydown 获取的按键是不区分字母大小写, keypress 可以区分字母按键的大小写。

(3) 文档事件

load	页面中所有的一切加载完毕,触发;通常监听给 window 元素。
DOMContentLoaded	页面中的元素加载完毕,触发;通常监听给 window 元素。推荐。
beforeunload		文档关闭的时候触发。

load 事件和 DOMContentLoaded 事件的区别:

  1. DOMContentLoad 只要页面中所有的元素加载完毕就可以触发,而 load 事件必须等到页面中所有的一切(包括外部文件,如图片)加载完毕才触发。
  2. DOMContentLoaded 只能使用 addEventListener 方式监听。

(4) 表单事件

submit	监听给 form 元素,当表单被提交的时候,触发事件。
reset	监听给 form 元素,当表单被重置的时候,触发事件。
focus	监听给表单控件,当获取焦点的时候触发事件。
blur	监听给表单控件,当失去焦点的时候触发事件。
select	监听给可输入元素,当里面的内容被选中,触发事件。
change	监听给表单控件,更适合复选框、单选按钮、下拉选项,有变化就触发。

输入框监听 change 事件,触发条件:

  1. 输入框内容要改变。
  2. 输入框要失去焦点。

(5) 图片事件

load	监听给 img 元素,等到图片加载完毕。
error	监听给 img 元素,图片加载失败。

(6) 其他事件

scroll	监听给有滚动条的元素或window,一滚动就不停地触发。
resize	监听给 window,视口尺寸发生变化。

获取页面整体滚动(偏移)的距离:

document.documentElement.scrollTop || document.body.scrollTop

4.6 Event 对象

(1) 获取 Event 对象

给事件的回调函数,设置一个形参,自动获取本次事件触发对应的事件对象。

(2) 鼠标事件对象 MouseEvent 的属性和方法

clientX / clientY		获取鼠标在视口上的位置
pageX / pageY			获取鼠标在整个文档(整个页面)上的位置
screenX / screenY		获取鼠标在屏幕上的位置
offsetX / offsetY		获取鼠标在目标元素上的位置
button					获取鼠标按的哪个按键; 值是 0 表示左键、值是 1 表示中间的滚轮、值是 2 表示右键

(3) 键盘事件对象 KeyBorardEvent 的属性和方法

keyCode		获取按键的ascii值
which		同 keyCode
key			获取按键的值

(4) 所有的事件对象都有的属性和方法

type		获取事件名
target		获取目标元素
timeStamp	获取触发事件的那一刻距离打开页面的那一刻相差的毫秒数
stopPropagation()		阻止冒泡
preventDefault()		阻止浏览器默认行为

(5) 阻止事件冒泡

在事件的回调函数中执行:

event.stopPropagation();

注意: return false 在原生 js 中不能阻止冒泡。

(6) 浏览器的默认行为

① 浏览器有哪些默认行为
在页面中右击,出现菜单
超连接点击跳转
表单的提交和重置
等
② 阻止浏览器默认行为

在事件的回调函数中调用语句:

event.preventDefault();

注意:

如果是使用第二种方式监听事件(把事件作为元素对象的方法),回调函数中写 return false 同样可以阻止默认行为,与 event.preventDefault() 功效一致!

4.6 事件委托

如何实现事件委托:

把事件委托监听给要监听事件元素 的祖先元素,触发事件的时候,判断目标元素是否是监听事件的元素,如果是就执行相关操作,不是什么也不做。

事件委托解决什么问题:

事件委托主要解决新增的元素也能监听上事件。

5 深入分析 DOM 对象

5.1 元素对象的原型链关系

div元素对象 -> HTMLDivElement.prototype -> HTMLElement.prototype -> Element.prototype -> Node.prototype -> EventTarget.prototype -> Object.prototype

5.2 事件对象的原型链关系

鼠标事件对象 -> MouseEvent.prototype -> UIEvent.prototype -> Event.prototype -> Object.prototype

5.3 HTMLCollection 和 NodeList 的区别

NodeList 类型的对象:

  1. NodeList 对象是节点组成的集合,成员中可以有元素节点、属性节点等所有类型的节点。
  2. 具有 forEach 方法。
  3. 该对象是静态的,获取完对象再添加元素,对已经获取的对象没有影响。
  4. querySelectorAll()getElementsByName() 的返回值和 childNodes 的属性值 得到一个 NodeList 对象。

HTMLCollection 类型的对象:

  1. HTMLCollection 对象是元素组成的集合,成员中只能是元素。
  2. 没有 forEach 方法
  3. 该对象是动态的,获取完对象再添加元素,对象中包含新的元素。
  4. getElementsByTagName()getElementsByClassName() 的返回值和 children的属性值可以得到一个 HTMLCollection 对象。