jacascript DOM节点——节点获取与选择器API
前言:这是笔者学习之后自己的理解与整理。如果有错误或者疑问的地方,请大家指正,我会持续更新!
DOM 操作必须等待 HTML 加载完毕之后,才可以获取节点;有两种方法:
- 把 script 标签放到代码的最后;
- 使用 window.onload 事件或者 JQuery 的 ready 事件;
一般情况一个页面响应加载的顺序是,域名解析---加载html---加载js和css---加载图片等其他信息。
window.onload 和 JQuery 的 ready事件的区别:
- window.onload 必须等到页面内包括图片的所有元素加载完毕后才能执行;
- $(document).ready() 是 DOM 结构绘制完毕后(加载图片等信息之前)就执行,不必等到加载完毕;
- window.onload 不能同时编写多个,如果有多个 window.onload 方法,只会执行一个;
- $(document).ready() 可以同时编写多个,并且都可以得到执行;
- $(document).ready(function(){...}) 可以简写成 $(function(){...});
有时候我们需要加载完图片之后在执行JS代码,那么 $(window).load(function(){...}) 可以代替 window.onload;
getElementById()
obj.getElementById(id) 该方法接收一个参数(该元素的id),若找到则返回该元素对象,若不存在则返回 null;
任何HTML元素可以有一个 id 属性,在文档中该值必须唯一;
getElementsByTagName()
obj.getElementsByTagName(tagName) 方法接收一个参数,即要取得元素的标签名,而返回的是包含0或多个元素的类数组对象 HTMLCollection。可以使用方括号语法或 item() 方法来访问类数组对象中的项,length 属性表示对象中元素的数量;
<script type="text/javascript"> //获取body var oBodyA = document.getElementsByTagName('body')[0]; var oBodyB = document.getElementsByTagName('body').item(0); console.log(oBodyA === oBodyB);//true //获取所有元素 var all = document.getElementsByTagName('*'); //chrome和firefox都弹出6 //IE弹出 7 //因为 IE 把<! DOCTYPE html> 文档声明也当成标签 console.log(all.length); </script>
getElementsByName()
obj.getElementsByName(name) 方法会返回带有给定 name 特性的所有元素;一般我们用在表单元素上比较多;
IE9及以下浏览器只支持在表单元素上使用 getElementsByName() 方法;
IE9及以下浏览器中使用 getElementsByName() 方法也会返回id属性匹配的元素。因此,不要将 name 和 id 属性设置为相同的值;
<input type="checkbox" name="test" value="测试" checked="checked"/> <script type="text/javascript"> var oTest = document.getElementsByName('test')[0]; console.log(oTest.value);//测试 console.log(oTest.checked);//true </script>
getElementsByClassName()
HTML5 新增了 getElementsByClassName() 方法;
在 javascript 中 class 是保留字,所以使用 className 属性来保存 HTML 的 class 属性值;
- obj.getElementsByClassName(classaName) 方法接收一个参数,是包含一个或多个类名的字符串,返回带有指定类的所有元素的类数组对象 HTMLCollection。传入多个类名时,类名的先后顺序不重要。与 getElementsByTagName() 类似,该方法既可以用于 HTML 文档对象 document,也可以用于 element 元素对象;
- IE8及以下浏览器不支持 getElementsByClassName();
- 在操作 class 类名时,需要通过 className 属性添加、删除和替换类名。因为 className 是一个字符串,所以即使只修改字符串一部分,也必须每次都设置整个字符串的值。要从 className 字符串中删除一个类名,需要把类名拆开,删除不想要的那个,再重新拼成一个新字符串;
classList
- HTML5 为所有元素添加了 classList 属性,这个 classList 属性是新集合类型 DOMTokenList 的实例,它有一个表示自己包含多少元素的 length 属性,而要取得每个元素可以使用 item() 方法,也可以使用方括号法;
- IE9及以下浏览器不支持 classList 属性;
classList 还有以下4个方法,我们主要用这些方法操作类名,有了 classList 属性,className 属性基本没有什么用武之地了:
- obj.classList.add(value); 将给定的字符串值添加到列表中,没有返回值,如果值已存在,则不添加;
- obj.classList.contains(value); 表示列表中是否存在给定的值,如果存在则返回true,否则返回false;
- obj.classList.remove(value); 从列表中删除给定的字符串,没有返回值;
- obj.classList.toggle(value); 如果列表中已经存在给定的值,删除它并返回false;如果列表中没有给定的值,添加它并且返回true;
<div class="test abc"></div> <script> var oTest = document.getElementsByClassName('test')[0]; var oTestAbc = document.getElementsByClassName('test abc')[0]; var oAbc = document.getElementsByClassName('abc')[0]; console.log(oTest === oTestAbc);//true console.log(oAbc === oTestAbc);//true console.log(oAbc === oTest);//true console.log(oTest.classList);//["test", "abc", value: "test abc"] console.log(oTest.classList[0]);//"test" console.log(typeof oTest.classList[0]);//"string" console.log(oTest.classList.item(0));//"test" //add()将给定的字符串值添加到列表中,没有返回值,如果值已存在,则不添加; oTest.classList.add('def'); console.log(oTest.classList);//["test", "abc", "def", value: "test abc def"] //contains()表示列表中是否存在给定的值,如果存在则返回true,否则返回false; console.log(oTest.classList.contains('def'));//true console.log(oTest.classList.contains('abcde'));//false //remove()从列表中删除给定的字符串,没有返回值; oTest.classList.remove('abc'); console.log(oTest.classList);//["test", "def", value: "test def"] //toggle()如果列表中已经存在给定的值,删除它并返回false;如果列表中没有给定的值,添加它并且返回true; console.log(oTest.classList.toggle('hello'));//true console.log(oTest.classList);//["test", "def", "hello", value: "test def hello"] console.log(oTest.classList.toggle('test'));//false console.log(oTest.classList);//["def", "hello", value: "def hello"] </script>
选择器API
HTML5 拓展了 querySelector()、querySelectorAll() 和 matchesSelector() 这3种方法,通过 CSS选择器 查询DOM文档取得元素的引用的功能变成了原生的API,解析和树查询操作在浏览器内部通过编译后的代码来完成,极大地改善了性能。
- obj.querySelector(selector) 方法接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null。该方法既可用于文档 document 类型,也可用于元素 element 类型。IE7及以下不支持。
- obj.querySelectorAll(selector) 接收一个CSS选择符,返回一个类数组对象,如果没有匹配元素,返回空的类数组对象,而不是null;IE7及以下不支持;
- obj.matchesSelector(selector) 方法接收一个CSS选择符参数,如果调用元素与该选择符相匹配,返回true;否则返回false;
- obj.matchesSelector(selector) 有兼容性问题,IE9+浏览器支持 msMatchesSelector() 方法,firefox 支持 mozMatchesSelector() 方法,safari 和 chrome 支持 webkitMatchesSelector() 方法。
<div id="wrapper"> <ul class="box"> <li class="no1">第一行</li> <li class="no2">第二行</li> <li class="no3">第三行</li> <li class="no4">第四行</li> <li class="no5">第五行</li> </ul> </div> <script type="text/javascript"> var oWrapper = document.querySelector('#wrapper'); var oUl = oWrapper.querySelector('ul'); var oLiNo1 = oWrapper.querySelector('.no1'); //obj.querySelector(selector) 方法接收一个CSS选择符,返回与该模式匹配的第一个元素, var oLiFirst = oWrapper.querySelector('li'); var oFirstLi = oWrapper.querySelector('ul > li'); console.log(oLiNo1 === oLiFirst);//true console.log(oLiNo1 === oFirstLi);//true console.log(oLiFirst === oFirstLi);//true console.log(oLiNo1.innerHTML , oLiFirst.innerHTML , oFirstLi.innerHTML);//第一行 第一行 第一行 //obj.querySelectorAll(selector) 接收一个CSS选择符,返回一个类数组对象 var oWrapperAll = document.querySelectorAll('#wrapper'); console.log(oWrapperAll);//[div#wrapper] console.log(oWrapperAll[0] === oWrapper);//true var oWrapperArray = oWrapperAll[0]; var oLiFirstAll = oWrapperArray.querySelectorAll('li'); var oLiFirstArrayNo1 = oWrapperArray.querySelectorAll('li')[0]; console.log(oLiFirstArrayNo1 === oLiNo1);//true console.log(oLiFirstAll[1].innerHTML);//第二行 // console.log(oWrapperArray.matchesSelector('#wrapper')); //TypeError: oWrapperArray.matchesSelector is not a function console.log(oWrapperArray.webkitMatchesSelector('#wrapper'));//true //obj.matchesSelector(selector) 有兼容性问题, //IE9+浏览器支持 msMatchesSelector() 方法, //firefox 支持 mozMatchesSelector() 方法, //safari 和 chrome 支持webkitMatchesSelector() 方法。 </script>
选择器API使用时,需要注意的是:
- querySelectorAll() 方法得到的类数组对象是非动态实时的,所以如果要计算长度等的实事值,最好重新获取;当然以前的 getElementById() 之类的就没这个毛病;
- selector 类方法在元素上调用时,指定的选择器仍然在整个文档中进行匹配,然后过滤出结果集,以便它只包含指定元素的后代元素。这看起来是违反常规的,因为它意味着选择器字符串能包含元素的祖先而不仅仅是所匹配的元素;所以如果出现后代选择器,为了防止该问题,可以在参数中显式地添加当前元素的选择器;
<div id="wrapper"> <ul class="box"> <li class="no1">第一行</li> <li class="no2">第二行</li> <li class="no3">第三行</li> <li class="no4">第四行</li> <li class="no5">第五行</li> </ul> </div> <script type="text/javascript"> var oWrapper = document.querySelector('#wrapper'); var oUl = oWrapper.querySelector('ul'); var oLiLast = oUl.querySelector('li:last-of-type'); var oLiAll = oUl.querySelectorAll('ul > li'); console.log(oLiLast.innerHTML);//第五行 console.log(oLiAll.length);//5 var newLi = document.createElement('li'); newLi.innerHTML = '新加的Li,放到最后面'; oUl.appendChild(newLi); //querySelectorAll() 方法得到的类数组对象是非动态实时的; console.log(oLiLast.innerHTML);//第五行 console.log(oLiAll.length);//5 console.log(oUl.querySelector('li:last-of-type').innerHTML);//新加的Li,放到最后面 console.log(oUl.querySelectorAll('ul > li').length);//6 </script> <div class="wrapper"> <div class="test1"></div> <div class="test2"></div> </div> <script type="text/javascript"> var oWrapper = document.querySelector('.wrapper'); //selector 类方法在元素上调用时,指定的选择器仍然在整个文档中进行匹配,然后过滤出结果集,以便它只包含指定元素的后代元素。 //这看起来是违反常规的,因为它意味着选择器字符串能包含元素的祖先而不仅仅是所匹配的元素 console.log(oWrapper.querySelectorAll('div div'));//[div.test1, div.test2] //这句代码我的理解是获取oWrapper内部子孙元素中,div里嵌套的div,这里没有这种情况,所以应该弹出一个空数组 //如果出现后代选择器,为了防止该问题,可以在参数中显式地添加当前元素的选择器 console.log(oWrapper.querySelectorAll('.wrapper div div'));//[] console.log(oWrapper.querySelectorAll('.wrapper div'));//[div.test1, div.test2] </script>