文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”,双方为了在JavaScript与JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上加入了不少专属事物,既有VBScript、ActiveX、以及微软自家的DHTML格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时蕴酿出来的杰作。
- 文档:一个网页可以称为文档
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等)
- 元素:网页中的标签
- 属性:标签的属性
DOM经常进行的操作
- 获取元素
- 动态创建元素
- 对元素进行操作(设置其属性或调用其方法)
- 事件(什么时机做相应的操作)
DOM又称为文档树模型
-
DOM的作用:操作页面的元素
-
DOM树:把html页面或者是xml文件看成是一个文档,文档就是一个对象,这个文档中所有的标签都是元素,元素也可以看成是对象,标签(元素,对象)有很多,还有嵌套的关系,组成的这种层次结构,可以模拟成树形结构图,简称:树状图,就是DOM树
- 页面就是文档–document,文档中有根元素:html
- html—>head
- ------>body—>其他的标签
那么首先来解释一下什么是API:
API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
- 任何开发语言都有自己的API
- API的特征输入和输出(I/O)
- API的使用方法(console.log())
Web API的概念:浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)
为什么要获取页面元素
例如:我们想要操作页面上的某部分(显示/隐藏,动画),需要先获取到该部分对应的元素,才进行后续操作
获取元素:
- 根据id从整个的文档中获取元素—返回的是一个元素对象
document.getElementById(“id属性的值”)
var div = document.getElementById('main');
console.log(div);
注意:由于id名具有唯一性,部分浏览器支持直接使用id名访问元素,但不是标准方式,不推荐使用。
- 根据标签的名字获取元素-----返回的是元素对象组成的伪数组
document.getElementsByTagName(“标签的名字”);
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
var div = divs[i];
console.log(div);
}
- 根据name属性的值获取元素,返回来的是一个伪数组,里面保存了多个的DOM对象
document.getElementsByName(“name属性的值”)
var inputs = document.getElementsByName('hobby');
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
console.log(input);
}
4.根据类样式的名字来获取元素,返回来的是一个伪数组,里面保存了多个的DOM对象
document.getElementsByClassName(“类样式的名字”)
var mains = document.getElementsByClassName('main');
for (var i = 0; i < mains.length; i++) {
var main = mains[i];
console.log(main);
}
- 根据选择器获取元素,返回来的是一个元素对象
document.querySelector(“选择器的名字”);
var text = document.querySelector('#text');
console.log(text);
6.根据选择器获取元素,返回来的是一个伪数组,里面保存了多个的DOM对象
document.querySelectorAll(“选择器的名字”)
var boxes = document.querySelectorAll('.box');
for (var i = 0; i < boxes.length; i++) {
var box = boxes[i];
console.log(box);
}
操作基本标签的属性
src,title,alt,href,id属性
操作表单标签的属性
name,value,type,checked,selected,disabled,readonly
元素的样式操作
对象.style.属性=值;
对象.className=值;
var link = document.getElementById('link');
console.log(link.href);
console.log(link.title);
var pic = document.getElementById('pic');
console.log(pic.src);
事件
事件:触发-响应机制
Event接口表示在DOM中发生的任何事件,一些是用户生成的(例如鼠标或键盘事件),而其他由API生成。
事件三要素
- 事件源:触发(被)事件的元素
- 事件类型:事件的触发方式(例如鼠标点击或键盘点击)
- 事件处理程序:事件触发后要执行的代码(函数形式)
事件的基本使用
var box = document.getElementById('box');
box.onclick = function() {
console.log('代码会在box被点击后执行');
};
为元素添加事件的操作
事件:就是一件事,有事件源,触发和响应
this关键字----如果是在当前的元素的事件中使用this,那么this就是当前的对象
- innerHTML和innerText的区别
- 如果使用innerText主要是设置文本的,设置标签内容,是没有标签的效果的 innerHTML是可以设置文本内容
- innerHTML主要的作用是在标签中设置新的html标签内容,是有标签效果的
- 想要设置标签内容,使用innerHTML,想要设置文本内容,innerText或者textContent,或者innerHTML,推荐用innerHTML
- 获取的时候:
innerText可以获取标签中间的文本内容,但是标签中如果还有标签,那么最里面的标签的文本内容也能获取.—获取不到标签的,文本可以获取
innerHTML才是真正的获取标签中间的所有内容
如果这个属性在浏览器中不支持,那么这个属性的类型是undefined 判断这个属性的类型
是不是undefined,就知道浏览器是否支持
- innerText的兼容性处理
//设置任意的标签中间的任意文本内容
function setInnerText(element,text) {
//判断浏览器是否支持这个属性
if(typeof element.textContent =="undefined"){//不支持
element.innerText=text;
}else{//支持这个属性
element.textContent=text;
}
}
//获取任意标签中间的文本内容
function getInnerText(element) {
if(typeof element.textContent=="undefined"){
return element.innerText;
}else{
return element.textContent;
}
}
自定义属性操作
- getAttribute(“属性的名字”) 获取标签行内属性
- setAttribute(“属性的名字”,“属性的值”); 设置标签行内属性
- removeAttribute(“属性的名字”) 移除标签行内属性
- 与element.属性的区别: 上述三个方法用于获取任意的行内属性。
样式操作
- 使用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';
表单元素属性
- value 用于大部分表单元素的内容获取(option除外)
- type 可以获取input标签的类型(输入框或复选框等)
- disabled 禁用属性
- checked 复选框选中属性
- selected 下拉菜单选中属性
节点操作
- 节点的属性:(可以使用标签–元素.出来,可以使用属性节点.出来,文本节点.点出来)
- nodeType:节点的类型:1----标签,2—属性,3—文本
- nodeName:节点的名字:标签节点—大写的标签名字,属性节点—小写的属性名字,文本节点----#text
- nodeValue:节点的值:标签节点—null,属性节点—属性值,文本节点—文本内容
节点层级
节点操作,方法
appendChild()
insertBefore()
removeChild()
replaceChild()
节点层次,属性
parentNode
childNodes
children
nextSibling/previousSibling
firstChild/lastChild
var box = document.getElementById('box');
//父级节点
console.log(box .parentNode);
//父级元素
console.log(box .parentElement);
//子节点
console.log(box .childNodes);
//子元素
console.log(box .children);
console.log("==============================================");
//第一个子节点
console.log(box .firstChild);//---------------------IE8中是第一个子元素
//第一个子元素
console.log(box .firstElementChild);//--------------IE8中不支持
//最后一个子节点
console.log(box .lastChild);//---------------------IE8中是第一个子元素
//最后一个子元素
console.log(box .lastElementChild);//--------------IE8中不支持
//某个元素的前一个兄弟节点
console.log(my$("three").previousSibling);
//某个元素的前一个兄弟元素
console.log(my$("three").previousElementSibling);
//某个元素的后一个兄弟节点
console.log(my$("three").nextSibling);
//某个元素的后一个兄弟元素
console.log(my$("three").nextElementSibling);
-
注意
childNodes和children的区别,childNodes获取的是子节点,children获取的是子元素
nextSibling和previousSibling获取的是节点,获取元素对应的属性是nextElementSibling和previousElementSibling获取的是元素
nextElementSibling和previousElementSibling有兼容性问题,IE9以后才支持
-
总结
凡是获取节点的代码在谷歌和火狐得到的都是 相关的节点
凡是获取元素的代码在谷歌和火狐得到的都是 相关的元素
从子节点和兄弟节点开始,凡是获取节点的代码在IE8中得到的是元素,获取元素的相关代码,在IE8中得到的是undefined----元素的代码,iE中不支持
节点兼容代码
//第一个节点和第一个元素的获取的代码在IE8中可能不支持
//element.firstChild--->谷歌和火狐获取的是第一个子几点
//element.firstChile--->IE8获取的是第一个子元素
//element.firstElementChild------>谷歌和火狐是第一个子元素,IE8不支持
//获取任意一个父级元素的第一个子级元素
function getFirstElementChild(element) {
if(element.firstElementChild){//true--->支持
return element.firstElementChild;
}else{
var node=element.firstChild;//第一个节点
while (node&&node.nodeType!=1){
node=node.nextSibling;
}
return node;
}
}
//最后一个节点和最后一个元素的获取的代码在IE8中可能不支持
//前一个节点和前一个元素的获取的代码在IE8中可能不支持
//后一个节点和后一个元素的获取的代码在IE8中可能不支持
//获取任意一个父级元素的最后一个子级元素
function getLastElementChild(element) {
if(element.lastElementChild){//true--->支持
return element.lastElementChild;
}else{
var node=element.lastChild;//第一个节点
while (node&&node.nodeType!=1){
node=node.previousSibling;
}
return node;
}
}
创建元素的三种方式
document.write()
document.write('新设置的内容<p>标签也可以生成</p>');
//创建元素,缺陷:如果是在页面加载完毕后,此时通过这种方式创建元素,
//那么页面上存在的所有的内容全部被干掉
innerHTML
var box = document.getElementById('box');
box.innerHTML = '新内容<p>新标签</p>';
document.createElement()
var div = document.createElement('div');
document.body.appendChild(div);//把创建后的子元素追加到父级元素中
相关元素方法
document.getElementById("dv").appendChild(obj);//追加子元素
//把新的子元素插入到第一个子元素的前面
document.getElementById("dv").insertBefore(obj,my$("dv").firstElementChild);
//my$("dv").replaceChild();---自己玩
//移除父级元素中第一个子级元素
document.getElementById("dv").removeChild(my$("dv").firstElementChild);
//点击按钮删除div中所有的子级元素
//判断父级元素中有没有第一个子元素
document.getElementById("dv").removeChild(my$("dv").firstElementChild);
兼容代码
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;
}
}
性能问题
- innerHTML方法由于会对字符串进行解析,需要避免在循环内多次使用。
- 可以借助字符串或数组的方式进行替换,再设置给innerHTML
- 优化后与document.createElement性能相近
为元素绑定事件(DOM):一种,但是不兼容,有两种
1 对象.addEventListener(“事件类型”,事件处理函数,false);–谷歌和火狐支持,IE8不支持
2 对象.attachEvent(“有on的事件类型”,事件处理函数)–谷歌不支持,火狐不支持,IE8支持
事件的绑定:为同一个元素绑定多个相同的事件
三种方式:
- 对象.on事件名字=事件处理函数 如果是多个相同事件注册用这种方式,最后一个执行,之前的被覆盖了
my$(“btn”).οnclick=function(){};- 对象.addEventListener(“没有on的事件名字”,事件处理函数,false);
my$(“btn”).addEventListener(“click”,function(){},false);- 对象.attachEvent(“有on的事件名字”,事件处理函数);
my$(“btn”).attachEvent(“onclick”,function(){});
兼容代码
//为任意元素.绑定任意的事件, 任意的元素,事件的类型,事件处理函数
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;
}
}
注册/移除事件的三种方式
var box = document.getElementById('box');
box.onclick = function () {
console.log('点击后执行');
};
box.onclick = null;
box.addEventListener('click', eventCode, false);
box.removeEventListener('click', eventCode, false);
box.attachEvent('onclick', eventCode);
box.detachEvent('onclick', eventCode);
function eventCode() {
console.log('点击后执行');
}
总结绑定事件的区别:
- 相同点: 都可以为元素绑定事件
- 不同点:
1.方法名不一样- 2.参数个数不一样addEventListener三个参数,attachEvent两个参数
- 3.addEventListener 谷歌,火狐,IE11支持,IE8不支持 * attachEvent 谷歌火狐不支持,IE11不支持,IE8支持
- 4.this不同,addEventListener 中的this是当前绑定事件的对象
- attachEvent中的this是window
- 5.addEventListener中事件的类型(事件的名字)没有on * attachEvent中的事件的类型(事件的名字)有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;
}
}
解绑事件:
/*
* 注意:用什么方式绑定事件,就应该用对应的方式解绑事件
* 1.解绑事件
* 对象.on事件名字=事件处理函数--->绑定事件
* 对象.on事件名字=null;
* 2.解绑事件
* 对象.addEventListener("没有on的事件类型",命名函数,false);---绑定事件
* 对象.removeEventListener("没有on的事件类型",函数名字,false);
* 3.解绑事件
* 对象.attachEvent("on事件类型",命名函数);---绑定事件
* 对象.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.事件捕获阶段 :从外向内
2.事件目标阶段 :最开始选择的那个
3.事件冒泡阶段 : 从里向外
为元素绑定事件
- addEventListener(“没有on的事件类型”,事件处理函数,控制事件阶段的)
- 事件触发的过程中,可能会出现事件冒泡的效果,为了阻止事件冒泡—>
- window.event.cancelBubble=true;谷歌,IE8支持,火狐不支持
- window.event就是一个对象,是IE中的标准
- e.stopPropagation();阻止事件冒泡---->谷歌和火狐支持
- window.event和e都是事件参数对象,一个是IE的标准,一个是火狐的标准
- 事件参数e在IE8的浏览器中是不存在,此时用window.event来代替
- addEventListener中第三个参数是控制事件阶段的
- 事件的阶段有三个:
- 通过e.eventPhase这个属性可以知道当前的事件是什么阶段你的
- 如果这个属性的值是:
- 1---->捕获阶段
- 2---->目标阶段
- 3---->冒泡
- 一般默认都是冒泡阶段,很少用捕获阶段
- 冒泡阶段:从里向外
- 捕获阶段:从外向内
阻止事件传播的方式
- 标准方式 event.stopPropagation();
- IE低版本 event.cancelBubble = true; 标准中已废弃
事件对象的属性和方法
- event.type 获取事件类型
- clientX/clientY 所有浏览器都支持,窗口位置
- pageX/pageY IE8以前不支持,页面位置
- event.target || event.srcElement 用于获取触发事件的元素
- event.preventDefault() 取消默认行为
偏移量
- offsetParent用于获取定位的父级元素
- offsetParent和parentNode的区别
var box = document.getElementById('box');
console.log(box.offsetParent);
console.log(box.offsetLeft);
console.log(box.offsetTop);
console.log(box.offsetWidth);
console.log(box.offsetHeight);
客户区大小
var box = document.getElementById('box');
console.log(box.clientLeft);
console.log(box.clientTop);
console.log(box.clientWidth);
console.log(box.clientHeight);
滚动偏移
var box = document.getElementById('box');
console.log(box.scrollLeft)
console.log(box.scrollTop)
console.log(box.scrollWidth)
console.log(box.scrollHeight)
定时器
1.setInterval
用法:里面有个函数,函数后面加一个时间,每隔多长时间执行一次函数。
可以用作定时器,是全局里的方法,即使不window执行时也会上GO中找。
每次执行都会返回一个数字作为它的唯一标识,如果有两个setInterval的话,第一个就返回1,第二个就返回2等等等作为它的唯一标识。
var timeId = setInterval(function () {
alert("hello");//断言
}, 1000);
document.getElementById("btn").onclick = function () {
//点击按钮,停止定时器
//参数:要清理的定时的id的值
window.clearInterval(timeId);
};
另一种形式(很少很少用):setInterval(“console.log(‘a’)”,1000);,每隔1000毫秒执行一次字符串里的代码
//页面加载后
window.onload=function () {
//一次性的定时器
var timeId=window.setTimeout(function () {
alert("您好");
},1000);
//点击这个按钮,停止这个一次性的定时器
document.getElementById("btn").onclick=function () {
clearTimeout(timeId);
};
};