-
简介
Document Object Model 文档对象模型,通过DOM可以来任意来修改网页中各个内容。
文档指的是网页,一个网页就是一个文档。
对象指将网页中的每一个节点都转换为对象。
模型用来表示节点和节点之间的关系,方便操作页面。 - 节点(Node)
节点是构成网页的最基本的单元,网页中的每一个部分都可以称为是一个节点。
虽然都是节点,但是节点的类型却是不同的,常用的节点:
- 文档节点 (Document),代表整个网页
- 元素节点(Element),代表网页中的标签
- 属性节点(Attribute),代表标签中的属性
- 文本节点(Text),代表网页中的文本内容
DOM操作
在网页中浏览器已经为我们提供了document对象,它代表的是整个网页,它是window对象的属性,可以在页面中直接使用。
document查询方法:
1)根据元素的 id 属性查询一个元素节点对象:
document.getElementById("id属性值");
2)根据元素的name属性值查询一组元素节点对象:
document.getElementsByName("name属性值");
3)根据标签名来查询一组元素节点对象:
document.getElementsByTagName("标签名");
元素的属性:
读取元素的属性:
语法:元素.属性名
修改元素的属性:
语法:元素.属性名 = 属性值
innerHTML
使用该属性可以获取或设置元素内部的HTML代码
city. innerHTML += "<li>广州</li>";
-
文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。
如果将js代码编写到页面的上边,当代码执行时,页面中的DOM对象还没有加载,此时将会无法正常获取到DOM对象,导致DOM操作失败。
解决方式一:
可以将js代码编写到body的下边
<body>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
};
</script>
</body>
解决方式二:
将js代码编写到window.onload = function(){}中,
window.onload 对应的回调函数会在整个页面加载完毕以后才执行。
<script>
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
};
};
</script>
- DOM查询
- 通过具体的元素节点来查询
通过标签名查询当前元素的指定后代元素
元素.getElementsByTagName()
获取当前元素的所有子节点, 会获取到空白的文本子节点,根据DOM标准,标签间空白也会当成文本子节点。
元素.childNodes
获取当前元素的所有子元素
元素.children
获取当前元素的第一个子节点
元素.firstChild
获取当前元素的最后一个子节点
元素.lastChild
获取当前元素的父元素
元素.parentNode
获取当前元素的前一个兄弟节点
元素.previousSibling
获取当前元素的后一个兄弟节点
元素.nextSibling
- innerHTML和innerText
这两个属性并没有在DOM标准定义,但是大部分浏览器都支持这两个属性。
两个属性作用类似,都可以获取到标签内部的内容,
不同是innerHTML会获取到html标签,而innerText会自动去除标签。
如果使用这两个属性来设置标签内部的内容时,没有任何区别的。
读取标签内部的文本内容
元素.firstChild.nodeValue
- document对象的其他的属性和方法
document.all
获取页面中的所有元素,相当于document.getElementsByTagName("*");
document.documentElement
获取页面中html根元素
document.body
获取页面中的body元素,body的引用
document.getElementsByClassName()
根据元素的class属性值查询一组元素节点对象(这个方法不支持IE8及以下的浏览器)
document.querySelector()
根据CSS选择器去页面中查询一个元素
如果匹配到的元素有多个,则它会返回查询到的第一个元素
document.querySelectorAll()
根据CSS选择器去页面中查询一组元素
会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个
- DOM增删改
根据标签名创建一个元素节点对象
document.createElement()
根据文本内容创建一个文本节点对象
document.createTextNode()
向父节点中添加指定的子节点
父节点.appendChild(子节点)
// 向父节点city中添加子节点li
//方式一
var li = document.createElement("li");
var text = document.createTextNode("广州");
li.appendChild(text);
city.appendChild(li);
// 方式二
city. innerHTML += "<li>广州</li>";
// 方式三(推荐)
var li = document.createElement("li");
li.innerHTML = "广州";
city.appendChild(li);
将一个新的节点插入到旧节点的前边
父节点.insertBefore(新节点,旧节点)
使用一个新的节点去替换旧节点
父节点.replaceChild(新节点,旧节点)
删除指定的子节点
父节点.removeChild(子节点)
推荐方式:子节点.parentNode.removeChild(子节点)
- DOM对CSS的操作
- 读取和修改内联样式
使用style属性来操作元素的内联样式
- 读取内联样式:
语法:元素.style.样式名
元素.style.width
元素.style.height
注意:如果样式名中带有-,则需要将样式名修改为驼峰命名法
将-去掉,然后-后的字母改大写, 比如:background-color --> backgroundColor , border-width ---> borderWidth
- 修改内联样式:
语法:元素.style.样式名 = 样式值
通过style修改的样式都是内联样式,由于内联样式的优先级比较高,所以我们通过JS来修改的样式,往往会立即生效,但是如果样式中设置了!important,则内联样式将不会生效。
- 读取元素的当前样式
- 正常浏览器
使用getComputedStyle()
这个方法是window对象的方法,可以返回一个对象,这个对象中保存着当前元素生效样式。
参数:
要获取样式的元素
可以传递一个伪元素,一般传null
// 获取元素的宽度
getComputedStyle(box , null)["width"];
通过该方法读取到样式都是只读的不能修改
// IE8 使用currentStyle
// 元素.currentStyle.样式名
box.currentStyle["width"]
- 其他的样式相关的属性
以下样式都是只读的
clientHeight
元素的可见高度,指元素的内容区和内边距的高度
clientWidth
元素的可见宽度,指元素的内容区和内边距的宽度
offsetHeight
整个元素的高度,包括内容区、内边距、边框
offfsetWidth
整个元素的宽度,包括内容区、内边距、边框
offsetParent
当前元素的定位父元素
离他最近的开启了定位的祖先元素,如果所有的元素都没有开启定位,则返回body
offsetLeft、offsetTop
当前元素和定位父元素之间的偏移量
offsetLeft 水平偏移量
offsetTop 垂直偏移量
scrollHeight、scrollWidth
获取元素滚动区域的高度和宽度
scrollTop、scrollLeft
获取元素垂直和水平滚动条滚动的距离
判断滚动条是否滚动到底
垂直滚动条: scrollHeight - scrollTop = clientHeight
水平滚动条: scrollWidth - scrollLeft = clientWidth
DOM其它操作
-
DOM操作CSS
通过JS修改元素的样式:
语法:元素.style.样式名 = 样式值
注:如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color,需要将这种样式名修改为驼峰命名法backgroundColor。
我们通过style属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示。
但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加 !important。
读取元素的样式:
语法:元素.style.样式名
注:通过style属性设置和读取的都是内联样式,无法读取样式表中的样式。
window.onload = function(){
/*
* 点击按钮以后,修改box1的大小
*/
//获取box1
var box1 = document.getElementById("box1");
var btn01 = document.getElementById("btn01");
btn01.onclick = function(){
box1.style.width = "300px";
box1.style.height = "300px";
box1.style.backgroundColor = "yellow";
};
//点击按钮2以后,读取元素的样式
var btn02 = document.getElementById("btn02");
btn02.onclick = function(){
alert(box1.style.width);
getStyle(box1 , "width");
};
/*
* 定义一个函数,用来获取指定元素的当前的样式
* 参数:
* obj 要获取样式的元素
* name 要获取的样式名
*/
function getStyle(obj , name){
if(window.getComputedStyle){
//正常浏览器的方式,具有getComputedStyle()方法
return getComputedStyle(obj , null)[name];
}else{
//IE8的方式,没有getComputedStyle()方法
return obj.currentStyle[name];
}
//return window.getComputedStyle?getComputedStyle(obj , null)[name]:obj.currentStyle[name];
}
};
- 获取其它css操作的属性:
/*
* clientWidth
* clientHeight
* 这两个属性可以获取元素的可见宽度和高度
* 这些属性都是不带px的,返回都是一个数字,可以直接进行计算
* 会获取元素宽度和高度,包括内容区和内边距
* 这些属性都是只读的,不能修改
*/
box1.clientWidth;
box1.clientHeight;
/*
* offsetWidth
* offsetHeight
* 获取元素的整个的宽度和高度,包括内容区、内边距和边框
*/
box1.offsetWidth;
/*
* offsetParent
* 可以用来获取当前元素的定位父元素,会获取到离当前元素最近的开启了定位的祖先元素
* 如果所有的祖先元素都没有开启定位,则返回body
*/
var op = box1.offsetParent;
/*
* offsetLeft
* 当前元素相对于其定位父元素的水平偏移量
* offsetTop
* 当前元素相对于其定位父元素的垂直偏移量
*/
box1.offsetLeft;
/*
* scrollWidth
* scrollHeight
* 可以获取元素整个滚动区域的宽度和高度
*/
box4.clientHeight;
box4.scrollWidth;
/*
* scrollLeft
* 可以获取水平滚动条滚动的距离
* scrollTop
* 可以获取垂直滚动条滚动的距离
*/
box4.scrollLeft;
box4.scrollTop;
//当满足scrollHeight - scrollTop == clientHeight,说明垂直滚动条滚动到底了
//当满足scrollWidth - scrollLeft == clientWidth,说明水平滚动条滚动到底
事件(Event)
事件指的是用户和浏览器之间的交互行为。比如:点击按钮、关闭窗口、鼠标移动 ... ...
可以为事件来绑定回调函数来响应事件。
绑定事件的方式:
1.可以在标签的事件属性中设置相应的JS代码
<button onclick = "js代码......">按钮</button>
2.可以通过为对象的指定事件属性设置回调函数的形式来处理事件
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
};
</script>
- 事件对象
当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标、键盘哪个按键被按下、鼠标滚轮滚动的方向等。
可以在响应函数中定义一个形参,来使用事件对象,但是在IE8以下浏览器中事件对象没有做为实参传递,而是作为window对象的属性保存。
元素.事件 = function(event){
event = event || window.event;
};
元素.事件 = function(e){
e = e || event;
};
// 当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
window.onload = function(){
//获取两个div
var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");
/*
* onmousemove
* 该事件将会在鼠标在元素中移动时被触发
*
*/
areaDiv.onmousemove = function(event){
// IE8以下浏览器中事件对象作为window对象的属性保存。
// 解决事件对象的兼容性问题。
event = event || window.event;
/*
* clientX可以获取鼠标指针的水平坐标
* cilentY可以获取鼠标指针的垂直坐标
*/
var x = event.clientX;
var y = event.clientY;
//在showMsg中显示鼠标的坐标
showMsg.innerHTML = "x = "+x + " , y = "+y;
};
};
- 事件的冒泡(Bubble)
事件的冒泡指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发。
事件的冒泡大部分情况下都是有益的,如果需要取消冒泡,则需要使用事件对象来取消。
可以将事件对象的cancelBubble设置为true,即可取消冒泡
元素.事件 = function(event){
event = event || window.event;
event.cancelBubble = true;
};
事件的委派
将事件统一绑定给元素共同的祖先元素,当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理。
事件的委派利用冒泡,减少了事件绑定的次数,提高程序性能。事件的绑定
使用 对象.事件 = 函数 的形式绑定响应函数,只能同时为一个元素的一个事件绑定一个响应函数。如果绑定多个,先绑定的会被覆盖。
- addEventListener()
通过addEventListener()方法也可以为元素绑定响应函数,可以同时为一个元素的相同事件同时绑定多个响应函数,当事件被触发时,响应函数将会按照函数的绑定顺序执行。
注:不支持IE8及以下的浏览器
参数:
1.事件的字符串,不要on
2.回调函数,当事件触发时该函数会被调用
3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
var btn2 = document.getElementById("btn2");
btn2.addEventListener("click",function(){
alert(1);
},false);
btn2.addEventListener("click",function(){
alert(2);
},false);
- attachEvent()
在IE8中可以使用attachEvent()来绑定事件,可以同时为一个事件绑定多个处理函数,但是它是后绑定先执行,执行顺序和addEventListener()相反。
参数:
1.事件的字符串,要on
2.回调函数
btn2.attachEvent("onclick",function(){
alert(1);
});
btn2.attachEvent("onclick",function(){
alert(2);
});
注:addEventListener()中的this,是绑定事件的对象
attachEvent()中的this,是window
//定义一个函数,用来为指定元素绑定响应函数
/*
* 参数:
* obj 要绑定事件的对象
* eventStr 事件的字符串(不要on)
* callback 回调函数
*/
function bind(obj , eventStr , callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr , callback , false);
}else{
/*
* this是谁由调用方式决定
* callback.call(obj)
*/
//IE8及以下
obj.attachEvent("on" + eventStr , function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}
- 事件的传播
事件传播分成了三个阶段
- 捕获阶段
在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件; - 目标阶段
事件捕获到目标元素,捕获结束开始在目标元素上触发事件; - 冒泡阶段
事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件;
如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true。
一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false。
注:IE8及以下的浏览器中没有捕获阶段
- 拖拽
拖拽的流程- 当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
- 当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
- 当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
var box = document.getElementById("box");
//为box绑定一个鼠标按下事件
box.onmousedown = function(event){
// 设置box捕获所有鼠标按下的事件
// setCapture() 只有IE支持,但是在火狐中调用时不会报错,而如果使用chrome调用,会报错
box.setCapture && box.setCapture();
event = event || window.event;
//div的偏移量 鼠标.clentX - 元素.offsetLeft
//div的偏移量 鼠标.clentY - 元素.offsetTop
var ol = event.clientX - box1.offsetLeft;
var ot = event.clientY - box1.offsetTop;
//为document绑定一个onmousemove事件
document.onmousemove = function(event){
event = event || window.event;
//获取鼠标的坐标
var left = event.clientX - ol;
var top = event.clientY - ot;
//修改box1的位置
box1.style.left = left+"px";
box1.style.top = top+"px";
};
//为document绑定一个鼠标松开事件
document.onmouseup = function(){
//取消document的onmousemove事件
document.onmousemove = null;
//取消document的onmouseup事件
document.onmouseup = null;
//当鼠标松开时,取消对事件的捕获
obj.releaseCapture && obj.releaseCapture();
};
return false;
};
当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,如果不希望发生这个行为,则可以通过return false来取消默认行为。但是这招对IE8不起作用
- 滚轮事件
onmousewheel 鼠标滚轮滚动事件,会在滚轮滚动时触发,但是火狐不支持该属性。在火狐中需要使用 DOMMouseScroll 来绑定滚动事件,该事件需要通过addEventListener()函数来绑定。
使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false, 需要使用event来取消默认行为event.preventDefault(); , 但是IE8不支持event.preventDefault();
window.onload = function(){
var box1 = document.getElementById("box1");
//为box绑定一个鼠标滚轮滚动的事件
box.onmousewheel = function(event){
event = event || window.event;
//event.wheelDelta 可以获取鼠标滚轮滚动的方向,wheelDelta这个值不看大小,只看正负
//alert(event.wheelDelta);
//wheelDelta这个属性火狐中不支持,在火狐中使用event.detail来获取滚动的方向
/*
* 当鼠标滚轮向下滚动时,box变长
* 当滚轮向上滚动时,box变短
*/
//判断鼠标滚轮滚动的方向
if(event.wheelDelta > 0 || event.detail < 0){
//向上滚,box变短
box.style.height = box1.clientHeight - 10 + "px";
}else{
//向下滚,box变长
box.style.height = box1.clientHeight + 10 + "px";
}
event.preventDefault && event.preventDefault();
return false;
};
//为火狐绑定滚轮事件
bind(box1,"DOMMouseScroll",box1.onmousewheel);
};
function bind(obj , eventStr , callback){
if(obj.addEventListener){
//大部分浏览器兼容的方式
obj.addEventListener(eventStr , callback , false);
}else{
//IE8及以下
obj.attachEvent("on"+eventStr , function(){
//在匿名函数中调用回调函数
callback.call(obj);
});
}
}
- 键盘事件
onkeydown 按键被按下
对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发。当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快,这种设计是为了防止误操作的发生。
onkeyup 按键被松开
键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document。
可以通过keyCode来获取按键的编码, 通过它可以判断哪个按键被按下。
除了keyCode,事件对象中还提供了几个属性:altKey、ctrlKey、shiftKey 这三个用来判断alt ctrl 和 shift是否被按下,按下则返回true,否则返回false。
document.onkeydown = function(event){
event = event || window.event;
//console.log(event.keyCode);
//判断y和ctrl是否同时被按下
if(event.keyCode === 89 && event.ctrlKey){
console.log("ctrl和y都被按下了");
}
};
/*document.onkeyup = function(){
console.log("按键松开了");
};*/