DOM( Document Object Model)
文档对象模型,通过 DOM 可以来任意来修改网页中各个内容
- 文档:
- 指的是网页,一个网页就是一个文档
- 对象:
- 指将网页中的每一个节点都转换为对象,转换完后,以一种纯面向对象的形式来操作网页
- 模型:
- 用来表示节点和节点之间的关系,方便操作页面
- 节点(Node):
- 构成网页的最基本的单元,网页中的每一个部分都可以称为是一个节点
- 常用的节点(每个节点的类型都不一样)
- 文档节点(Document),代表整个网页
- 元素节点(Element),代表网页中的标签
- 属性节点(Attribute),代表标签中的属性
- 文本节点(Text),代表网页中的文本内容
DOM 操作
- DOM 查询
- 在网页中浏览器已经为我们提供了 document 对象,
- 它代表的是整个网页,它是 window 对象的属性,可以在页面中直接使用。
document 查询方法:
- 根据元素的 id 属性查询一个元素节点对象:
1
document.getElementById("id属性值")
- 根据元素的 name 属性值查询一组元素节点对象:
1
document.getElementsByName("name属性值")
- 根据标签名来查询一组元素节点对象:
1
document.getElementsByTagName("标签名")
- 获取页面中 html 根元素:document.documentElement
- 获取页面中的 body 元素:document.body
- 根据元素的 class 属性值查询一组元素节点对象:
1
document.getElementsByClassName()
- 不支持 IE8 及以下的浏览器
- 返回文档中与指定选择器或选择器组匹配的第一个 Element 对象:
1
document.querySelector()
- 根据 CSS 选择器去页面中查询一个元素
- IE8 使用 querySelector()代替
- 如果匹配到的元素有多个,那么它只会返回查询到的第一个元素
- 示例:
1
var div = document.querySelector(".box1 div");
- 返回与指定的选择器组匹配的文档中的元素列表:
1
document.querySelectorAll()
- 根据 CSS 选择器去页面中查询一组元素
- 会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个
具体的元素节点查询
- 通过标签名查询当前元素的指定后代元素
1
元素.getElementsByTagName()
- 获取当前元素的所有子节点,会获取到空白的文本子节点: ele.childNodes
- 获取当前元素的所有子元素: ele.children
- 获取当前元素的第一个子节点: ele.firstChild
- 获取当前元素的最后一个子节点: ele.lastChild
- 获取当前元素的父元素: ele.parentNode
- 获取当前元素的前一个兄弟节点: ele.previousSibling
- 获取当前元素的后一个兄弟节点: ele.nextSibling
- innerHTML 和 innerText
- 两个属性作用类似,都可以获取到标签内部的内容,
- 不同是『innerHTML会获取到html标签』,而『innerText会自动去除标签』
- 读取标签内部的文本内容
1
2示例:<h1>h1中的文本内容</h1>
元素.firstChild.nodeValue
DOM 修改
- 可以根据标签名创建一个元素节点对象
1
document.createElement()
- 可以根据文本内容创建一个文本节点对象
1
document.createTextNode()
- 向父节点中添加指定的子节点
1
父节点.appendChild(子节点)
- 将一个新的节点插入到旧节点的前边
1
父节点.insertBefore(新节点,旧节点)
- 使用一个新的节点去替换旧节点
1
父节点.replaceChild(新节点,旧节点)
- 删除指定的子节点
1
2父节点.removeChild(子节点)
子节点.parentNode.removeChild(子节点) // 推荐
元素的属性
- 读取元素的属性:
1
语法:元素.属性名
- 修改元素的属性:
1
语法:元素.属性名 = 属性值
使用 DOM 操作 CSS
- 修改元素的样式 — 内联样式
- 语法:
1
元素.style.样式名 = 样式值
- 注意:如果 CSS 的样式名中含有-,需要将这种样式名修改为驼峰命名法,aaBB
- 尽量不要为样式添加!important
- 语法:
- 读取元素的样式 — 内联样式
- 语法:
1
元素.style.样式名
- 语法:
- 读取元素的当前显示的样式
- 正常浏览器: getComputedStyle()
- 这个方法是 window 对象的方法,可以返回一个对象,这个对象中保存着当前元素生效样式
- 可以通过对象.样式名来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值
- 参数:
- 要获取样式的元素
- 可以传递一个伪元素,一般传 null
- IE8
1
元素.currentStyle.样式名 // IE 浏览器支持
- 可以用来读取当前元素正在显示的样式,如果当前元素没有设置该样式,则获取它的默认值
- 正常浏览器: getComputedStyle()
- 定义一个函数,用来获取指定元素的当前的样式
- 参数
- obj:要获取样式的元素
- name:要获取的样式名
- 例子:
1
2
3
4
5function getStyle(obj, name) {
return window.getComputedStyle
? getComputedStyle(obj, null)[name]
: obj.currentStyle[name]
}
- 参数
- clientWidth | clientHeight
- 这两个属性可以获取元素的『可见宽度和高度,包括内容区和内边距』
- 不带单位
- offsetWidth | offsetHeight
- 获取元素的『整个的宽度和高度,包括内容区、内边距和边框』
- offsetParent
- 可以用来获取当前元素的定位父元素
- 会获取到离当前元素最近的开启了定位的祖先元素
- 如果所有的祖先元素都没有开启定位,则返回 body
- offsetLeft | offsetTop
- 当前元素相对于其定位父元素的『水平或垂直偏移量』
- scrollWidth | scrollHeight
- 可以获取元素整个滚动区域的宽度和高度
- scrollLeft | scrollTop
- 可以获取『水平或垂直滚动条滚动的距离』
- 判断滚动条是否到底
- 垂直滚动条滚动到底:
1
scrollHeight - scrollTop == clientHeight
- 水平滚动条滚动到底:
1
scrollWidth - scrollLeft == clientWidth
- 垂直滚动条滚动到底:
- ele.setCapture()
- 这个元素将会把『下一次所有的鼠标按下相关的事件捕获到自身』上
事件(Event)
事件指的是用户和浏览器之间的交互行为。比如:点击按钮、关闭窗口、鼠标移动等
事件对象
- 当响应函数被调用时,浏览器每次都会将一个事件对象作为实参传递进响应函数中,这个事件对象中封装了当前事件的相关信息,比如:鼠标的坐标、按键,键盘的按键,滚轮的方向等
- 在响应函数中定义一个形参,来使用事件对象,但是在 IE8 及以下的浏览器中,是将事件对象作为 window 对象的属性保存的
- 『解决事件对象的兼容性问题』
1
2
3元素.事件 = function (event) {
event = event || window.event
} - clientX 可以获取鼠标指针的水平坐标,cilentY 可以获取鼠标指针的垂直坐标
- 『获取滚动条滚动的距离』
- chrome 认为浏览器的滚动条是 body 的,可以通过 body.scrollTop 来获取
- 火狐等浏览器认为浏览器的滚动条是 html 的,
- 解决兼容问题:
1
st = document.body.scrollTop || document.documentElement.scrollTop;
事件的冒泡(Bubble)
- 释义:指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发。
- 如果需要取消冒泡,可以将事件对象的 cancelBubble 设置为 true
- 示例:
1
2
3
4元素.事件 = function (event) {
event = event || window.event
event.cancelBubble = true
}
事件的委派
- 释义:指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素从而通过祖先元素的响应函数来处理事件。
- 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
- target — event 中的 target 表示的触发事件的对象
事件的绑定
1 | 对象.事件 = 函数 |
只能同时为一个元素的一个事件绑定一个响应函数,
不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的
绑定事件的方式:
- 可以在标签的事件属性中设置相应的 JS 代码(不建议)
1
<button onclick="js代码。。。">按钮</button>
- 可以通过为对象的指定事件属性设置回调函数的形式来处理事件
1
2
3
4
5
6
7<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
alert("你还点~~~");
};
</script>
- 可以在标签的事件属性中设置相应的 JS 代码(不建议)
addEventListener() (不支持 IE8 及以下的浏览器)
- 可以为元素绑定响应函数
- 参数:
- 事件的字符串,不要 on
- 回调函数,当事件触发时该函数会被调用
- 是否在捕获阶段触发事件,需要一个布尔值,一般都传 false
- 使用 addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,
- 这样当事件被触发时,响应函数将会按照函数的绑定顺序执行
- 示例:
1
2
3
4
5
6
7btn01.addEventListener(
'click',
function () {
alert(1)
},
false
)
attachEvent()
- 在IE8中可以使用 attachEvent()来绑定事件
- 参数:
- 事件的字符串,要 on
- 回调函数
- 这个方法也可以同时为一个事件绑定多个处理函数,
- 不同的是它是后绑定先执行,执行顺序和 addEventListener()相反
- 示例:
1
2
3btn01.attachEvent('onclick', function () {
alert(1)
})
定义一个函数,用来为指定元素绑定响应函数
- addEventListener() 中的 this,是绑定事件的对象
- attachEvent()中的 this,是 window
- 需要统一两个方法 this
- 参数:
- obj 要绑定事件的对象
- eventStr 事件的字符串(不要 on)
- callback 回调函数
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12function bind(obj, eventStr, callback) {
if (obj.addEventListener) {
//大部分浏览器兼容的方式
obj.addEventListener(eventStr, callback, false)
} else {
//IE8及以下
obj.attachEvent('on' + eventStr, function () {
//在匿名函数中调用回调函数
callback.call(obj)
})
}
}
事件的传播
- 微软认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,
然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。 - 网景认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素
W3C 综合了两个公司的方案,将事件传播分成了三个阶段
- 捕获阶段
- 在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
- 目标阶段
- 事件捕获到目标元素,捕获结束开始在目标元素上触发事件
- 冒泡阶段
- 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件
- 在捕获阶段就触发事件,可以将 addEventListener()的第三个参数设置为 true
- 一般情况下不会希望在捕获阶段触发事件,所以这个参数一般都是 false
- IE8 及以下的浏览器中没有捕获阶段
滚轮事件
- onmousewheel 鼠标滚轮滚动的事件,会在滚轮滚动时触发,但是火狐不支持该属性
- 在『火狐』中需要使用 DOMMouseScroll 且通过 addEventListener()来绑定滚动事件
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34box1.onmousewheel = function (event) {
event = event || window.event
//event.wheelDelta 可以获取鼠标滚轮滚动的方向
//向上滚 120 向下滚 -120
//wheelDelta这个值不看大小,只看正负
//wheelDelta这个属性火狐中不支持
//在火狐中使用event.detail来获取滚动的方向
//向上滚 -3 向下滚 3
/*
* 当鼠标滚轮向下滚动时,box1变长
* 当滚轮向上滚动时,box1变短
*/
//判断鼠标滚轮滚动的方向
if (event.wheelDelta > 0 || event.detail < 0) {
//向上滚,box1变短
box1.style.height = box1.clientHeight - 10 + 'px'
} else {
//向下滚,box1变长
box1.style.height = box1.clientHeight + 10 + 'px'
}
/*
* 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false
* 需要使用event来取消默认行为event.preventDefault();
* 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错
*/
event.preventDefault && event.preventDefault()
/*
* 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,
* 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
*/
return false
}
//为火狐绑定滚轮事件
bind(box1, 'DOMMouseScroll', box1.onmousewheel)
键盘事件
- onkeydown: 按键被按下
- 对于 onkeydown 来说如果一直按着某个按键不松手,则事件会一直触发
- 当 onkeydown 连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快,这种设计是为了防止误操作的发生。
- onkeyup: 按键被松开
- 键盘事件一般都会绑定给一些可以获取到焦点的对象或者是 document
- 可以通过 keyCode 来获取按键的编码,通过它可以判断哪个按键被按下
- altKey、ctrlKey、shiftKey
- 这个三个用来判断 alt、ctrl 和 shift 是否被按下,如果按下则返回 true,否则返回 false
- 示例
1
2
3
4
5
6
7
8
9
10
11
12
13document.onkeyup = function () {
console.log('按键松开了')
}
input.onkeydown = function (event) {
event = event || window.event
//数字 48 - 57
//使文本框中不能输入数字
if (event.keyCode >= 48 && event.keyCode <= 57) {
//在文本框中输入内容,属于onkeydown的默认行为
//如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中
return false
}
}
拖拽事件
- 拖拽的流程
- 当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
- 当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
- 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55window.onload = function(){
var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");
var img1 = document.getElementById("img1");
//开启box1的拖拽
drag(box1);
//开启box2的
drag(box2);
drag(img1);
};
/*
* 提取一个专门用来设置拖拽的函数
* 参数:开启拖拽的元素
*/
function drag(obj){
obj.onmousedown = function(event){
// 设置box1捕获所有鼠标按下的事件
/*
* setCapture()
* - 只有IE支持,但是在火狐中调用时不会报错,而如果使用chrome调用,会报错
*/
obj.setCapture && obj.setCapture();
event = event || window.event;
// div的偏移量 鼠标.clentX - 元素.offsetLeft
// div的偏移量 鼠标.clentY - 元素.offsetTop
var ol = event.clientX - obj.offsetLeft;
var ot = event.clientY - obj.offsetTop;
// 为document绑定一个onmousemove事件
document.onmousemove = function(event){
event = event || window.event;
// 当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
// 获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;
// 修改box1的位置
obj.style.left = left+"px";
obj.style.top = top+"px";
};
// 为document绑定一个鼠标松开事件
document.onmouseup = function(){
// 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
// 取消document的onmousemove事件
document.onmousemove = null;
// 取消document的onmouseup事件
document.onmouseup = null;
// 当鼠标松开时,取消对事件的捕获
obj.releaseCapture && obj.releaseCapture();
};
/*
* 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
* 此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
* 可以通过return false来取消默认行为,但是这招对IE8不起作用
*/
return false;
};
文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。
如果将 js 代码编写到页面的上边,当代码执行时,页面中的 DOM 对象还没有加载,
此时将会无法正常获取到 DOM 对象,导致 DOM 操作失败。解决方式一:
- 可以将 js 代码编写到 body 里,放在最下边执行
- 示例:
1
2
3
4
5
6<body>
<button id='btn'>按钮</button>
<script>
var btn = document.getElementById("btn"); btn.onclick = function(){};
</script>
</body>
解决方式二:
- 将 js 代码编写到 window.onload = function(){}中
- window.onload 对应的回调函数会在整个页面加载完毕以后才执行,
所以可以确保代码执行时,DOM 对象已经加载完毕了 - 示例
1
2
3
4
5
6<script>
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){};
};
</script>
BOM
浏览器对象模型
- BOM 可以使我们通过 JS 来操作浏览器,在 BOM 中提供了一组对象,用来完成对浏览器的操作
BOM 对象
Window:代表的是整个浏览器的窗口,同时 window 也是网页中的全局对象
userAgent:是一个字符串,通过这个字符串来判断不同的浏览器
- 火狐的 userAgent
1
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
- Chrome 的 userAgent
1
Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36
- IE8-10
1
Mozilla/4.0 (compatible; MSIE 8/9/10.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
- IE11
1
Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; rv:11.0) like Gecko
- 注意:『在IE11中已经将微软和IE相关的标识都已经去除了,所以基本已经不能通过UserAgent来识别一个浏览器是否是IE』
- 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16if (/firefox/i.test(ua)) {
alert('你是火狐!!!')
} else if (/chrome/i.test(ua)) {
alert('你是Chrome')
} else if (/msie/i.test(ua)) {
alert('你是IE浏览器~~~')
} else if ('ActiveXObject' in window) {
alert('你是IE11,枪毙了你~~~')
}
// 如果通过UserAgent不能判断,还可以通过一些浏览器中特有的对象,来判断浏览器的信息
// 比如:ActiveXObject
if ('ActiveXObject' in window) {
alert('你是IE,我已经抓住你了~~~')
} else {
alert('你不是IE~~~')
}
- 火狐的 userAgent
Location:代表当前浏览器的地址栏信息,或者操作浏览器跳转页面
- 直接修改 location 属性,页面会自动跳转到该路径,并且会生成相应的历史记录
1
location = "http://www.baidu.com";
- assign(): 用来跳转到其他的页面,作用和直接修改 location 一样
- 示例:
1
location.assign("http://www.baidu.com");
- 示例:
- reload(): 用于重新加载当前页面,作用和刷新按钮一样
- 如果在方法中传递一个 true,作为参数,则会强制清空缓存刷新页面
- 示例:
1
location.reload(true);
- replace(): 可以使用一个新的页面替换当前页面,调用完毕也会跳转页面
- 不会生成历史记录,不能使用回退按钮回退
- 示例:
1
location.replace("01.BOM.html");
- 直接修改 location 属性,页面会自动跳转到该路径,并且会生成相应的历史记录
History:代表浏览器的历史记录,可以通过该对象来操作浏览器的历史记录
- 由于隐私原因,该对象不能获取到具体的历史记录,只能操作浏览器向前或向后翻页,而且该操作只在当次访问时有效
- length: 可以获取到当成访问的链接数量
- back(): 可以用来回退到上一个页面,作用和浏览器的回退按钮一样
- forward(): 可以跳转下一个页面,作用和浏览器的前进按钮一样
- go(): 可以用来跳转到指定的页面
- 它需要一个整数作为参数
- 1:表示向前跳转一个页面 相当于 forward()
- 正整数:表示向前跳转 n 个页面
- 负整数:表示向后跳转 n 个页面
Screen:代表用户的屏幕信息,通过该对象可以获取到用户显示器的相关信息
『这些BOM对象在浏览器中都是作为window对象的属性保存的,可以通过window对象来使用,也可以直接使用』