JS中的DOM

DOM

一、DOM简介

D——document,没有文档,也就是没有网页,DOM就无从谈起。

当创建了一个网页并把它加载到web浏览器中时,DOM就悄然而生。浏览器根据网页文档创建一个文档对象。

O——object,对象。

对象有三种,

1、用户自定义对象

2、内建对象,javascript中的对象,如Array,Math,Date等。

3、宿主对象,由浏览器提供的对象,如window对象。

M——model,模型。

正如一个火车模型代表一列真正的火车,DOM代表被加载到浏览器窗口里的当前网页。浏览器为我们提供了当前网页的模型,可通过javascript去读写它。

所以DOM(Document Object Model),文档对象模型,可以简单理解为代表网页文档的一颗树(模型)。

二、nodeName、nodeValue以及nodeType和innerHTML和value

DOM将网页表示为一颗树,该树的节点类型有多种。

元素节点——html标签

文本节点——文本

属性节点——属性总是被包含在标签里,所以属性节点总是被包含在元素节点当中。(元素节点(属性节点,文本节点))

通常可以通过开发者工具(如firebug)查看dom结构,但是要说明一点,开发者工具中的DOM并不完整,因为有些元素存在于DOM中,但是不会被开发者工具显示。比如回车会被当做一个文本节点。

点我查看DOM中的空白符

 1、nodeType

DOM本质就是一堆节点的集合,由于包含不同类型的信息,所以就有不同类型的节点。接下来看nodeType。

元素节点,nodeType为1

属性节点,nodeType为2

文本节点,nodeType为3

文档节点,nodeType为9

Note:文档节点并不是根元素(html),因为注释等内容可以出现在根元素之外。所以在构造DOM树时,根元素并不适合作为根节点,所以就出现了文档节点,而根节点作为文档节点的子节点。

<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素节点nodeType返回值"+element.nodeType);
    console.log("文本节点nodeType返回值"+text.nodeType);
    console.log("属性节点nodeType返回值"+property.nodeType);
    console.log("文档节点nodeType返回值"+document.nodeType);
</script>
</body>

 这里我要重点说一下属性节点。先上一张图:

 

图是w3schools教程中的,属性节点(红色框)的画法是很特别的,我第一次看教程没看懂为什么要这么画?难道其中有隐情?但是教程也都没有提及。

可能很多人没注意,我现在来说一下。

因为属性节点实际上是附属于元素的,所以不被看做是元素的子节点,因为并没有被当做是DOM的一部分。在属性节点上调用parentNode,previousSibling和nextSibling都返回null。

<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    console.log("<p>的子节点是  "+element.firstChild);
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("属性节点的parentNode  "+property.parentNode);
    console.log("属性节点的左邻节点  "+property.previousSibling);
    console.log("属性节点的右邻节点  "+property.nextSibling);
</script>
</body>

 

所以w3schools的画法也就可以理解了,属性节点不是子节点,所以“随便”挂到元素节点上。

 nodeType属性经常和if配合使用,确保不会在错误的节点类型上执行错误的操作。比如

<script type="text/javascript">
window.onload=function(){
    var mynode=document.getElementById("p");
    if(mynode.nodeType==1){
        mynode.setAttribute('title','段落');
        mynode.style.color="red";
    }
}
</script>

 

补充内容:

值——元素类型

1——元素节点,表示文档中元素,元素节点是唯一能够拥有属性的节点类型。元素和属性的文本内容都是由文本节点来表示的。

2——属性节点,代表元素的属性。

3——文本节点,只包含文本内容,也可以只包含空白。

4——CDATA段节点。

5——ENTITY REFERENCE实体引用节点。实体引用节点可以被用于表示DOM树中的一个实体引用。

6——ENTITY实体节点,表示文档中已分析或未分析的实体。

7——PI(processing instruction)处理指令节点,

8——注释节点,表示注释的内容。

9——文档节点(DOCUMENT),文档树的根节点。

10——DOCUMENT TYPE文档类型节点。

11——DOCUMENT FRAGMENT文档片段节点,文档片段是"轻量级的"或"最小的"Document对象。

12——NOTATION记号节点表示了在DTD中声明的记号。

2、nodeName

对于元素节点,nodeName就是标签名。元素节点也可以通过tagName获取标签名。【update 20170315】

对于文本节点,nodeName永远是#text

对于属性节点,nodeName是属性名称

对于文档节点,nodeName永远是#document

注意

nodeName是一个只读属性,不能进行设置。

nodeName所包含的XML元素的标签名称永远是大写的。

<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素节点nodeName返回值"+element.nodeName);/*元素节点返回标签名P*/
    console.log("文本节点nodeName返回值"+text.nodeName);/*文本节点永远返回#text*/
    console.log("属性节点nodeName返回值"+property.nodeName);/*返回属性名,这里是id*/
    console.log("文档节点nodeName返回值"+document.nodeName);
</script>
</body>    
</html>

 3、nodeValue

对于元素节点,因为本身不直接包含文本,所以nodeValue是不可用的。

对于文本节点,nodeValue值为文本值

对于属性节点,nodeValue值为属性值

<body>
<p id="p">段落</p>
<script type="text/javascript">
    var element=document.getElementById("p");
    var text=document.getElementById("p").firstChild;
    var property=document.getElementById("p").getAttributeNode("id");
    console.log("元素节点nodeValue返回值"+element.nodeValue);
    console.log("文本节点nodeValue返回值"+text.nodeValue);
    console.log("属性节点nodeValue返回值"+property.nodeValue);
    console.log("文档节点nodeValue返回值"+document.nodeValue);
</script>
</body>    
</html>

 下面是一个关于nodeType,nodeName和nodeValue的综合demo。

<body>
<h1 id="h1">An HTML Document</h1> 
<p><input id="elementNode" type="button" value="查看元素节点的各项值"></p> 
<p><input id="text" type="button" value="查看文本节点的各项值"></p> 
<p><input id="documentNode" type="button" value="查看文档节点的各项值"></p> 
<p><input id="property"type="button" alt="这是个演示按钮" title="演示按钮提示标题" name="property"  value="本按钮的属性节点演示" /></p> 
<script type="text/javascript">
function showElement(){
var element=document.getElementById("h1");
alert('nodetype:'+element.nodeType);//nodeType=1 
alert('nodeName:'+element.nodeName); 
alert('nodeValue:'+element.nodeValue); //null 
alert('element:'+element); 
}
function showText(){ 
var element=document.getElementById("h1"); 
var text=element.childNodes[0]; 
alert('nodeType:'+text.nodeType); //nodeType=3 
alert('nodeValue:'+text.nodeValue); //文本节点的nodeValue是其文本内容 
text.nodeValue=text.nodeValue+"abc"; //文本内容添加修改删除等等。 
alert('nodeName:'+text.nodeName); 
alert(text.data); //data同样是其内容,这个属性下同样可以增删改。 
} 
function showDocument(){ 
alert('nodeType:'+document.nodeType); //9 
alert('nodeName:'+document.nodeName); 
alert(document); 
} 
function showAttr(){ 
var property=document.getElementById("property"); //演示按钮,有很多属性 
var attrs=property.attributes; 
for(var i=0;i<attrs.length ;i++){ 
var attr=attrs[i]; 
alert('nodeType:'+attr.nodeType); //attribute 的nodeType=2 
alert('attr:'+attr); 
alert('attr.name:'+attr.name+'='+attr.value); 
} 
} 
function demo(){
    var element=document.getElementById("elementNode");
    element.onclick=showElement;//按钮1获取节点的nodeType值
    var text=document.getElementById("text"); 
    text.onclick=showText; 
    var documentNode=document.getElementById("documentNode"); 
    documentNode.onclick=showDocument; 
    var property=document.getElementById("property"); 
    property.onclick=showAttr;
}    
window.onload=demo;
</script>
</body>

 4、innerHTML

尽管innerHTML只对元素节点有用,但不是所有的元素节点都能使用innerHTML,比如像<input> 这样的替换元素。

<label>姓名:<input type="text" value="lxy" /></label>
<script>
var oinput=document.getElementsByTagName("input")[0];
console.log("oinput.innerHTML   "+oinput.innerHTML);//没有内容
console.log("oinput.value   "+oinput.value);//获取input的value属性
</script>

其实很好理解,因为input里面不包含文本节点,所以用innerHTML获取不到文本节点的值。可使用value获取其属性值。

类似的,form里的DOM元素(input select checkbox textarea radio)值获取时都使用value。

textarea虽然可以访问innerHTML,但是获取的是初始文档中的值,当页面的textarea中的值发生变化时,innerHTML不会及时更新。有兴趣可自己写demo测试。

三、HTML DOM 访问节点

DOM的思想就是每个节点都是对象,是对象我们就可以通过一些方法获取它或者改变它的属性等。

可以通过多种方法来查找DOM元素:

a、使用getElementById()和getElementByTagName()和getElementsByClassName()方法

b、通过一个元素节点的parentNode、childNodes、children、firstChild和lastChild和previousSibling和nextSibling

c、通过document.documentElement和document.body

1、getElementById()和getElementsByTagName()和getElementsByClassName()和getElementsByName()

这四种方法会忽略文档的结构。

getElementById()不多说。

getElementsByTagName()使用指定标签名返回所有元素,这些元素是调用该方法的元素的后代。

getElementsByClassName()返回带有指定类名的所有元素的节点列表。

getElementsByName()根据元素的name属性返回所有元素的节点列表。(IE容错能力较强,会得到一个数组,其中包括id等于name值的。我还没测试)

<body> 
<span class="class">span标签内容</span>
<p class="class">p标签的内容</p>
<script>
var aclass=document.getElementsByClassName("class");
for(var i=0;i<aclass.length;i++){
    console.log(aclass[i].innerHTML);
}
</script>
</body>

 

还有一些方法是和文档结构相关的,因为DOM树中的节点是紧密相连的

上——parentNode

下——childNodes/children,firstChild,lastChild

左/右——previousSibling/nextSibling

2、childNodes

 childNodes保存子节点的引用,包括空白也在内(除了IE<9),也包括<script>在内
 

<!DOCTYPE HTML>
<!-- My document -->
<html>
<head>
  <title>My Document</title>
</head>
<body>
  <h1>Header</h1>
  <p>
    Paragraph
  </p>
  <script type="text/javascript">
  window.onload=function(){
      var childNodes=document.body.childNodes;
      for(var i=0;i<childNodes.length;i++){
          console.log(childNodes[i]);
      }
  }
  </script>
</body>
</html>

 3、children

如果只想获得子节点中的元素节点,跳过文本节点,应该使用children属性。

IE<9会在children属性中列出注释节点。

还是上面的例子,将document.body.childNodes改为document.body.children;效果如下:

使用childNodes和children获得是一个集合,想要获得单个元素,可以使用一些快速的索引siblings、parent等。

4、firstChild和lastChild

firstChild和lastChild是childNodes中首尾节点的快速索引。

var body=document.body;
alert(body.firstChild===body.childNodes[0]);//true
alert(body.lastChild===body.childNodes[body.childNodes.length-1]);//true

对firstChild最普通的用法是访问某个元素节点的文本:

var x=[a paragraph];
var text=x.firstChild.nodeValue; 

小技能

写代码检查DOM节点是否为空,就是说没有children或者文本。可用以下三种方法”

if (elem.childNodes.length) { ... }
if (elem.firstChild) { ... }
if (elem.lastChild) { ... }//最快

5、parentNode,previousSibling和nextSibling

获取父节点或者左右相邻的节点。

可借助这些属性来更新DOM,增删元素。

parentNode属性常被用来改变文档的结构。假设希望从文档中删除带有id为"maindiv"的节点:

var x=document.getElementById("maindiv");
x.parentNode.removeChild(x); 

首先找到带有指定id的节点,再移至其父节点并执行removeChidld()方法。

现在有一个问题:

document.body.lastChild.nextSibling总是null吗?//是

同样document.body.children[0].previousSibling呢?//不一定,null或者文本。因为document.body.children[0]代表第一个元素节点,可能会有文本节点作为它 previousSibling。

6、特殊入口

 访问DOM还有两个特别的入口——document.documentElement和document.body。

document.documentElement代表<html>元素。

document.body代表<body>元素,可以为null,比如在body没有呈现的时候引用就是null。

 
<head>
    <script type="text/javascript">
    alert("head部分的body"+document.body);/*null*/
    </script>
</head>
 

 

四、HTML DOM 操作

1、创建新元素(节点)

  • createElement()//创建一具体的元素
  • createTextNode()//创建一个文本节点
  • createDocumentFragment()//创建一个DOM片段

createDocumentFragment()创建一个文档碎片,把所有的节点都加在上面,最后把文档碎片一次性添加到document中,比一次次修改DOM更高效。

2、元素操作

a、更改元素内容

<body> 
<p id="p">p标签的内容</p>
<script>
var p=document.getElementById("p");
alert("暂停观察");
p.innerHTML="内容替换了";
</script>
</body> 

还可以直接给文本节点的nodeValue赋值。

比如:p.firstChild.nodeValue="再次更新文字"

b、新增元素(appendChild和insertBefore)

appendChild()将新元素作为父元素的最后一个子元素。

<body> 
<p id="p1">p标签的内容</p>
<script>
var p1=document.getElementById("p1");
var newP=document.createElement("p");
var text=document.createTextNode("新增的p标签的内容");
newP.appendChild(text);
p1.parentNode.appendChild(newP);
</script>
</body> 

insertBefore()通过父元素调用,将第一个元素插入第二个元素前面

c、移除元素removeChild

DOM中删除元素,必须通过父元素进行操作。

<body> 
<p id="p1">p标签的内容</p>
<script>
var p1=document.getElementById("p1");
alert("暂停观察");
p1.parentNode.removeChild(p1);
</script>
</body> 

d、替换元素replaceChild

替换元素也必须通过父元素来进行,接收2个参数,和insertBefore类似,用第一个参数替换第二个。

wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== 编辑

可见DOM结构的改动(增删改)都是通过父节点来进行的。

e、一个综合demo

通过InnerHTML更改元素内容,通过appendChild新增元素,通过removeChild移除元素。

<body> 
<input type="text" id="text"/>
<input type="button" value="添加li" id="button">
<ul>
</ul>
<script>
window.onload=function(){
    var obutton=document.getElementById("button");
    obutton.onclick=createLi;
}
function createLi(){
    var oText=document.getElementById("text");
    var oUl=document.getElementsByTagName("ul")[0];
    var oLi=document.createElement("li");
    oLi.innerHTML=oText.value;
    var oA=document.createElement("a");
    oA.innerHTML="删除";
    oA.href="javascript:;";
    oA.onclick=function(){
        oUl.removeChild(this.parentNode);
    }
    oLi.appendChild(oA);
    oUl.appendChild(oLi);
}
</script>
</body> 

3、特性操作

用getAttribute(),setAttribute()和removeAttribute()控制HTML标签的特性 。

<body> 
<input type="text" id="text"/>
<input type="button" value="添加li" id="button">
<ul>
</ul>
<script>
window.onload=function(){
    var obutton=document.getElementById("button");
    obutton.onclick=createLi;
}
function createLi(){
    var oText=document.getElementById("text");
    var oUl=document.getElementsByTagName("ul")[0];
    var oLi=document.createElement("li");
    oLi.innerHTML=oText.value;
    var oA=document.createElement("a");
    oA.innerHTML="删除";
    oA.href="javascript:;";
    oA.onclick=function(){
        oUl.removeChild(this.parentNode);
    }
    oLi.appendChild(oA);
    oUl.appendChild(oLi);
}
</script>
</body> 

通过setAttribute更改样式:(就是重置内联样式)

不是p1.setAttribute("color","green");

而是p1.setAttribute("style","color:green;background-color:orange;");

因为setAttribute的修改是动态的,所以查看源代码时看不到!

4、样式操作

obj.style.属性=属性值,是通过添加内联样式去覆盖已有样式的。

修改文字颜色为红色

​
<body> 
<p id="p">p标签的内容</p>
<script>
var p=document.getElementById("p");
alert("暂停观察");
p.style.color="red";
</script>
</body> 



​

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值