本文详解JavaScript中nextSibling和previousSibling的正确用法。针对IE与Firefox对空白文本节点处理的差异,提供了通过nodeType过滤非元素节点的方法,确保在批量生成表单时能准确获取兄弟节点的值,避免跨浏览器兼容性问题。
基于DOM节点的日期验证场景
在进行日期验证时,无需验证具体格式,只需确保起始日期不大于结束日期。由于输入页面采用批量生成方式,且每一行由脚本动态创建,无法直接使用ID作为参数,必须通过DOM节点进行操作,这增加了验证逻辑的复杂度。
以下是JSP页面中相关部分的代码结构:
<td><input id="warrantyStartDateStr" name="warrantyStartDateStr"
class="toolbar_button_input_80" type="Text" onClick="WdatePicker()"></td>
<td><input id="warrantyEndDateStr" name="warrantyEndDateStr" class="toolbar_button_input_80" type="Text" onClick="WdatePicker()" onBlur="checkDateOne(this)"></td>
最终的JavaScript函数实现如下:
该函数的核心目标是不依赖ID,直接通过DOM节点获取两个input元素的value值(即起始时间和结束时间),进而比较这两个时间的大小关系。
function checkDateOne(inputsNode){
var p = inputsNode.parentNode; //取得input节点的父节点td
var preNode=p.previousSibling.firstChild;//取得td节点的前一个兄弟节点的第一个子结点
var startDate = document.getElementByIdx_x(preNode.id).value;
var endDate = document.getElementByIdx_x(inputsNode.id).value;
if(startDate.length>0 && endDate.length>0){
var startTmp=startDate.split("-");
var endTmp=endDate.split("-");
var sd=new Date(startTmp[0],startTmp[1],startTmp[2]);
var ed=new Date(endTmp[0],endTmp[1],endTmp[2]);
if(sd.getDate()>=ed.getDate()){
alert("起始日期不能大于结束日期");
//return false;
}
}
}
实现思路首先获取当前input节点的父节点p(即td节点),然后获取父节点的上一个兄弟节点的第一个子节点input,从而成功获取到目标值。
需要特别注意,td节点是input节点的父节点,而非兄弟节点,在遍历时应明确这一层级关系。
IE与Firefox对空白节点处理的差异
此外,nextSibling和previousSibling在Internet Explorer(IE)与Firefox(FF)之间存在显著的行为差异,需特别处理。
通过以下示例进行说明:
<body>
<div>
<input id= "a4" type= "button" onclick= "alert(this.nextSibling);" value= "d" />
<input id= "a5" type= "button" onclick= "alert(this.nextSibling);" value= "e" />
</div>
</body>
从表面结构看,div的nextSibling似乎只包含两个input节点,但实际上包含5个节点:换行符、input、换行符、input、换行符。这是因为IE在生成表单控件(如button、checkbox、radio等)时,会自动在标签后插入一个1字节宽的空白节点。
IE会自动跳过节点间的空格文档节点(如换行字符),而Firefox不会这样做。Firefox会将空格、换行等排版元素视为节点进行读取。因此,在IE中使用nextSibling可直接读取下一个节点元素,而在Firefox中则需要使用nextSibling.nextSibling才能定位到实际的元素节点。
previousSibling的作用与nextSibling相反,但处理逻辑相同,同样需要考虑浏览器对空白节点的差异处理。
以下是关于nextSibling和previousSibling的详细介绍及兼容性问题解决方案。
通过nodeType实现跨浏览器兼容
在Firefox中,节点间包含大量作为文本节点的空白字符,直接使用nextSibling和previousSibling会导致获取到文本节点而非元素节点。Firefox会将文本节点误判为元素节点的兄弟节点。解决方法是添加nodeType判断,当获取到的上一节点或下一节点为文本节点时,继续向上或向下查找,直到找到nodeType为1的元素节点。以下代码已在Firefox中测试通过,供参考:
//下一个兄弟节点
function nextSibling(node) {
var tempLast = node.parentNode.lastChild;
if (node == tempLast) return null;
var tempObj = node.nextSibling;
while (tempObj.nodeType != 1 && tempObj.nextSibling != null) {
tempObj = tempObj.nextSibling;
}
return (tempObj.nodeType==1)? tempObj:null;
}
//前一个兄弟节点
function prevSibling(node) {
var tempFirst = node.parentNode.firstChild;
if (node == tempFirst) return null;
var tempObj = node.previousSibling;
while (tempObj.nodeType != 1 && tempObj.previousSibling != null) {
tempObj = tempObj.previousSibling;
}
return (tempObj.nodeType==1)? tempObj:null;
}
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript" >
window.onload = function () {
var oUl = document.getElementsByTagName("UL");
var nodeLi = oUl[0].childNodes[3];
var nextListItem = nodeLi.nextSibling;
var preListItem = nodeLi.previousSibling;
alert(nextListItem.tagName + " " + preListItem.tagName);
nextListItem = nextSibling(nodeLi);
preListItem = prevSibling(nodeLi);
alert(nextListItem.tagName + " " + preListItem.tagName);
}
//下一个兄弟节点
function nextSibling(node) {
var tempLast = node.parentNode.lastChild;
if (node == tempLast) return null;
var tempObj = node.nextSibling;
while (tempObj.nodeType != 1 && tempObj.nextSibling != null) {
tempObj = tempObj.nextSibling;
}
return (tempObj.nodeType==1)? tempObj:null;
}
//前一个兄弟节点
function prevSibling(node) {
var tempFirst = node.parentNode.firstChild;
if (node == tempFirst) return null;
var tempObj = node.previousSibling;
while (tempObj.nodeType != 1 && tempObj.previousSibling != null) {
tempObj = tempObj.previousSibling;
}
return (tempObj.nodeType==1)? tempObj:null;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
<li>JQuery</li>
<li>Dom</li>
</ul>
<ul>
<li>ASP.NET</li>
<li>JSP</li>
<li>PHP</li>
<li>VB.NET</li>
</ul>
</div>
</form>
</body>
</html>
其中,nodeType的值主要有以下几种常见类型:
元素节点的nodeType值为1 属性节点的nodeType值为2 文本节点的nodeType值为3