[原]再次理解DOM的节点属性

    正如《JavaScript DOM编程艺术》的笔记:DOM 一文中描述的,DOM把一份文档表示为一棵树,或称家谱树,并使用parent(父)、child(子)、sibling(兄弟)等记号来表示家族成员之间的关系。DOM文档是由节点构成的集合,节点是文档树上的数字和树叶。DOM里存在许多不同类型的节点,其中最常见的有三种:元素节点、属性节点和文本节点。节点类型和具体的节点决定了其是否能包含其他节点。
    例如,元素节点可以包含属性节点,但不一定能包含文本节点。<p>、<span>就可以包含文本节点,<ul>就不行。同时,根据您使用DOM获取节点的方法不同,对节点的处理方式也不一样。特别是涉及关键字this 的情况。

一、示例说明
以一个实际的例子来具体说明。在这个例子中,我们希望通过点击一个链接,然后把链接文本内容(而不是目标)显示在屏幕中。
HTML代码如下:

<head>
<script language="javascript" type="text/javascript">
function showhref(obj) {
  var content = document.getElementById("content");
  content.innerHTML = obj;
  }
</script>
</head>
<body>
<a href="#" onclick="showhref(this);return false;">点击</a>
<div id="content">
没有内容
</div>
</body>

结果?您预想中的结果是什么呢?实际查看页面,点击链接后,结果是:

引用
点击
http://localhost/this_test.html#

可见,得到的不是链接目标,而并不是我们需要的实际链接文本内容。

二、分析
既然结果不正确,我们来逐步分析问题原因。
1、节点类型
我们知道,关键字this在这种情况下应该传递的是点击对象的本身。但这个本身是什么含义呢?
幸亏,DOM提供了一个nodeType的方法,查看某节点的类型(不同于JavaScript的typeof方法)。所以,我们先来看看this传递的是什么对象。把JavaScript函数改动一下:

function showhref(obj) {
  var content = document.getElementById("content");
  content.innerHTML = "obj节点名称是:"+obj.nodeName+"<br />";
  content.innerHTML += "类型是:"+obj.nodeType;
  }

页面显示结果:

引用
点击  
obj节点名称是:A
类型是:1

可见,在这里this 传递的对象是一个a元素节点(类型1表示元素节点)。而元素节点本身的nodeValue为null 。这可通过实际代码来看看,把代码改为:

content.innerHTML += "其nodeValue是:"+obj.nodeValue;

结果:

引用
点击
obj节点名称是:A
其nodeValue是:null

◎ 这与我们从DOM一文了解到的信息是相同的:

引用
如果给定节点是一个元素节点,该属性将返回null 。
如果给定节点是一个属性节点,将返回这个属性的值。
如果给定节点是一个文本节点,将返回这个文本节点的内容。
nodeValue属性是一个读/写属性,但不能对已经被定义为null的值进行设置(也就是元素节点没有这个属性)。

那么,到底链接内容是属于哪个节点呢?

2、子节点
链接内容既然不是a标记的属性,那只可能是一个文本节点。修改代码:

content.innerHTML += "其第一个子节点的类型是:"+obj.firstChild.nodeType+"<br />";
content.innerHTML += "其第一个子节点的名称是:"+obj.firstChild.nodeName+"<br />";
content.innerHTML += "其第一个子节点的值是:"+obj.firstChild.nodeValue;

结果:

引用
点击
obj节点名称是:A
其第一个子节点的名称是:#text
其第一个子节点的类型是:3
其第一个子节点的值是:点击

可见,链接内容文本时作为一个文本节点,连接到a标记属性节点的后面的。文本节点也是节点的类型之一,类型值为3。所以,其拥有nodeValue属性。
但是,如果链接内容不是一个单纯的文本,而是包括其他的标记,例如HTML代码是:

<a href="#" onclick="showhref(this);return false;"><strong>点击</strong></a>

这时,我们得到的结果就完全不同了:

引用
点击  
obj节点名称是:A
其第一个子节点的名称是:STRONG
其第一个子节点的类型是:1
其第一个子节点的值是:null

※ 所以,在使用DOM方式时,务必注意操作的元素对象属性。
我们又得到一个新的元素节点。怎么办?
当然,你可以继续往下寻找strong标记的子节点(一个文本节点),肯定可以得到相关的值。但万一链接文本内容再次改变,代码就又要跟着修改。所以,这明显不是一种好办法。
这时,我们可借助span标记和innerHTML,把链接文本内容放在span标记里面,HTML代码改为:

<a href="#" onclick="showhref(this);return false;"><span><strong>点击</strong></span></a>

单纯这样还不行,a元素节点下的第一个子节点还是span,我们还需要借助innerHTML的帮助:

content.innerHTML = "obj节点名称是:"+obj.nodeName+"<br />";
content.innerHTML += "span第一个子节点的名称是:"+obj.firstChild.firstChild.nodeName+"<br />";
content.innerHTML += "span第一个子节点的类型是:"+obj.firstChild.firstChild.nodeType+"<br />";
content.innerHTML += "其链接内容节点的值是:"+obj.firstChild.innerHTML;

结果:

引用
点击  
obj节点名称是:A
span第一个子节点的名称是:STRONG
span第一个子节点的类型是:1
其链接内容节点的值是:点击

※ 注意,如果不使用innerHTML,那你只能使用DOM 2的办法逐个往下遍历子节点。使用span标记是为了把整个链接文本内容归在一起,以防止再出现独立的子节点。留意,结果中“链接内容节点的值”是个整体(还是粗体)的。

3、不同标记,其值的属性值不同
正如前面所说的,span、div、a等标记,可使用其innerHTML属性获得或设置其文本值。而对于常用于form中的input、select等标记,则可以通过value值获得,它们并没有innerHTML属性。
例如:

<input name="searchStrings" type="text" id="searchStrings" />

在JavaScript中获得其值:

var searchStrings = document.getElementById("searchStrings").value;

三、关于innerHTML
在修改类似的a、p、span、div等标记时,innerHTML确实很方便,例如,如果一开始我们就使用:

content.innerHTML = "obj节点名称是:"+obj.nodeName+"<br />";
content.innerHTML += "其链接内容节点的值是:"+obj.innerHTML;

结果:

引用
点击
obj节点名称是:A
其链接内容节点的值是:点击

因为innerHTML忽略了子节点的问题,对于直接处理文字带来了很多方便。但是,因为忽略了子节点处理,对于只修改部分HTML元素时可能会带来问题。
根据前人的建议是:

引用
innerHTML只适合修改頁面上静态内容。比如div和span里的动态信息。以及在某个可显示容器内一次性显示较复杂的内容对象,比如一张表格。而对现有的对象做修改,还是应该使用DOM来解决。

还有一些具体的问题,如innerHTML自带了语法检查功能,它会自动把不完整的HTML代码补充完整等。可见:Javascript:小心使用innerHTML

四、没有关键字this
上面我们是通过this传递需要操作的对象本身,下面的HTML代码去掉了this:

<a href="#" onclick="showhref();return false;">点击</a>

JavaScript代码:

function showhref() {
  var content = document.getElementById("content");
  var node = document.getElementsByTagName("a");
  content.innerHTML = "其链接内容节点的值是:"+node[0].innerHTML;
  }

结果:

引用
点击  
其链接内容节点的值是:点击

注意,getElementsByTagName返回的是一个包含对应标记的元素数组,需从中选择其子元素进行实际操作。这个只有一个a元素,所以可通过node[0]指定。

IE 和FF 获取class属性的问题
JavaScript的window.setTimeout()方法
JavaScript 的in 操作符
JavaScript 的 keyCode与键盘对应表

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/linux/105085.html

(0)
上一篇 2021年8月25日 14:48
下一篇 2021年8月25日 14:48

相关推荐

发表回复

登录后才能评论