目录
一、概述
dom元素选择器用来检索文档标签,并返回指定标签的dom化结果。dom元素选择器细分为两种,其一标签特性选择器,其二selector选择器。
二、标签特性选择器
标签特性选择器返回的结果都具有实时性,所谓实时性是指能够自动映射dom节点的变化。
getElementById()
根据标签id获取dom元素节点,返回的结果具有实时性,若没有符合条件的元素节点则返回null。标签的id特性必须唯一,若文档中出现多个重复id,css样式对所有id相同的标签都生效,但Javascript脚本仅对满足条件的第一个元素有效。该方法在ie7及以下版本的浏览器中有两个bug,其一对匹配元素的id不区分大小写,其二标签的name特性也会被当作id特性识别。该方法作用于文档节点。
<div id="div"></div>
<script>
var div = document.getElementById("div");
console.log(div); //<div id="div"></div>
</script>
<div id="div"></div>
<script>
var div = document.getElementById("DIV");
//ie7及ie7以下浏览器打印<div id="demo"></div>
//其他浏览器打印undefined
console.log(div);
</script>
标签如果存在id特性,且Window对象中没有以此id值为名称的属性,那么这个id就会隐式转换为一个指向该元素节点的全局变量,效果与getElementById方法相同。最初这是ie里面的方法,后来其他浏览器也支持了,但并不推荐使用,因为这不是w3c中的标准。说不定哪天就不支持了。
<div id="div"></div>
<script>
console.log(div); //等同于var div = document.getElementById("div")
</script>
document.getElementById方法写起来很长,可以选择用一个简短的单词替代它,但因为this指向问题,容易造成错误,比如下面这段代码就是错误的。
var getId = document.getElementById;
getId('div'); //报错
上面这段代码报错的原因是this指向问题。当getElementById作为document对象的属性被调用时,方法内部的this指向document。当用getId来引用document.getElementById,再调用getId时,这种情况就是一个普通函数的调用,函数内部的this指向window而非document,所以报错。解决这个问题需要正确设置this的指向,如下代码所示。
<!--方法1-->
<div id="d1"></div>
<script>
var getId = document.getElementById;
var div = getId.call(document,'d1');
</script>
<!--方法2-->
<div id="d1"></div>
<script>
var getId = document.getElementById.bind(document);
var div = getId("d1");
</script>
getElementsByTagName()
根据标签名获取dom元素节点,返回结果是一个HTMLCollection集合(返回结果具有实时性)。该方法是dom元素选择器目前最主流的方法,在所有浏览器中都可以使用(可以兼容到ie4)。该方法的参数可以是通配符*,表示选取所有标签。该方法作用于文档节点和元素节点。
<div id="demo"></div>
<script>
var divs = document.getElementsByTagName("div");
var div0 = divs[0]; //<div id="demo"></div>
var div1 = divs.item(0); //<div id="demo"></div>
</script>
<div id="name"></div>
<script>
var div = document.getElementsByTagName("div");
var newDiv = document.createElement('div');
document.body.appendChild(newDiv);
console.log(div); //HTMLCollection(2) [div#name, div], 数据会实时更新
</script>
<div>
<span>123</span>
</div>
<span>456</span>
<script>
var div = document.getElementsByTagName("div")[0];
var span = div.getElementsByTagName("span")[0]; //选取div下面的span
console.log(span); //<span>123</span>
</script>
getElementsByClassName()
根据标签class获取dom元素节点。返回结果是一个HTMLCollection集合(返回结果具有实时性)。该方法接收一个参数,参数是个包含一个或多个class类名的字符串(class类名之间用空格间隔)。当传入的参数只包含一个class类名时,所有包含该class类名的标签都会被识别。当传入的参数中包含多个类名时,只能识别同时满足所有class类名的标签(类名的先后顺序不重要)。ie8及以下版本的浏览器中不兼容。该方法作用于文档节点和元素节点。
<div class="jpf0 jpf1"></div>
<div class="jpf0"></div>
<div class="jpf1"></div>
<script>
//HTMLCollection [div.jpf0.jpf1]
var div0 = document.getElementsByClassName("jpf0 jpf1");
//HTMLCollection [div.jpf0.jpf1]
var div1 = document.getElementsByClassName("jpf1 jpf0");
//HTMLCollection(2) [div.jpf0.jpf1, div.jpf1]
var div2 = document.getElementsByClassName("jpf1");
</script>
<div class="c1">
<span class="c2">123</span>
</div>
<span>456</span>
<script>
var div = document.getElementsByClassName("c1")[0];
var span = div.getElementsByClassName("c2")[0]; //选取div下面的span
console.log(span); //<span>123</span>
</script>
getElementsByName()
根据标签name获取dom元素节点,返回结果是一个HTMLCollection集合(返回结果具有实时性)。该方法在ie9及以下版本的浏览器中有两个bug,其一只有部分标签生效(如表单、表单元素、img、iframe),其二标签的id特性也会被当作name特性识别,因此最好不要把id和name设置为相同的值。该方法不推荐使用。该方法作用于html文档节点。
三、selector选择器
为了实现更多功能,html5对dom进行了扩展,其中很重要的一个拓展就是对选择器API的扩展。新增加了2种selector选择器,分别是querySelector()和querySelectorAll(),它们可以通过css选择器直接查询dom文档并取得元素引用,解析和树查询操作均在浏览器内部通过编译后的代码完成,极大简化了元素查询操作。
querySelector()
根据css选择器检索标签,接收一个参数即css选择器,返回匹配的第一个标签对应的元素节点,如果没有匹配的标签则返回null。该方法可以用于文档节点或元素节点。
<ul class="list">
<li id="l1" title="demo"><li>
</ul>
<script>
//没有匹配的元素,返回null
var u1 = document.querySelector('#demo'); //null
//通过id选择器获取元素
var u2 = document.querySelector('#l1');
//通过class选择器获取元素
var u3 = document.querySelector('.list');
//通过元素加class选择器获取元素
var u4 = document.querySelector('ul.list');
//通过属性选择器获取元素
var u5 = document.querySelector('[title="demo"]');
</script>
<ul class="list">
<li id="l1"><li>
<li id="l2"><li>
</ul>
<script>
var ul = document.querySelector('.list'); //应用于文档节点
var l1 = ul.querySelector('#l1'); //应用于元素节点
</script>
querySelectorAll()
根据css选择器检索标签,接收一个参数即css选择器,返回一个NodeList集合。该方法可以用于文档节点或元素节点。
<div class="d1">0</div>
<div class="d1">1</div>
<div class="d1">2</div>
<script>
var dis0 = document.querySelectorAll('.d2'); //没有匹配的元素,返回NodeList []
var dis1 = document.querySelectorAll('.d1'); //NodeList(3) [div.d1, div.d1, div.d1]
var div0 = dis1 [0]; //<div class="d1">0</div>
var div1 = dis1 .item(1); //<div class="d1">1</div>
</script>
缺陷
兼容性
querySelector和querySelectorAll方法在ie7及以下版本的浏览器中不兼容。
非实时
不具备实时性,其底层实现类似于元素的快照,而非不断对文档进行搜索的动态查询。
<div id="name"></div>
<script>
var div = document.querySelectorAll("div");
var newDiv = document.createElement('div');
document.body.appendChild(newDiv);
console.log(div); //NodeList [div#name], 不会实时更新数据
</script>
参数缺陷
selector选择器被具体元素节点调用时,作为参数的css选择器仍会在整个文档中进行匹配,然后再过滤出结果集,以便返回结果只包含指定元素的后代元素节点。
<div id="wrapper">
<div>1</div>
<div>2</div>
</div>
<div>
<div>3</div>
</div>
<script>
var wrapper = document.getElementById('wrapper');
console.log(wrapper.querySelectorAll('div div'));//NodeList(2) [div, div]
</script>
按照正常理解,控制台应该返回空的NodeList集合,因为id为wrapper的div元素中不存在div嵌套。但控制台实际返回的是NodeList(2) [div, div],这是因为作为参数的css选择器是在整个文档范围内进行匹配的。所以如果出现后代选择器,为了防止该问题,可以在参数中显示的添加当前元素选择器。
<div id="wrapper">
<div>1</div>
<div>2</div>
</div>
<div>
<div>3</div>
</div>
<script>
var wrapper = document.getElementById('wrapper');
console.log(wrapper.querySelectorAll('#wrapper div div')); //NodeList []
console.log(wrapper.querySelectorAll('#wrapper div')); //NodeList(2) [div, div]
</script>
瑕不掩瑜,selector选择器虽然存在缺陷,但是它们的出现极大的简化了查找元素的繁琐操作。