有的没的
DOM就是把html视为一个层次结构(树形结构)的文档
文档(Document):一个页面就是一个文档,html或者xml文件,html主要用来展示数据,xml侧重于存储数据
html文件看做是一个文档,由于万物皆对象,所以把这个文档看成是一个对象,文档中的所有标签都可以看成是一个对象。
元素(Element):Html文档中的所有标签
页面中的每个标签都是一个元素,每个元素都可以看成是一个对象,标签可以嵌套,标签中有标签,元素中有元素。html页面中都有一个跟标签,html,它也称为根元素。
节点(Node):文档中的所有内容都可以称之为节点:标签、属性、文本。
根元素(root):文档中的第一个元素,html文档就是<html>,只有一个
文本节点
属性节点
dom可以做什么
1. 找对象(元素)
2. 设置元素属性
3. 设置元素样式
4. 动态创建和删除元素
5. 事件—触发响应
--事件源(事件的触发者)
--事件名称
--事件响应程序
一个栗子:
点击操作:事件
按钮:事件源
点击:事件名称
被点击了:触发了
弹框了:响应
html标签中的id属性中存储的值是唯一的,id属性就像是人的身份证号码一样,不能重复,他是页面中的唯一标识;
var btObj = document.getElementById(‘id属性的值’);返回的是一个元素对象,他有很多的属性,可以通过’.属性’来获取属性;
btObj.onclick = f2;(f2后面不要加括号)
innerText、textContent和innerHTML
设置标签中的文本内容,应该使用textContent属性,谷歌、火狐支持,IE8不支持;innerText属性,谷歌、火狐、IE8都支持,它是IE8的标准
获取标签中的文本内容,textContent属性,谷歌、火狐支持,IE8不支持(输出undefined);inertText属性,谷歌、火狐、IE8都支持
如果这个属性在浏览器中不支持,那么这个属性的类型是undefined
//设置任意标签中间的任意文本内容
function setTextContent (element , text){
if(typeof(element.textContent) === undefined){
element.innerText = text;
}else {
element.textContent = text;
}
}
//获取任意标签中间的文本内容
function getTextContent (element){
if(typeof(element.textContent) === undefined){
return element.innerText;
}else {
return element.textContent;
}
}
innerHTML也可以设置文本内容,并且任何浏览器都是支持的;而且它还可以设置html标签。同样,获取标签的时候,innerHTML也能获取到标签。
总结:
想要设置标签内容,就用innerHTML,如果想要设置文本内容,innerText或者textContent或者innerHTML,推荐使用innerHTML,没有兼容性问题。
获取的时候,innerText可以获取标签中的文本内容,但是如果标签中还有标签,那么最里面的标签文本也能获取到;innerHTML在获取标签中的文本时,能获取到标签中的文本,如果标签中还有标签,那么获取到的就是标签中的标签。
自定义属性
<ul id="score">
<li score='10分'>你的成绩</li>
<li score='20分'>他的成绩</li>
<li score='30分'>她的成绩</li>
<li score='40分'>它的成绩</li>
<li score='50分'>谁的成绩</li>
</ul>
var list = document.getElementsByTagName('li');
for(var i = 0;i<list.length;i++){
list[i].onclick = function(){
alert(this.getAttribute('score'));
//score属性时设置在<li>标签上的,而this指的是DOM对象,直接this.score是获取不到这个属性值的,
//要通过getAttribute方法获取标签的某个属性
//同样,要设置标签的属性,要使用list[i].setAttribute()方法,其中有两个参数,一个属性名,一个属性值
}
}
一般在设置自定义属性的时候,不通过上面的方式对标签添加属性,如果标签很多的话会造成代码重复,一般是通过循环遍历,使用list[i].setAttribute()方式添加标签元素。
移除自定义属性时,使用的方法是element.removeAttribute(‘属性名’);属性和值都没有了,这种方式也可以移除元素自带的属性。
节点
节点有三个属性:nodeType、nodeName、nodeValue
nodeType:节点的类型,1:标签,2:属性,3:文本
nodeName:节点的名字,标签节点:大写的标签名字;属性节点:小写的属性名字;文本节点:#text
nodeValue:节点的值:标签节点:null;属性节点:属性值;文本节点:文本内容
12行代码
<div id="dv">
<ul id="uu">第一个子节点
<li>第一个子元素</li>
<li>前一个兄弟元素</li>前一个兄弟节点
<li id="some">吼吼</li>后一个兄弟节点
<li>后一个兄弟元素</li>
<li>最后一个子元素</li>最后一个子节点
</ul>
</div>
var ulObj = document.getElementById('uu');
//ul的父元素
console.log(ulObj.parentElement);
//ul的父节点
console.log(ulObj.parentNode);
//ul的子元素
console.log(ulObj.children);
//ul的子节点
console.log(ulObj.childNodes);
console.log('----------------------------------------------');
//ul的第一个子元素
console.log(ulObj.firstElementChild);
//ul的第一个子节点
console.log(ulObj.firstChild);
//ul的最后一个子元素
console.log(ulObj.lastElementChild);
//ul的最后一个子节点
console.log(ulObj.lastChild);
var someObj = document.getElementById('some');
//某个元素的前一个兄弟元素
console.log(someObj.previousElementSibling)
//某个元素的前一个兄弟节点
console.log(someObj.previousSibling);
//某个元素的后一个兄弟元素
console.log(someObj.nextElementSibling);
//某个元素的后一个兄弟节点
console.log(someObj.nextSibling);
分割线后面的代码在IE8中会有写问题,所有的获取元素的不再支持,输出undefined,在获取节点时,以获取第一个节点(firstChild)为例,如果第一个节点中有文本,则这个方法返回的还是第一个节点,如果第一个节点中没有文本,则这个方法返回的是第一个元素。但在IE11中又重新支持。恩,IE这样玩也是……
所以就有了下面的兼容性代码:
function getFirstElementChild(element){
if(element.firstElementChild){
return element.firstElementChild;
}else{
var node = element.firstChild;
//一直判断node是否存在,并且是否是标签(标签的nodeType==1),如果是则返回,如果不是,则获取node的后一个兄弟节点
while(node && node.nodeType!= 1){
node = node.nextSibling;
}
return node;
}
}
获取元素的方法
根据id属性的值获取元素,返回来的是一个元素对象
getElementById(‘id属性的值’)
根据标签名字获取元素,返回来的是一个伪数组,里面保存了多个DOM对象
getElementsByTagName(‘标签名字’)
//下面的几个,有的浏览器不支持
根据name属性的值获取元素,返回来的是一个伪数组,里面保存了多个DOM对象
getElementsByName(‘name属性的值’)
根据类样式的名字来获取元素,返回来的是一个伪数组,里面保存了多个DOM对象
getElementsByClassName(‘类样式的名字’)
根据选择器获取元素,返回来的是一个元素对象
querySelector(‘选择器的名字’)
根据选择器获取元素,返回来的是一个伪数组,里面保存了多个DOM对象
querySelectorAll(‘选择器的名字’)
创建元素的三种方式
document.write
document.write(‘标签代码及内容’)
这种方式创建元素有缺陷:如果在页面加载完毕后再通过这种方式创建元素的话,整个页面就会被覆盖掉。
对象.innerHTML
对象.innerHTML(‘标签代码及内容’)
在谁里面添加标签,就用谁做对象
<input type="button" value="动态创建列表" id="createList">
<div id="list"></div>
var arrName = ['陈信宏', '温尚翊', '石锦航', '蔡升晏', '刘谚明'];
var divObj = document.getElementById('list');
document.getElementById('createList').onclick = function () {
var str = '<ul>';
for (var i = 0; i < arrName.length; i++) {
str += '<li>';
str += arrName[i];
str += '</li>';
}
str += '</ul>';
divObj.innerHTML = str;
var list = divObj.getElementsByTagName('li');
for (var j = 0; j < list.length; j++) {
list[j].style.cursor = 'pointer';
list[j].onmouseover = function () {
this.style.backgroundColor = 'green';
}
list[j].onmouseout = function () {
this.style.backgroundColor = '';
}
}
}
createElement
var appendChd = document.getElementById('append');
document.getElementById('addChild').onclick = function(){
var pObj = document.createElement('p');
setTextContent(pObj,'我是一个p标签');
appendChd.appendChild(pObj);
}
一个栗子:动态创建表格
var arrTable = [
{name:'百度',href:'https://www.baidu.com/'},
{name:'谷歌',href:'https://www.google.cn/'},
{name:'百度',href:'https://www.baidu.com/'},
{name:'谷歌',href:'https://www.google.cn/'},
{name:'百度',href:'https://www.baidu.com/'},
{name:'谷歌',href:'https://www.google.cn/'}
]
document.getElementById('createTable').onclick = function(){
var tableObj = document.createElement('table');
var tabDivObj = document.getElementById('table');
tabDivObj.appendChild(tableObj);
tableObj.border = '1';
tableObj.cellPadding = '0';
tableObj.cellSpacing = '0';
for(var i = 0;i<arrTable.length;i++){
var col = document.createElement('tr');
tableObj.appendChild(col);
var row1 = document.createElement('td');
row1.innerText = arrTable[i].name;
row1.style.padding = '10px';
var row2 = document.createElement('td');
row2.innerHTML = "<a href='"+arrTable[i].href+"'>"+arrTable[i].name+"</a>";
row2.style.padding = '10px';
tableObj.appendChild(row1);
tableObj.appendChild(row2);
}
}
何时使用匿名函数,何时使用命名函数?
如果是循环的方式添加事件,推荐使用命名函数;如果不是循环的方式添加事件,推荐使用匿名函数。
元素的相关方法
appendChild(元素) 追加元素,旧元素后移,新元素在第一个位置
insertBefore(新元素,旧元素) 插入元素
replaceChild(新元素,旧元素) 替换旧元素
removeChild(旧元素) 删除旧元素
为元素绑定事件
为同一个元素绑定多个相同的事件
1. 对象.on事件名 = 函数(命名函数、匿名函数)
element.onclick = function(){}
2.addEventListener(); 谷歌、火狐是支持的,IE8****不支持
三个参数
第一个参数:事件的类型------事件的名字没有on
第二个参数:事件的处理函数------命名函数、匿名函数
第三个参数:布尔类型,false表示事件是冒泡阶段(从里向外),true表示事件是捕获阶段(从外向里)
3.attachEvent(); 只有IE8****支持
两个参数
第一个参数:事件类型------事件的名字,有on
第二个参数:事件的处理函数------命名函数、匿名函数
兼容性代码
//为任意元素绑定任意事件
function addEventListener(element,type,fn){
//判断一个对象有没有一个方法,直接对象.方法名,不要加括号
//加括号的意思就是执行方法,得到的是方法的返回值
if(element.addEventListener){
element.addEventListener(type,fn,false);
}else if(element.attachEvent){
element.attachEvent('on'+type,fn);
}else {
element['on'+type] = fn;
}
}
addEventListener和attachEvent对比
相同点:
都可以为元素绑定事件
不同点:
1. 方法名不一样
2. 参数个数不一样addEventListener参数有三个,attachEvent参数有两个
3. addEventListener中事件的名字没有on,attachEvent中事件的名字有on
4. addEventListener谷歌、火狐、IE11支持,IE8不支持,attachEvent谷歌、火狐、IE11不支持,IE8支持
5. addEventListener方法中的this是当前绑定对象,attachEvent方法中的this是window
为元素解绑事件
注:用什么样的方式绑定事件,就要用什么样的方式解绑事件
1. 对象.on事件名字 = null;
2. remoceEventListener()
三个参数:
第一个参数:事件的类型------事件的名字没有on
第二个参数:事件的处理函数------命名函数
第三个参数:布尔类型,false表示事件是冒泡阶段(从里向外),true表示事件是捕获阶段(从外向里)
这种方式解绑事件,需要在绑定事件的时候使用命名函数,最后解绑的时候使用同样的函数名
function f1(){};
document.getElementById('btn').addEventListener('click',f1,false);
document.getElementById('btn').removeEventListener('click',f1,false);
3. detachEvent()
两个参数:
第一个参数:事件类型------事件的名字,有on
第二个参数:事件的处理函数------命名函数
同样,在绑定事件的时候需要使用命名函数,在解绑的时候使用同样的函数名
兼容代码
//为任意元素解绑任意事件
function removeEventListener(element,type,fnName){
//判断一个对象有没有一个方法,直接对象.方法名,不要加括号
//加括号的意思就是执行方法,得到的是方法的返回值
if(element.removeEventListener){
element.removeEventListener(type,fnName,false);
}else if(element.detachEvent){
element.detachEvent('on'+type,fnName);
}else {
element['on'+type] = null;
}
}
阻止浏览器的默认事件
两种方式:
1. return false:
2. e.preventDefault() 这种方式IE8不支持
事件冒泡
多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素的事件触发了,外面元素的相同事件(相同事件的意思是,相同类型的事件)也会被触发。
阻止事件冒泡
在想要阻止的事件处理函数中,最后调用这么一句话
document.getElementById('btn').onclick = function(){
window.event.cancelBubble = true;
}
谷歌、IE8****都支持,火狐不支持
或者是使用事件处理对象
document.getElementById('btn').onclick = function(e){
e.stopPropagation();
}
谷歌、火狐支持,IE8****不支持
可以看到,IE8中的window.event和谷歌火狐中的e对象时相同的,在IE8中,没有e这个事件处理参数,所以不能调用其对应方法。
事件流
冒泡事件流
事件的传播是从下往上传,即从DOM树的叶子到根。
捕获事件流
事件的传播是从上往下,即从跟到叶子
var divObjs = [my$('div1'),my$('div2'),my$('div3')];
divObjs.forEach(function(element){
element.addEventListener('click',function(e){
console.log(this.id);
console.log(e.eventPhase);
},true);
})
/**
* 1.冒泡事件
* 2.目标事件
* 3.捕获事件
*
* 标识这是什么事件的属性在事件参数对象中存在,也就是上面的e,e.eventPhase
* 哪个对象触发的点击事件,那么这个对象就是目标对象,它触发的事件就是目标事件,对应的e.eventPhase属性值为2
* 通过冒泡触发的事件,对应的对象的e.eventPhase属性值就为1
* 通过捕获触发的事件,对应的对象的e.eventPhase属性值就为3
*/
总结:
事件的出发过程中可能会出现事件冒泡,为了阻止事件冒泡:
window.event.cancelBubble = true;谷歌、IE8支持,火狐不支持,
window.event是一个对象,是IE中的标准;
e.stopPropagation();谷歌、火狐支持,IE8不支持,
window.event和e都是事件参数对象,一个是IE的标准,一个是火狐的标准,事件参数e在IE8的浏览器中是不存在的,此时用window.event来代替。
事件的阶段有三个,通过e.eventPhase这个属性可以知道当前的事件是什么阶段的,如果这个属性的值是1,表示为捕获阶段,2表示目标阶段,3表示冒泡阶段;一般默认为冒泡阶段,很少用捕获阶段。
一个栗子,事件的类型在e.type属性中
//为同一个元素绑定不同的事件,指向相同的事件处理函数
my$('div1').onclick = f1;
my$('div1').onmouseover = f1;
my$('div1').onmouseout = f1;
function f1 (e){
console.log(e.type)
}
offset系列
在style标签中设置的样式属性时获取不到的,但在标签的style属性中设置的样式属性时可以获取到的。以后获取元素的高和宽用offset系列。
元素.offsetWidth; 元素的宽(有边框的,和元素中的内容是没有关系的)
元素.offsetHeight; 元素的高(有边框的,和元素中的内容是没有关系的)
元素.offsetLeft; 元素距离左边的距离
元素.offsetTop; 元素距离上边的距离
解释一下后面两个
没有脱离文档流时:
offsetLeft:父级元素的****margin + 父级元素的padding + 父级元素的border + 自己的margin
脱离文档流时:
offsetLeft:大小和父级元素的margin、padding、border已经没有关系了,只和自己的****left****和margin****有关,但相对的位置是相对父元素的位置(也就是说,这个时候,找到子元素的父元素是关键)
scroll系列
scrollWidth:元素中内容的实际宽度(没有边框),当没有内容或者内容没有超出元素时,还是元素的宽度
scrollHeight:元素中内容的实际高度(没有边框),当没有内容或者内容没有超出元素时,还是元素的高度
scrollTop:元素中的内容向上卷曲过去的距离
scrollLeft:元素中的内容向左卷曲过去的距离
兼容性代码:
//获取滚动条的滚动距离(上、左)
function getScroll (){
return {
top:window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,
left:window.pageYOffset||document.documentElement.scrollLeft||document.body.clientLeft||0
};
}
固定导航栏案例
//这个地方有个注意点,就是设置marginTop的时候,一定要记得加‘px’
window.onscroll = function () {
console.log(getScroll().top);
if(getScroll().top > my$('d1').offsetHeight){
my$('d2').className = 'div2 fixed';
my$('d3').style.marginTop = my$('d2').offsetHeight+'px';
}else{
my$('d2').className = 'div2';
my$('d3').style.marginTop = 0 +'px';
}
}
client系列
可视区域:能看到的元素的大小
clientWidth:可视区域的宽,没有边框,有padding
clientHeight:可视区域的高,没有边框,有padding
clientLeft:左边框的宽度
clientTop:上边框的宽度
因为padding也是内容的一部分,所以padding并不算在这个值里面
clientX,offsetX,layerX,pageX,screenX,X
https://www.cnblogs.com/xulei1992/p/5659923.html
先来个定义
screenX/Y:鼠标位置相对于屏幕的坐标
pageX/Y:鼠标位置相对于文档边缘的距离,当滚动条滚动时,对应的值会增加,可以理解为相对于文档的top和left,而不是相对于可是区域的top、left(IE8不支持)
clientX/Y:鼠标位置相对于文档边缘的距离,当公东条滚动时,对应的值不会增加
offsetX/Y:鼠标位置相对于当前元素(块或行内块)的距离,google浏览器的边缘包含border,IE浏览器的边缘不包含边框
啥意思呢?看图说话
google浏览器中,当鼠标放在border上时,offset的值是正的
在IE浏览器中,当鼠标放在border上时,offset的值是负的
X/Y:与clientX/Y相同,火狐浏览器不支持
layerX/Y:与pageX/Y相同(不包括IE浏览器),IE11浏览器中和clientX/Y相同(IE8不支持)
测试代码自存
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
.div {
text-align: center;
font-size: 24px;
height: 300px;
width: 1300px;
line-height: 300px;
color: yellow;
}
#d1 {
background-color: #FF3B2F;
}
#d2 {
background-color: #4CDA64;
}
#d3 {
background-color: #007AFF;
border: 50px solid #004400;
width: 500px;
display: inline-block;
}
#d3-2{
background-color: #FF2C55;
width: 500px;
border: 10px solid #019EE4;
display: inline-block;
}
#d4 {
position: fixed;
background-color: #FFCC00;
height: 340px;
width: 120px;
top: 0;
bottom: 0;
left: 50px;
margin: auto 0;
font-family: "arial";
font-size: 16px;
}
</style>
<script type="text/javascript">
$(function () {
document.onmousemove = function (e) {
if (e == null) {
e = window.event;
}
var html = "<span style='color:#000'>screenX:" + e.screenX + "</span><br/>";
html += "<span style='color:#000'>screenY:" + e.screenY + "</span><br/><br/>";
html += "<span style='color:#f00'>clientX:" + e.clientX + "</span><br/>";
html += "<span style='color:#f00'>clientY:" + e.clientY + "</span><br/><br/>";
html += "<span style='color:#f00'>x:" + e.x + "</span><br/>";
html += "<span style='color:#f00'>y:" + e.y + "</span><br/><br/>";
html += "<span style='color:#00f'>layerX:" + e.layerX + "</span><br/>";
html += "<span style='color:#00f'>layerY:" + e.layerY + "</span><br/><br/>";
html += "<span style='color:#00f'>pageX:" + e.pageX + "</span><br/>";
html += "<span style='color:#00f'>pageY:" + e.pageY + "</span><br/><br/>";
html += "<span style='color:#070'>offsetX:" + e.offsetX + "</span><br/>";
html += "<span style='color:#070'>offsetY:" + e.offsetY + "</span><br/>";
$("#d4").html(html);
};
});
</script>
</head>
<body>
<div id="d1" class="div">div1 height:300px width:1300px</div>
<div id="d2" class="div">div2 height:300px width:1300px</div>
<div id="d3" class="div">div3 height:300px width:500px</div>
<div id="d3-2" class="div">div3-2 height:300px width:500px <span style="width:50px;height:50px;background:#000;display: inline-block;border: 5px solid #fff;line-height: 45px;">dddd</span></div>
<div id="d4"></div>
</body>
</html>
通过document获取元素
获取body,得到的是一个标签
document.body
获取title,得到的是title文本
document.title
获取html
document.documentElement
获取元素的所有样式属性
window.getComputedStyle(my$('d1'),null)
这样就能获取到d1元素的所有样式,返回值是一个样式对象,通过.属性即可获得属性值(IE8不支持)
my$('d1').currentStyle
IE8支持
兼容性代码
//获取元素的所有样式属性
function getStyle (element,attr){
return window.getComputedStyle? window.getComputedStyle(element,null)[attr]:element.currentStyle[attr];
}
元素隐藏的不同方式
不占位:
display:none;