在DOM中搜索元素

大部分时间里,为了与用户进行交互,我们需要找到元素并进行修改。

虽然我们可以使用childNodes,children等方式,但他们只允许在相邻的元素中进行移动。

幸运的是,我们有其他的全局方法可以实现这一点。

方法

document.getElementById

获取元素的最快方式是使用其 id。

下例将使用 id='info' 从document中搜索div标签。不管它在什么地方,始终都能被找到。

复制代码
<body>
  <div id="info">Info</div>
  <script>
    var div = document.getElementById('info')
    alert( div.innerHTML )
  </script>
</body>
复制代码

注意,同一个id只应该出现一起。当然,你也可以破坏这个规则,但这么做的话根据浏览器 getElementById 会出现不同的加过。因此最好还是坚持标准规范,保证指定的 id 只有一个元素。

如果没有找到元素,将会返回null。

隐式 id 变量

所有的浏览器都会隐式的为 id 创建一个变量。

举例说明,运行以下代码。它会输出 test。因为 a 是由IE生成的对元素的引用。

<div id="a">test</div>
<script>
  alert(a)
</script>

运行下段代码在IE中可能会导致错误,请看下面的例子。

<div id="a">test</div>
<script>
  a = 5 // (x)
  alert(a)
</script>

如果你从IE运行,它将不会工作。x行有错误的,因为:

  1. a 是对DIV的引用(没问题)
  2. IE生成的引用不能被重写

但是你可以使用var a来代替a:

<div id="a">test</div>
<script>
  var a = 5 
  alert(a) // all fine
</script>

IE教了我们其他的好的实验。

我们都知道window是全局对象。JavaScript在最后会在window中搜索所有的东西。

那么window.window是什么,window === window.window 是否成立

逻辑上来看,它是相同的,但... 。

除了IE的大部分浏览器中,window.window只是对引用的一个钩子,window也是。因此 window === window.window,成立。

并且 window.window.window 也是跟 window.window 一样。

但是在IE,顶层的 window 是特殊的对象拥有着特殊的功能,然而 window.window 有点像标准的window对象。

你可以在IE中验证以下代码:

alert(window === window.window) // false
alert(window.window === window.window.window) // true

为什么说它是重要的。

当你使用一个变量不适用 var 时,它会有一些功能及Bug,因为IE使用它自己的外部window对象对它进行处理。

其中最明显的有:

1. 对元素的id重新进行赋值 - IE会报错:

<div id="a">...</div>
<script> 
  a = 5    // error in IE! Ok if "var a = 5"
  alert(a) // will never happen
</script>

2. 从外部window变量中对它进行递归遍历 - 下面的代码会在 IE<9 中死掉。

复制代码
<script>
// recurse is explicitly defined on the outer window
window.recurse = function(times) {
  if (times !== 0) recurse(times-1)
}

recurse(13)
</script>
复制代码

该BUG在IE9中已修复。

document/node.getElementsByTagName

通过这个方法可以使用特定的标签名进行检索,结果为array-like的元素集合。

// get all div elements
var elements = document.getElementsByTagName('div')

下例会展示出如何从 document 中检索出 INPUT 标签集合,并对它们进行遍历:

复制代码
<table id="myTable">
  <tr>
    <td>Your age:</td>

    <td>
      <label>
        <input type="radio" name="age" value="young" checked/> under 18
      </label>
      <label>
        <input type="radio" name="age" value="mature"/> from 18 to 50
      </label>
      <label>
        <input type="radio" name="age" value="senior"/> older than 60
      </label>
    </td>
  </tr>

</table>

<script>
var elements = document.getElementsByTagName('input')
  for(var i=0; i<elements.length; i++) {
    var input = elements[i]  
    alert(input.value+': '+input.checked)
  }
</script>
复制代码

我们也可以直接访问第一个元素:

var element = document.getElementsByTagName('input')[0]

可以通过使用 '*' 而不是标签来获取所有的元素:

// get all elements in the document
document.getElementsByTagName('*')
Limit search by parent element

getElementsByTagName可以被 document 调用,它也可以被普通的DOM元素进行调用。

下例演示 getElementsByTagName 如何在普通的DOM元素中进行调用的。 

复制代码
<ol id="people">
  <li>John</li>
  <li>Rodger</li>
  <li>Hugo</li>
</ol>
<script>

  var elem = document.getElementById('people')

  var list = elem.getElementsByTagName('li')
  alert(list[0].innerHTML)

</script>
复制代码

 

在elem中通过使用elem.getElementsByTagName('li')查找所有的 LI。点号之前的被称为上下文对象。

 

document.getElementsByName

元素是支持 name attribute的,可以通过name来查询它们。

上面的例子我们还可以使用以下代码: 

var elements = document.getElementsByName('age')
document/node.getElementsByClassName

这个方法在除了IE<9以外的所有的浏览器所支持。

它根据 class 名称进行搜索,不是attribute。尤其是,它支持多个类。

下面的例子将演示它如何根据 class名 查找对应元素。

请不要使用 IE<9 浏览器:

<div class="a b c">Yep</div>
<script>
alert( document.getElementsByClassName('a')[0].innerHTML )
</script>

跟 getElementsByTagName 一样它也可以从普通的DOM元素进行查找

document/node.querySelectorquerySelectorAll

querySelector 和 querySelectorAll可以根据 CSS3 语法检索元素。

querySelector 只返回第一个元素(深度优先),querySelectorAll 返回全部。

它们运行在除了IE<8以外的所有的浏览器里。下面列表为IE支持的情况:

  1. IE8必须在IE8末世,而不是适配末世。
  2. IE中它不支持CSS3,只支持到CSS2.1,因此没有CSS3那么强大,但大部分情况都够用了。

下面的代码会查询到最后的元素为 LI 并且父节点为 UL 的所有匹配元素。他们都可以再IE8里运行。

复制代码
<ul>
  <li>The</li>
  <li>Test</li>
</ul>
<ul>
  <li>Is</li>
  <li>Passed</li>
</ul>
<script>
  var elements = document.querySelectorAll('UL > LI:last-child')

  for(var i=0; i<elements.length; i++) {
    alert(elements[i].innerHTML )
  }
</script>
复制代码

querySelector 是 querySelectorAll('...')[0] 的缩写。

现代浏览器中使用XPath

现代浏览器都支持强力的XPath搜索,XPath在XML世界中是一个通用的DOM检索工具。大部分也可以在HTML中使用该工具。

下面的例子将会使用XPath语法检索出所有包含XPath的 H3 元素。

var result = document.evaluate("//h3[contains(text(),'XPath')]", document.documentElement, null,                  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)

for (var i=0; i<result.snapshotLength; i++) {
    alert(result.snapshotItem(i).innerHTML)
}

唯一的里外是IE(包含9),它支持XML文档。文档可以使用 XMLHTTPRequest(AJAX) 技术从服务器进行加载,但如果要在文档中进行搜索,你需要显示的把该网页载入到XML文档对象。

在现实生活中 querySelector 可以更加方便的解决任务,但多了解不同的实现方式始终是有好处的。

查询结果是实时的(活动的)

所有的DOM搜索,都会匹配多个元素,会返回一个 array-like集合,通过它有获取长度和下标功能。它也可以像数组一样使用 for 进行遍历。

但是下标和长度属性是它和数组仅有的共同点,并且返回的元素集合有一个特殊的类型 NodeList 或 HTMLCollection

因此它没有 push,pop 或JavaScript Array对象的其他属性。

相反,通过 getElementsBy* 方法查询后的结果集是活着的。你可以选择元素并更改文档 - 之前查询后的结果也会自动进行更新。

下例将会说明当元素被移除后结果集的长度是如何被更改的。

复制代码
<div id="outer">
  <div id="inner">Info</div>
</div>
<script>
  var outerDiv = document.getElementById('outer')
  var divs = document.getElementsByTagName('div')

  alert(divs.length) 

  outerDiv.innerHTML = '' // clear inner div

  alert(divs.length)
</script>
复制代码

这个特性只存在于集合中。如果你得到一个元素的引用,则该引用不会成为 null。例如,元素 elem = document.getElementById('inner') 当外部 div 被清除后它也会一直存在。

但是 querySelectorAll 有些特殊。因为性能原因,它会返回 非活跃 的 NodeList。它是通用规则的一个例外。

实践

考虑以下的HTML:

复制代码
<!DOCTYPE HTML>
<html>
<body>
<label>The table</label>

<form name="age-form">

  <table id="age-table">
    <tr>
      <td id="age-header">Your age:</td>
      <td>
        <label>
          <input type="radio" name="age" value="young"/> under 18
        </label>
        <label>
          <input type="radio" name="age" value="mature"/> 18 to 50
        </label>
        <label>
          <input type="radio" name="age" value="senior"/> after 60
        </label>
      </td>
    </tr>
  </table>

</form>
</body>
复制代码

下面为根据上面的DOM结构的一些练习。

查找表格中的所有的 laben 元素。结果是 label 类型的数组。

参考答案

编写一个函数checkInsideTable(id) ,当传一个id,并且该id的元素在id为age-table的表格中存在的话返回true。

如果没有此元素,则返回false:

例如:

    checkInsideTable('age-header') // true
    checkInsideTable('top') // false
    checkInsideTable('non-existant-id') // false

参考答案

标签链接
复制代码
<style>
.external { background-color: yellow }
</style>
<ul>
  <li><a href="http://google.com">http://google.com</a></li>
  <li><a href="/tutorial">/tutorial.html</a></li>
  <li>
   <a href="ftp://ftp.com/file.zip">ftp://ftp.com/file.zip</a>
  </li>
  <li><a href="http://nodejs.org">http://nodejs.org</a></li>
</ul>
复制代码

给所有的外部链接添加 external 类。

参考答案

显示子节点数量

编写程序,当 li 节点拥有者 li 子节点的时候给该 li 节点方括号及子li节点的数量。

如果没有li子节点则不进行任何操作。

下面代码为html代码:

复制代码
<ul>
    <li>About Animals
        <ul>
            <li>Mammal
                <ul>
                    <li>Cows</li>
                    <li>Donkeys</li>
                    <li>Dogs</li>
                    <li>Tigers</li>
                </ul>
            </li>   
            <li>Others
                <ul>
                    <li>Snakes</li>
                    <li>Birds</li>
                    <li>Lizards</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>
        About Fish
        <ul>
            <li>
                About aquarium fishes
                <ul>
                    <li>Guppy</li>
                    <li>Scalare</li>
                </ul>
            </li>
            <li>
                Sea fish
                <ul>
                    <li>Sea trout</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
复制代码

希望的输出结果是

  • About Animals [9]
    • Mammals [4]
      • Cows
      • Donkeys
      • Dogs
      • Tigers
    • Others [3]
      • Snakes
      • Birds
      • Lizards
  • About Fish [5]
    • About aquarium fishes [2]
      • Guppy
      • Scalare
    • Sea fish [1]
      • Sea trout

参考答案

更多

在任意一个html文档中执行以下代码

1
2
3
4
5
6
var  aList1 = document.getElementsByTagName( 'a' );
var  aList2 = document.querySelectorAll( 'a' );
 
document.body.appendChild(document.createElement( 'a' ));
 
alert(aList1.length - aList2.length);

会输出什么,为什么?  

总结

有5种方式查询DOM:

  1. getElementById
  2. getElementsByTagName
  3. getElementsByName
  4. getElementsByClassName (除了 IE<9)
  5. querySelector (除了 IE<8 和 IE8 兼容模式)

上面的所有的方法都可以搜索节点内的其他元素。除了最后一个之外的所有方法都是 活动的 集合。

大部分浏览器支持XPath,但现在很少被使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值