DOM
一、DOM及节点
1.DOM简述
JavaScript分为三个部分,ECMAScript,DOM(页面文档对象模型)和BOM(浏览器对象模型)。
DOM是JS操作网页的接口,全称为“文档对象模型”(Document Object Model。通过 HTML DOM,JavaScript 能够访问和改变 HTML 文档的所有元素。
2.节点
网页中的所有内容都是节点(例如注释、标签、文本等),是DOM的最小组成单位。任何 HTML 或 XML 文档都可以用 DOM 表示为一个由节点构成的层级结构。节点分很多类型,每种类型对应着文档中不同的信息或标记,也都有自己不同的特性、数据和方法,而且与其他类型有某种关系。
2.1节点类型
1.文档节点(document)
整个HTML文档document对象作为window对象的属性存在的,我们不用获取可以直接使用。
2.元素节点(Element)
HTML文档中的HTML标签就是元素节点。
3.属性节点(Attribute)
元素的属性表示的是标签中的一个一个的属性,这里要注意的是属性节点并非是元素节点的子节点,而是元素节点的一部分。
4.文本节点(Text)
HTML标签中的文本内容。
5.DocumentType(doctype标签)
6.Comment(注释)
7.DocumentFragment(文档片段)*
2.2节点层级
<html>
<head>
<title>Example1</title>
</head>
<body>
<p>Hello world!</p>
<a href="www.nenu.edu.cn">东北师范大学</a>
</body>
</html>
document 节点表示每个文档的根节点,根节点的唯一子节点是html元素(也是根元素),我们称之为文档元素(documentElement)。HTML 中的每段标记都可以表示为这个树形结构中的一个节点。元素节点表示 HTML 元素,例如head元素,body元素,属性节点表示属性,例如上元素面a后面的href,文档类型节点表示文档类型,注释节点表示注释。DOM 中总共有12种节点类型,这些类型都继承一种基本类型。
2.3节点树
一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是DOM。
最顶层的节点就是document节点,它代表了整个文档。一般根节点只有一个子节点html元素,该html元素成为根节点,其他html标签都是它的下级。
节点之间存在三种关系:
父节点关系(parentNode):直接的那个上级节点。
子节点关系(childNode):直接的下级节点。
同级节点关系(sibling):拥有同一父节点的节点
二、DOM应用
1.Document类型
1.1查找html元素
项目 | 描述 |
---|---|
document.getElementById(id) | 通过元素 id 来查找元素 |
document.getElementsByTagName(name) | 通过标签名来查找元素 |
document.getElementsByClassName(name) | 通过类名来查找元素 |
document.querySelector() | 返回文档中匹配指定的CSS选择器的第一元素 |
document.querySelectorAll() | 返回文档中匹配的CSS选择器的所有元素节点列表 |
1.getElementById() 返回匹配指定 id 的一个元素
<div id="one">我是一个div标签</div>
<script>
var div = document.getElementById('one'); // 查找id为one的标签
console.log(div);
</script>
2.getElementsByTagName()
返回一个HTMLCollection(伪数组),包含匹配指定标签名的所有元素。
<p>我是第一个p标签</p>
<p>我是第二个p标签</p>
<p>我是第三个p标签</p>
<script>
var p = document.getElementsByTagName('p'); // 查找所有p标签
console.log(p); //
</script>
3.getElementsByClassName()
返回一个HTML集合HTMLCollection(伪数组),包含匹配指定类名的所有元素。
<div class="one">我是div标签</div>
<div class="one">我是div标签</div>
<div class="one">我是div标签</div>
<script>
var div = document.getElementsByClassName('one'); // 查找class为one的标签
console.log(div);
</script>
4.document.querySelector()
返回文档中匹配指定的CSS选择器的第一元素
<div id="div1">111</div>
<div id="div1">222</div>
<script>
document.querySelector("#div1").innerHTML = "Hello World";
//将第一个id="div1"的区域内容改为Hello world
</script>
5.document.querySelectorAll()
查找匹配指定 CSS 选择器(id、类名、类型、属性、属性值等等)的所有 HTML 元素
<p>段落1</p>
<p class="one">段落22</p>
<p class="one">段落33</p>
<p id="demo"></p>
<script>
var x = document.querySelectorAll("p.one");
document.getElementById("demo").innerHTML = x[1].innerHTML;
//返回了class="one"的第二个索引,id="demo"的段落内容变为 段落33
</script>
1.2操作html元素
改变html元素:
项目 | 描述 |
---|---|
element.innerHTML = new html content | 改变元素的 inner HTML |
element.attribute = new value | 改变 HTML 元素的属性值 |
element.setAttribute(attribute, value) | 改变HTML 元素的属性值 |
element.style.property = new style | 改变 HTML 元素的样式 |
<p id="p1">段落1</p>
<p id="p2">段落2</p>
<script>
document.getElementById("p2").innerHTML = "段落已被改变";//段落内容已改为段落已被改变
document.getElementById("p2").style.color = "blue";//第二个段落的样式已被修改,颜色变为蓝色
var x = document.querySelector('#p2');
x.id='p3'; //将x的id属性改为p3
//或者也可以写成x.setAttribute('id', 'p3')
document.getElementById("p3").innerHTML ="段落再次被改变"
</script>
2.Node类型
DOM Level 1 描述了名为 Node 的接口,这个接口是所有 DOM 节点类型都必须实现的。Node 接口在 JavaScript中被实现为 Node 类型,在除 IE之外的所有浏览器中都可以直接访问这个类型。在 JavaScript中,所有节点类型都继承 Node 类型,因此所有类型都共享相同的基本属性和方法。
2.1属性
1.nodeType
nodeType属性返回一个整数值,表示节点的类型。
节点类型 | 值 | 对应常量 |
---|---|---|
文档节点(document) | 9 | Node.DOCUMENT_NODE |
元素节点(element) | 1 | Node.ELEMENT_NODE |
属性节点(attr) | 2 | Node.ATTRIBUTE_NODE |
文本节点(text) | 3 | Node.TEXT_NODE |
文档类型节点(DocumentType) | 10 | Node.DOCUMENT_TYPE_NODE |
注释节点(Comment) | 8 | Node.COMMENT_NODE |
文档片断节点(DocumentFragment) | 11 | Node.DOCUMENT_FRAGMENT_NODE |
<script>
console.log(element.nodeType); //输出1
</script>
2.nodeName
nodeName属性返回节点的名称(大写的元素名)。
<p id="one">123456</p>
<script>
var abc = document.getElementById('one');
console.log(abc.nodeName); //输出P
</script>
3.nodeValue
nodeValue属性返回一个字符串,表示当前节点本身的文本值。nodeValue只能获得文本节点的值,不能获得元素节点的值。
<div id="d1">hello world</div>
<script>
var div = document.getElementById('d1');
console.log(div.nodeValue); // null,因为div是一个元素节点
console.log(div.firstChild.nodeValue); //hello world,div的第一个子节点才是文本节点
</script>
4.textContent
textContent属性返回当前节点和它的所有后代节点的文本内容
<div id="one">Hello World!
<P>Hello DOM!</P>
</div>
<script>
var x = document.getElementById('one');
console.log(x.textContent); //Hello World! Hello DOM!
</script>
5.nextSibling
nextSibling属性返回紧跟在当前节点后面的第一个同级节点。如果当前节点后面没有同级节点,则返回null
注意可能会识别到“空格”或“回车”这样的文本节点
<div id="d1">hello</div><div id="d2">world</div> //两个div之间不能换行
<script>
var div1 = document.getElementById('d1');
var div2 = document.getElementById('d2');
console.log(div1.nextSibling); //输出<div id="d2">world</div>
</script>
6.previousSibling
previousSibling属性返回当前节点前面的、距离最近的一个同级节点。如果当前节点前面没有同级节点,则返回null(同上,也可能会识别空格或回车)。
<div id="d1">111</div><div id="d2">222</div>
<script>
var div1 = document.getElementById('d1');
var div2 = document.getElementById('d2');
console.log(div2.previousSibling); //<div id="d1">hello</div>
</script>
7.parentNode
parentNode属性返回当前节点的父节点。对于一个节点来说,它的父节点只可能是三种类型:元素节点(element)、文档节点(document)和文档片段节点(documentfragment)
<div id="d1"><div id="d2"></div></div>
<script>
var div1 = document.getElementById('d1');
var div2 = document.getElementById('d2');
console.log(div1.parentNode); // body
console.log(div2.parentNode); // <div id="d1"></div>
</script>
8.parentElement
parentElement属性返回当前节点的父元素节点。如果当前节点没有父节点,或者父节点类型不是元素节点,则返回null
与parentNode的区别:
在获取根部document节点时,parentElement找的是元素,因此返回null,而parentNode获取的是节点,返回的是#document。
<div id="d1"></div>
<script>
var div1 = document.getElementById('d1');
console.log(div1.parentElement); // body
console.log(div1.parentElement.parentElement); //html
console.log(div1.parentElement.parentElement.parentElement); //null
console.log(div1.parentNode.parentNode.parentNode); //#document
</script>
.9.firstChild和lastChild
firstChild属性返回当前节点的第一个子节点,如果当前节点没有子节点,则返回null,last则返回最后一个子节点。
<div id="d1">我是父节点<div>我是子节点</div></div>
<div id="d2"></div>
<script>
var div1 = document.getElementById('d1');
console.log(div1.firstChild); //输出"我是父节点",因为文本内容属于文本节点
console.log(div1.lastChild); // <div>我是子节点</div>
var div2 = document.getElementById('d2');
console.log(div2.firstChild); // null
</script>
10.childNodes
childNodes属性返回一个类似数组的对象(NodeList集合),成员包括当前节点的所有子节点
<div id="d1">Hello DOM<div>我是子节点</div><p>我也是子节点</p></div>
<script>
var div1 = document.getElementById('d1');
console.log(div1.childNodes);
</script>
输出结果为:
2.2方法
1.appendChild
appendChild方法接受一个节点对象作为参数,将其作为最后一个子节点,插入当前节点。该方法的返回值就是插入文档的子节点。
<div id="d1"><p>段落1</p><p>段落2</p></div>
<button onclick="myFunction()">点我</button>
<script>
function myFunction(){
var node=document.createElement("p");
node.innerHTML = '段落3';
document.getElementById("d1").appendChild(node);
}//按下按钮后,div最后多出一个段落3
</script>
2.insertBefore()
insertBefore方法用于将某个节点插入父节点内部的指定位置。
parentNode.insertBefore(newNode, referenceNode),该方法接受两个参数,第一个参数是所要插入的节点newNode,第二个参数是父节点parentNode内部的一个子节点referenceNode。newNode将插在referenceNode这个子节点的前面。返回值是插入的新节点newNode。
<ul>
<li>ECMAScript</li>
<li>DOM</li>
<li>BOM</li>
</ul>
<script>
var x = document.querySelector('ul');
var y = document.createElement("li");
y.innerHTML = 'JS';
x.insertBefore(y,x.children[0]);//将js插入到第一个子节点前面,使得js成为第一个子节点
</script>
3.removeChild()
removeChild方法接受一个子节点作为参数,用于从当前节点移除该子节点。返回值是移除的子节点。
<ul>
<li>ECMAScript</li>
<li>DOM</li>
<li>BOM</li>
</ul>
<script>
var x = document.querySelector('ul');
x.removeChild(x.children[2]); //ul的第三个li被删除
</script>
4.replaceChild()
replaceChild方法用于将一个新的节点,替换当前节点的某一个子节点。
parentNode.replaceChild(newChild, oldChild),replaceChild方法接受两个参数,第一个参数newChild是用来替换的新节点,第二个参数oldChild是将要替换走的子节点。返回值是替换走的那个节点oldChild。
<ul>
<li>ECMAScript</li>
<li>DOM</li>
<li>BOM</li>
</ul>
<script>
var x = document.querySelector('ul');
var y = document.createElement("p");
y.innerHTML = 'JS';
x.replaceChild(y,x.children[2]);//ul里第三个li的内容变成了"JS"
</script>
5.node.cloneNode()
返回调用该方法的节点的一个副本,如果括号参数为空或false,则只克隆复制节点本身,不克隆里面的内容;如果括号参数为true,则克隆复制节点本身及里面内容。
<ul>
<li>ECMAScript</li>
<li>DOM</li>
<li>BOM</li>
</ul>
<script>
var x = document.querySelector('ul');
var y =x.children[0].cloneNode(true);
x.appendChild(y);
//x的第一个子元素被复制,并插入到x的最后,成为x的第四个元素
</script>
3.事件
3.1概述
JavaScript使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
事件三要素:
- 事件源:触发事件的元素
- 事件类型: 例如 click 点击事件
- 事件处理程序:事件触发后要执行的代码(函数形式),事件处理函数
<button id="but1">按我</button>
<script>
var btn = document.getElementById('btn'); //btn为事件源
btn.onclick = function(){ //onclick为事件类型
alert('按钮已被按下'); //alert为事件处理程序
}
</script>
3.2常见事件
常见的鼠标事件:
- 1.onclick 鼠标点击左键触发
- 2.onmouseover 鼠标经过触发
- 3.onmouseout 鼠标离开触发
- 4.onfocus 获取鼠标焦点触发
- 5.onblur 失去鼠标焦点触发
- 6.onmousemove 鼠标移动触发
- 7.onmouseup 鼠标弹起触发
- 8.onmousedown 鼠标按下触发
常用的键盘事件:
- 1.onkeyup 某个键盘按键被松开时触发
- 2.onkeydown 某个键盘按键被按下时触发
- 3.onkeypress 某个键盘按键被按下时触发,但是它不识别功能键,比如ctrl、shift箭头等。
3.3注册事件
给元素添加事件,称为注册事件/绑定事件。注册事件有两种方式:传统方式和方法监听注册方式。
3.3.1传统注册方式
利用 on 开头的事件
DOM 0级事件绑定方式—— 因为 W3C 在确定 DOM 版本时,在之前已经有了事实上存在的一些事件,比如 onclick 这种直接绑定给元素的属性的事件,DOM1 中用的还是之前的事件,所以是 DOM 0级事件,而不是1级事件
<button oncilck = "alert(1)"></button>
btn.onclick = function () {
}
特点:注册事件的唯一性(同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数)
3.3.2 方法监听注册方式
方法:addEventListener()
特点:同一个元素可以多次绑定事件监听,同一个事件类型可以注册多个事件函数
语法:element.addEventListener(event, function, useCapture)
第一个参数是事件的类型(比如 “click” 或 “mousedown”)。第二个参数是当事件发生时我们需要调用的函数。第三个参数是布尔值,指定使用事件冒泡还是事件捕获。此参数是可选的。
注意:请勿对事件使用 “on” 前缀;请使用 “click” 代替 “onclick”。
下面的程序中,按下按钮将会弹出"Hello world"
<button id="myBtn">按我</button>
<script>
document.getElementById("myBtn").addEventListener("click", function() {
alert("Hello World!");
});
</script>
向相同元素添加多个事件处理程序:addEventListener()方法允许向相同元素添加多个事件,同时不覆盖已有事件:
<button id="myBtn">点击</button>
<script>
var x = document.getElementById("myBtn");
x.addEventListener("click", myFunction);
x.addEventListener("click", OtherFunction);
function myFunction() {
alert ("此函数被执行了!");
}
function OtherFunction() {
alert ("此函数也被执行了!");
}
</script>
也能够向相同元素添加不同类型的事件:
<button id="myBtn">点击</button>
<p id="demo"></p>
<script>
var x = document.getElementById("myBtn");
x.addEventListener("mouseover", myFunction);
x.addEventListener("click", mySecondFunction);
x.addEventListener("mouseout", myThirdFunction);
function myFunction() {
document.getElementById("demo").innerHTML += "Moused over!<br>";
}
function mySecondFunction() {
document.getElementById("demo").innerHTML += "Clicked!<br>";
}
function myThirdFunction() {
document.getElementById("demo").innerHTML += "Moused out!<br>";
}
</script>
3.4删除(解绑)事件
3.4.1传统注册方式
eventTarget.onclick = null
var btn = document.getElementById("btn");
btn.onclick = function () {
alert(1);
};
btn.onclick = null;// 解除绑定方法
3.4.2方法监听注册方式
element.removeEventListener() 方法,含有两个参数,第一个参数是事件类型的字符串(直接书写” click” ,不需要加 on),第二个参数为事件函数名字。
var btn = document.getElementById("btn");
btn.addEventListener("click", fun);
function fun() {
alert(1);
btn.removeEventListener("click", fun);
}// 点击按钮,只弹出一次1,点第二次不再弹出
三、总结
上节课我们学习了JavaScript的基础,包括JavaScript基础语法,变量类型,运算符,函数等,尤其是函数的异步,没有做好预习,经过补救后基础地掌握了异步的本质,可以得出一些简单程序的结果。在文章的末尾,衷心感谢学长学姐们的教导。