本文上接【前端学习之路】JavaScript语法(三),主要讲解JavaScript中文档对象模型DOM的概念。
本文部分内容参考W3school中JavaScript模块,在此感谢W3school对本文的支持。W3school主页
文档对象模型(DOM)
DOM::Document Object Model。
通过 HTML DOM,JavaScript 能够访问、更改、添加或删除 HTML 文档的任意元素。
DOM编程界面
编程界面是每个对象的属性和方法。
- 属性是您能够获取或设置的值(就比如改变 HTML 元素的内容)。
- 方法是您能够完成的动作(比如添加或删除 HTML 元素)。
例子:
<html>
<body>
<p id="demo"></p>
<script>
document.getElementById("demo").innerHTML = "Hello World!";
</script>
</body>
</html>
在这个例子中,getElementById
是方法,innerHTML
是属性。
HTML DOM Document对象
文档对象(document 对象)代表当前网页。
我们通过访问 document 对象,来访问 HTML 页面中的任何元素。
下面是一些如何使用 document 对象来访问和操作 HTML 的实例。
查找HTML元素
方法 | 描述 |
---|---|
document.getElementById(id) | 通过元素id来查找HTML中某一元素 |
document.getElementsByTagName(name) | 通过标签名来查找元素 |
document.getElementsByClassName(name) | 通过类名查找元素 |
因为每个标签的id是唯一的,所以Element不使用复数格式;因为HTML文档中一个标签或者类名可能出现多次,所以使用复数格式Elements;
改变HTML元素
方法 | 描述 |
---|---|
element.innerHTML = new html content | 改变元素的 inner HTML |
element.attribute = new value | 改变 HTML 元素的属性值 |
element.setAttribute(attribute, value) | 改变 HTML 元素的属性值 |
element.style.property = new style | 改变 HTML 元素的样式 |
添加和删除元素
方法 | 描述 |
---|---|
document.createElement(element) | 创建 HTML 元素 |
document.removeChild(element) | 删除HTML 元素 |
document.appendChild(element) | 添加 HTML 元素 |
document.replaceChild(element) | 替换 HTML 元素 |
document.write(text) | 写入 HTML 输出流 |
添加事件处理程序
方法 | 描述 |
---|---|
document.getElementById(id).onclick = function(){code} | 向element对应的onclick事件添加事件处理程序 |
HTML对象选择器
因为首个 HTML DOM Level 1 (1998)只定义了 11 个 HTML 对象、对象集合和属性。在 HTML DOM Level 3,加入了更多对象、集合和属性。
因为具体对象、集合和属性很多,这里就列举几个经常用的,其余的可以在W3school JavaScript DOM 文档中找到。
属性 | 描述 |
---|---|
document.anchors | 返回拥有 name 属性的所有 <a> 元素。 |
document.body | 返回 <body> 元素 |
document.cookie | 返回文档的 cookie |
document.documentElement | 返回<html> 元素 |
document.forms | 返回所有<form> 元素 |
document.head | 返回 <head> 元素 |
document.images | 返回所有 <img> 元素 |
document.links | 返回拥有 href 属性的所有 <area> 和 <a> 元素 |
document.scripts | 返回所有 <script> 元素 |
查找HTML元素
通过 id 查找 HTML 元素
var element=document.getElementById("id");
如果元素被找到,此方法会以对象返回该元素。
如果未找到元素,myElement 将包含 null。
通过标签名查找 HTML 元素
查找所有<p>元素:
var x=document.getElementsByTagName("p");
查找id="main"的元素,然后查找"main"中所有<p>元素:
var x=document.getElementById("main");
var y=x.getElementsByTagName("p");
通过类名查找 HTML 元素
如果您需要找到拥有相同类名的所有 HTML 元素,请使用 getElementsByClassName()。
本例返回包含 class=“class” 的所有元素的列表:
var x=document.getElementsByClassName("class");
通过 CSS 选择器查找 HTML 元素
如果您需要查找匹配指定 CSS 选择器的所有 HTML 元素,可以使用 querySelectorAll() 方法。
本例返回 class=“intro” 的所有 <p> 元素列表:
var x = document.querySelectorAll("p.intro");
通过 HTML 对象集合查找 HTML 元素
本例查找 id=“frm1” 的 form 元素,在 forms 集合中,然后显示所有元素值:
var x = document.forms["frm1"];
var text = "";
var i;
for (i = 0; i < x.length; i++) {
text += x.elements[i].value + "<br>";
}
document.getElementById("demo").innerHTML = text;
改变HTML
document.write()
在 JavaScript 中,document.write() 可用于直接写入 HTML 输出流:
document.write(Date());
需要注意的是,不要再文档加载后使用document.write()。因为这样做会覆盖原文档。
改变HTML内容
修改 HTML 文档内容最简单的方法是,使用 innerHTML 属性。如需修改 HTML 元素的内容,请使用此语法:
document.getElementById(id).innerHTML = new text
改变属性的值
如需修改 HTML 属性的值,请使用如下语法:
document.getElementById(id).attribute = new value
改变CSS样式
如需更改 HTML 元素的样式,请使用此语法:
document.getElementById(id).style.property = new style
property是你想改变的样式名称,比如说color,font等等。
创建HTML动画
JavaScript 动画是通过对元素样式进行渐进式变化编程完成的。
这种变化通过一个计数器来调用。当计数器间隔很小时,动画看上去就是连贯的。
例子:
<!DOCTYPE html>
<html>
<head>
<title>HTML动画</title>
<style type="text/css">
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animation {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
</style>
</head>
<body>
<button onclick="Move();">点我</button>
<div id="container">
<div id="animation">
</div>
</div>
<script type="text/javascript">
function Move(){
var element=document.getElementById("animation");
var pos=0;
var id=setInterval(frame,5);
function frame(){
if(pos==350){ //当pos等于350时,使用clearInterval()函数停止计时器对frame的周期执行
//clearInterval(id)的参数是setInterval()返回的id值,代表在第id次计时器停止执行。
clearInterval(id);
}
else{
pos++;
element.style.top=pos+"px";
element.style.left=pos+"px";
}
}
}
</script>
</body>
</html>
setInterval(func,interval)是一个计时器,表示每隔interval毫秒执行func函数。计时器的停止函数为clearInterval(id),其中id为setInterval()函数的返回值。
HTML DOM事件
在HTML中,通过事件触发来执行JavaScript的代码或者函数。
事件 | 作用 |
---|---|
onclick | 按钮被点击时执行,在button中常用 |
onload | 用户进入界面会触发onload事件,在body中常用 |
onunload | 用户离开界面会触发onunload事件,在body中常用 |
onchange | 经常与输入字段验证结合使用,用户改变输入内容时触发,在input中常用 |
onmouseover | 用户将鼠标移至 HTML 元素上时触发事件 |
onmouseout | 用户将鼠标移出 HTML 元素时触发事件 |
onmousedown | 鼠标按钮被点击时触发事件 |
onmousedown | 鼠标按钮被释放时触发事件 |
onfocus | 事件在对象获得焦点时触发,常用于input文本框 |
onblur | 事件会在对象失去焦点时触发,常用于input文本框 |
HTML DOM事件监听程序
我们在js中通过addEventListener() 方法为指定DOM元素添加事件监听器。也可以通过removeEventListener() 方法轻松地删除事件监听器。能被事件监听程序监听到的事件可看这篇博客:
JS中addEventListener的用法
语法
添加事件:addEventListener()
element.addEventListener(event,myfunction,useCapture)
第一个参数event是事件的类型(例如"click"或"focus",事件名去掉"on")。此参数必选。
第二个参数myfunction是当事件发生时我们需要调用的函数。此参数必选。
第三个参数useCapture,是一个布尔值,指定使用时间冒泡还是时间捕获。此参数可选。
移除事件:removeEventListener()
element.removeEventListener(event, myfunction);
这两个参数和添加事件的前两个参数一致,用于删除某个DOM元素上监听的事件。
向元素添加事件处理
例:
document.getElementById("id").addEventListener("click",function(){console.log("Hello");});
也可以引用外部“命名”函数:
document.getElementById("id").addEventListener("click",myfunction);
function myfunction(){
console.log("Hello");
}
向相同元素添加多个事件处理程序
addEventListener() 方法允许您向相同元素添加多个事件,同时不覆盖已有事件:
对相同元素、相同事件添加不同函数,例:
element.addEventListener("click", myFunction);
element.addEventListener("click", mySecondFunction);
同时,也可以相同元素、不同事件添加函数:
element.addEventListener("mouseover", myFunction);
element.addEventListener("click", mySecondFunction);
element.addEventListener("mouseout", myThirdFunction);
向window对象添加事件处理程序
addEventListener() 允许您将事件监听器添加到任何 HTML DOM 对象上,比如 HTML 元素、HTML 对象、window 对象或其他支持事件的对象,比如 xmlHttpRequest 对象。
例,当用户调整窗口大小时触发的事件监听器:
window.addEventListener("resize", function(){
document.getElementById("demo").innerHTML = sometext;
});
传递参数
当传递参数值时,请以参数形式使用调用指定函数的“匿名函数”:
例:
element.addEventListener("click", function(){ myFunction(p1, p2); });
事件冒泡传播or事件捕获传播
在 addEventListener() 方法中,我们使用useCapture参数规定传播类型。默认值是 false,将使用冒泡传播,如果该值设置为 true,则事件使用捕获传播。
事件冒泡传播
最内侧元素的事件会首先被处理,然后是更外侧的:首先处理 <p> 元素的点击事件,然后是 <div> 元素的点击事件。
事件捕获传播
最外侧元素的事件会首先被处理,然后是更内侧的:首先处理 <div> 元素的点击事件,然后是 <p> 元素的点击事件。
removeEventListener() 方法
removeEventListener() 方法会删除已通过 addEventListener() 方法附加的事件处理程序:
例:
element.removeEventListener("mousemove", myFunction);
HTML DOM导航节点树
DOM节点
根据 W3C HTML DOM 标准,HTML 文档中的所有事物都是节点:
- 整个文档是文档节点
- 每个 HTML 元素是元素节点
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 所有注释是注释节点
有了 HTML DOM,节点树中的所有节点都能通过 JavaScript 访问。JavaScript能够创建新节点,还可以修改和删除所有节点。
节点关系
通过 JavaScript,您可以使用以下节点属性在节点之间导航:
- parentNode 父节点
- childNodes 返回一个节点的所有子节点集合
- childNodes[nodenumber] 第nodenumber个子节点
- firstChild 第一个子节点
- lastChild 最后一个子节点
- nextSibling 相邻的下一个子节点
- previousSibling 相邻的上一个子节点
子节点和节点值
DOM 处理中的一种常见错误是认为元素节点中包含文本。
实例:
<title id="demo">DOM 教程</title>
上面例子中的元素节点 <title> 不包含文本。它包含了值为 “DOM 教程” 的文本节点,同时也包含了属性节点,它本身是元素节点。
文本节点的值能够通过节点的 innerHTML 属性进行访问:
var myTitle = document.getElementById("demo").innerHTML;
访问 innerHTML 属性等同于访问首个子节点的 nodeValue:
var myTitle = document.getElementById("demo").firstChild.nodeValue;
也可以这样访问第一个子节点:
var myTitle = document.getElementById("demo").childNodes[0].nodeValue;
DOM根节点
有两个特殊属性允许访问完整文档:
- document.body 文档的 body
- document.documentElement 整个文档内容
nodeName属性
nodeName 属性规定节点的名称。
- nodeName 是只读的
- 元素节点的 nodeName 等同于标签名
- 属性节点的 nodeName 是属性名称
- 文本节点的 nodeName 总是 #text
- 文档节点的 nodeName 总是 #document
nodeValue 属性
nodeValue 属性规定节点的值。
- 元素节点的 nodeValue 是 undefined
- 文本节点的 nodeValue 是文本内容
- 属性节点的 nodeValue 是属性值
添加和删除节点
创建新HTML节点(元素)
我们通过一个例子来了解创建节点的过程:
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另一个段落。</p>
</div>
<script>
//创建<p>元素节点
var para = document.createElement("p");
//创建文本节点
var node = document.createTextNode("这是新文本。");
//将文本节点挂在元素节点上,作为元素节点的子节点
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
</script>
结果:
使用appendChild(element)函数,追加新节点作为父节点的最后一个子节点。我们也可以使用insertBefore(element) 方法向父节点添加节点,不过追加新节点将作为父节点的第一个子节点。
例子:
我们将上面的element.appendChild(para);
换成element.insertBefore(para, child);
,将得到如下结果:
删除HTML节点(元素)
如需删除某个 HTML 节点,您需要知晓该节点的父节点:
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另一个段落。</p>
</div>
<script>
//获得待删除节点的父节点
var parent = document.getElementById("div1");
//获得待删除节点
var child = document.getElementById("p1");
//通过父节点删除子节点
parent.removeChild(child);
</script>
能够在不引用父的情况下删除某个节点是极好的。但是很遗憾。DOM 需要同时了解您需要删除的节点及其父节点。
这是一种常见的解决方法:找到你想要删除的子节点,并利用其 parentNode 属性找到父节点:
var child = document.getElementById("p1");
child.parentNode.removeChild(child);
替换HTML节点(元素)
如需替换元素的,请使用 replaceChild() 方法,这个方法同样需要得到待替换节点的父元素,才能进行替换。
<div id="div1">
<p id="p1">这是一个段落。</p>
<p id="p2">这是另一个段落。</p>
</div>
<script>
var para = document.createElement("p");
var node = document.createTextNode("这是新文本。");
para.appendChild(node);
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.replaceChild(para, child);
</script>
结果:
HTML DOM 集合与节点列表
HTMLCollection 对象
在前面我们就学到,可以使用getElementsByTagName() 方法返回 HTMLCollection 对象。
HTMLCollection 对象是类数组的 HTML 元素列表(集合)。
下面的代码选取文档中的所有 <p> 元素:
var x = document.getElementsByTagName("p");
该集合中的元素可通过索引号进行访问。
如需访问第二个 <p> 元素,我们可以使用x[1]
代表。也可以通过标签的名称和id号来获得对应元素。
除此之外,我们可以通过HTMLCollection 对象的length属性获得HTMLCollection中元素的数量。
需要注意的是,HTMLCollection 并非数组!
HTMLCollection 也许看起来像数组,但并非数组。我们能够遍历列表并通过数字引用元素(就像数组那样)。不过,我们无法对 HTMLCollection 使用数组方法,比如 valueOf()、pop()、push() 或 join()。
NodeList对象
NodeList 对象是从文档中提取的节点列表(集合)。和HTMLCollection几乎相同,一般由不同方法返回不同类型。
- 所有浏览器都会为
childNodes
属性返回 NodeList 对象。 - 如使用
getElementsByClassName()
方法,某些(老的)浏览器会返回 NodeList 对象而不是 HTMLCollection。 - 大多数浏览器会为
querySelectorAll()
方法返回 NodeList 对象。
和HTMLCollection对象一样,我们可以通过length属性获得NodeList的长度,也可以通过索引像数组那样访问每个元素,但是不能通过id和名称获取。
只有 NodeList 对象能包含属性节点和文本节点。
需要注意的是,NodeList并非数组!
和HTMLCollection一样,NodeList也许看起来像数组,但并非数组。我们能够遍历NodeList并通过数字引用元素。不过,我们无法对 NodeList使用数组方法,比如 valueOf()、pop()、push() 或 join()。