文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”,双方为了在JavaScript与JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上加入了不少专属事物,既有VBScript、ActiveX、以及微软自家的DHTML格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时蕴酿出来的杰作。
初识DOM
介绍
JS三部分:
- ECMAScript标准:JS的基本语法。
- DOM(Document Object Model):文档对象模型,操作页面的元素。
- BOM(Browser Object Model):浏览器对象模型,操作浏览器。
元素
- 文档:把一个html文件看成是一个文档,由于万物皆对象,所以把这个文档看成是一个对象。
- html:展示信息和数据。
- xml:侧重于存储数据。
- html文件都看成是一个文档,那么这个文档看成是一个对象,文档中所有标签都看成对象。
- 页面中每个标签,都是一个元素(element),每个元素都看成一个对象。
- 标签可以嵌套,标签中有标签,元素中有元素。
文档: 一个页面。
- 元素(element):页面中所有标签都是元素,元素可以看作对象。
- 节点(node):页面中所有内容都是节点,标签、属性、文本。节点范围比元素大。
- 根(root):根基元素。
DOM树:由文档及文档中所有元素(标签)组成的一个树形结构图
DOM的几种写法
-
在标签中写:
<a onclick="alert('哈哈')">点我</a>
-
在script标签写:
<a onclick="func()">点我</a> <script> function func(){ alert('呵呵'); } </script>
-
开始分离js和html代码:
<a id='a1'></a>
,再利用findElementById写js -
单独写一个JS文件
-
最好的方法:
<script> document.getElementById('btn1').onclick = function() { alert('哈哈'); }; </script>
注意
- 写事件应该有顺序,先有按钮、再获取,最后注册事件。比如弹窗脚本必须写在btn下面。
- 修改自己的属性:不需要obj.属性=…只需要this.属性=…
- for循环是在页面加载的时候执行完毕,而事件是在触发的时候执行。
- 在表单标签中,如果属性的值就是他本身,如"checked=checked",那么在写js代码只需要写boolean类型就可,注意布尔值不要有引号!
- 凡是css中属性是多个单词的,再JS代码DOM操作时,把’-'干掉,然后把后面的单词首字母大写即可。
- JS代码DOM操作的时候,设置类样式不用关键字
class
,而className
- 谁的点击事件,this就指向谁。
- 阻止超链接跳转:
<a id='a' href='www.bjtu.edu.cn'>北京交通大学</a> <script> // 阻止超链接跳转 document.getElementById('a').onclick = function() { // 法1 return false; // 法2 e.preventDefault(); }; </script>
- 如果设置
ele.style.backgroundColor='';
,是将属性恢复到默认的样式而不是去除。 - 如果是循环添加事件,应该用命名函数;否则用匿名函数。
- 如果样式代码写在style标签内部,JS是获取不到的,所以必须设置在目标标签style属性中。但是如果这两种情况都想获取,应该.offsetLeft获取4个方向的距离。
API
属性
获取属性值,只需要
obj.属性
即可。
obj.innerText=''
:凡是双标签,修改文本内容都用它。obj.textContent
:设置标签中的文本内容。IE8不支持。obj.innerHTML
:可设置html文本。以上两个仅支持纯文本。- 注意:
innerText
可获取标签中间文本内容,但标签中还嵌套标签,那么里面标签的文本也会获取。但是获取不到标签,只能获取文本。innerHTML
可获取标签中的【所有】内容。
方法
主要是获取元素的
- 根据id:
document.getElementById(id);
- 根据标签名:
document.getElementsByTagName(tag);
- 根据class:
document.getElementsByClassName(className);
属于h5的,不支持低版本IE。 - 根据name:
document.getElementsByName(name);
只在表单标签中有用。 - 根据css选择器:
document.querySelector(sel);
或querySelectorAll(sel);
兼容代码
-
概述: 如果某属性在浏览器中不支持,那么它的类型是undefined。所以,可以通过判断是否是undefined判断兼容性。
-
设置任意标签中间任意文本内容:
function setInnerText(ele,text){ if(typeof ele.textContent == 'undefined'){ //不兼容 ele.innerText = text; // inner就是值 }else{ ele.textContent = text; // 值就是content } }
-
获取任意标签中间的文本内容
function getInnerText(ele){ if(typeof ele.textContent == 'undefined'){ return ele.innerText; }else{ return ele.textContent; } }
自定义属性
- 设置:
0. 直接在html标签中添加属性,如添加成绩<li score="98"></li>
setAttribute('属性名',属性值)
;
- 获取:不能通过this.属性名,而是使用
getAttribute('属性名')
获取。 - 移除:
removeAttribute('属性名')
,它也可以移除自带的属性
节点node
节点概念
- [类型]nodeType:1->标签; 2->属性; 3->文本。
- [名称]nodeName:标签->大写标签名; 属性->小写属性名; 文本->#text。
- [值]nodeValue:标签->null; 属性->属性值; 文本->文本内容。
- 注意:
- 范围:【节点>元素】。
- 所有html的根节点是document,它的父节点是null。
获取节点
- 方法:
parentNode
:父节点parentElement
:父元素,和父节点一样。childNodes
:子节点。范围比子元素大。children
:子元素。和子节点不相等,一般children<childNodes,因为后者包含空白文本。getAttributeNode('id')
:获取属性节点。基本不用。firstChild
:第一个子节点。firstElementChild
:第一个子元素。lastChild
:最后一个子节点。lastElementChild
:最后一个子元素。previousSibling
:某一元素的前一个兄弟节点:previousElementSibling
:某一元素的前一个兄弟元素。nextSibling
:某一元素的后一个兄弟节点。nextElementSibling
:某一元素的后一个兄弟元素。
注意:从(5)往下,谷歌火狐都正常,而IE8节点->元素,元素->不支持。
获取节点信息
parentNode.nodeType
:获取节点类型parentNode.nodeName
:获取节点名。parentNode.nodeValue
:获取节点值。
遍历子节点
for(var i=; i<dvs.childNodes.length; i++){
var node = dvs.childNodes[i];
console.log(node.nodeType,node.nodeName,node.nodeValue);
}
创建和追加节点
创建元素的3种方式
document.write('代码')
:有缺陷,如果在页面加载【完成后】,此时创建的话页面原有的元素都会被干掉。但加载页面时不受影响。obj.innerHTML='代码';
document.createElement('标签名')
:这种方法只能创建一个对象,需要把对象追加到父级元素: 如:var obj = document.createElement('p'); setInnerText(obj,'这时一个p'); my$('dv').appendChild(obj); // 【追加】到父级元素
性能问题
innerHTML
方法由于会对字符串进行解析,需要避免在循环内多次使用。- 可以借助字符串或数组的方式进行替换,再设置给
innerHTML
- 优化后与
document.createElement
性能相近
CRUD追加节点
appendChild(obj)
:追加子元素。insertBefore(obj, pos)
:在位置pos处插入元素obj。replaceChild()
:替换子元素。removeChild(oldObj)
:移除某一个元素。
节点操作
属性操作
非表单元素属性
- href、title、id、src、className
var link = document.getElementById('link');
console.log(link.href);
console.log(link.title);
var pic = document.getElementById('pic');
console.log(pic.src);
- innerHTML和innerText
var box = document.getElementById('box');
box.innerHTML = '我是文本<p>我会生成为标签</p>';
console.log(box.innerHTML);
box.innerText = '我是文本<p>我不会生成为标签</p>';
console.log(box.innerText);
- HTML转义符
" "
‘ '
& &
< < //less than 小于
> > // greater than 大于
空格
© ©
表单元素属性
value
:用于大部分表单元素的内容获取(option除外)type
:可以获取input标签的类型(输入框或复选框等)disabled
:禁用属性checked
:复选框选中属性selected
:下拉菜单选中属性
样式操作
使用style
方式设置的样式显示在标签行内
var box = document.getElementById('box');
box.style.width = '100px';
box.style.height = '100px';
box.style.backgroundColor = 'red';
注意:通过样式属性设置宽高、位置的属性类型是字符串,需要加上px
类名操作
修改标签的className
属性相当于直接修改标签的类名
var box = document.getElementById('box');
box.className = 'clearfix';
操作document属性
通过document直接获取元素:
document.body
:获取或修改body元素document.title
:获取或修改title网页标题document.documentElement
:获取html代码
事件
事件类型
API | 事件类型 |
---|---|
onload | 页面加载完成 |
onscroll | 鼠标滚轮滚动 |
onclick | 鼠标点击 |
ondblclick | 鼠标双击 |
onmousedown | 鼠标按钮按下 |
onmouseup | 鼠标按键抬起 |
onmouseover | 鼠标进入 |
onmouseout | 鼠标离开 |
onmousemove | 鼠标移动 |
onkeydown | 键盘按键按下,通过e.keyCode 获取键码 |
onkeyup | 键盘按键抬起 |
onkeypress | 键盘按键按下后抬起 |
onfocus | (输入框)获取焦点 |
onblur | (输入框)失去焦点 |
onchange | (文本框)内容被改变 |
onpropertychange | 文本内容实时改变(IE专有) |
onselect | 文本被选中 |
onsubmit | 表单提交 |
onreset | 表单重置 |
事件绑定的3种方式
语法:
对象.on事件名 = 函数
: 如果多个相同的事件注册用这种方式,最后一个把前边的覆盖。对象.addEventListener('无on的事件名',函数,false)
: 谷歌火狐IE11支持,IE8不支持对象.attachEvent('带on的事件名', 函数)
:谷歌火狐IE11不支持,IE8支持
区别:
- addEventListener中的
this
是当前绑定的对象 - attachEvent中的
this
是window
- 方法名、参数个数、
attachEvent
有'on'
前缀
事件解绑
语法:
my('btn').onXxx = null;
:让该元素的事件指向null即可。my('btn').removeEventListener('Xxx',funcName,false);
:谷歌火狐IE11支持,IE8不支持。dom.detachEvent('onXxx', funcName)
:谷歌火狐IE11不支持,IE8支持。
注意:
- 使用何种方式绑定事件,就应该使用对应的方式解绑事件。
- 使用
removeEventListener
时函数必须是命名函数。
事件冒泡
概念:多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面元素触发了,外边的元素自动触发了。
阻止:
window.event.cancelBubble = true
: 谷歌IE支持,火狐不支持。e.stopPropageation()
:谷歌火狐支持,IE不支持。
注意:window.event = 参数e
,都是事件参数对象,只不过前者是IE标准,后者是火狐标准,e
在IE中不存在。
事件阶段
3个阶段:可以通过e.eventPhase
查看当前处于哪个阶段
- 事件捕获阶段:1,true,外->里;
- 事件目标阶段:2,开始选择的事件。
- 事件冒泡阶段:3,false,里->外;
注意:
- 控制捕获和冒泡阶段:
addEventListener
那个boolean参数。 - 一般默认都是冒泡阶段(false),很少用捕获阶段。
兼容代码
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;
}
}
function removeEventListener(element, type, fn) {
if (element.removeEventListener) {
element.removeEventListener(type, fn, false);
} else if (element.detachEvent) {
element.detachEvent('on' + type, fn);
} else {
element['on'+type] = null;
}
}
事件对象e
event.type
:获取事件类型clientX/clientY
:所有浏览器都支持,窗口位置pageX/pageY
:IE8以前不支持,页面位置event.target || event.srcElement
:用于获取触发事件的元素event.preventDefault()
:取消默认行为