在以前,要使用JavaScript来操作DOM节点的class属性比较麻烦,很多时候都要借助第三方js库。但html5新增的classList对象使这一操作变得简便多了,而且这个对象已经实现了五六年了,浏览器兼容性也比较好。(IE从IE10开始支持,其他浏览器支持得更好)
在html5中,每个DOM节点都有个classList对象,我们可以借助该对象的方法、属性来便利的操作节点的class属性。
浏览器能力检测:
"classList" in document.createElement("a"); // in 操作符用于检测索引是否在该数组中,或属性是否在该对象中。判断的是key不是value
classList对象的属性和方法如下:
element.classList.length // 返回节点的class数量 element.classList.value // 返回节点的所有class名,等价于element.className element.classList.add(string) // 给节点添加class。示例: document.body.classList.add("c1"); // 添加一个class document.body.classList.add("c1","c2","c3"); // 添加多个class element.classList.remove(string) // 从节点删除class,语法同add() element.classList.toggle(string) // 切换添加/删除class。如果不存在该class则添加,否则删除 // 如果执行的是添加操作则返回true,如果执行的是删除操作则返回false // toggle方法可以有第二个参数,根据第二个参数的结果是true还是false来添加/删除该class element.classList.contains(string) // 检查节点是否含有指定的class element.classList.item(number) // 返回指定索引的class的名字 // 其实这个方法比较麻烦,一般情况下我们可以直接在element.classList后面用序号查询。如下操作是等价的: document.body.classList[0]; document.body.classList.item(0); // 区别在于如果参数指定的class不存在,它们的返回值不同 document.body.classList[1000]; // undefined document.body.classList.item(1000); // null
使用html5的classList对象操作DOM节点的class
如果我们要删除一个DOM节点,可能大家都会想到remove方法。如下:
var a=document.createElement("a"); // 设置内容等代码 ... a.parentNode.removeChild(a);
Node.removeChild() 方法从DOM中删除一个子节点。返回删除的节点。
从返回值是个节点我们可以知道,removeChild之后,这个节点虽然在DOM里去掉了,但是它仍然存在在内存里。
虽说过一段时间不用,它就会被浏览器回收掉,但如果要重复的创建这个节点的话,那么每次removeChild时使用delete操作符,可以略微优化内存占用(大概……)。
如下:
var a=document.createElement("a"); // 设置内容等代码 ... delete a.parentNode.removeChild(a);
今天我在chrome上做了多次实验,有一些发现:
1.使用delete之后,chrome浏览器并不会立即回收这部分内存,而是等差不多二十秒之后才回收。
2.使用delete之后,内存回收的比只remove要多一些。
3.即使使用delete,内存也不能完全回收,内存占用还是会一直增加。只是情况略有缓解。
4.有人说delete回收内存只能回收由JavaScript创建的节点,如果是原本html文档里的节点,delete是回收不了的。我试了试,对于原本html文档里的节点,用delete和只用remove没看出明显区别,大概这个说法是对的。
JavaScript回收DOM节点的内存
以往我们插入、移动DOM元素经常是使用appendChild和insertBefore方法。
appendChild:在父级元素内追加新元素。 insertBefore:在父级元素内的某个元素之前插入新元素。
但是这两个方法的参数只能接收元素对象,不能使用字符形式的html代码,而且它们插入元素的位置也不够灵活。我们可以使用insertAdjacentHTML方法来更方便的插入元素。
insertAdjacentHTML可以将字符串形式的html代码(需要能解析为DOM元素)解析为一个节点,并将其追加到指定元素的指定位置。
insertAdjacentHTML方法的语法如下:
element.insertAdjacentHTML(position, text);
position参数有以下四个值(都是字符串形式):
beforebegin:在元素的开始位置之前插入。 beforeend:在元素的结束位置之前插入。 afterbegin:在元素的开始位置之后插入。 afterend:在元素的结束位置之后插入。
text参数则是字符串形式的html代码。
根据position参数,我们可以将新元素插入到到指定元素的四个位置:
示例:
<div id="a"> <div></div> </div> <script type="text/javascript" defer> var a=document.querySelector("#a"); a.insertAdjacentHTML("afterbegin","<a href='' >xxx</a"); </script>
结果如下:
<div id="a"> <a href="">xxx</a> <div></div> </div>
insertAdjacentHTML方法的兼容性表现良好,主流浏览器均已支持。我们也可以如下语句来检查浏览器是否支持方法:
document.documentElement.insertAdjacentHTML
此外,由于insertAdjacentHTML是根据位置插入元素的,因此它不能把新元素插入到img、input等单标签元素里(想这么做的人才是有毛病吧)。
相关文档:《https://developer.mozilla.org/zh-CN/docs/Web/API/Element/insertAdjacentHTML》
ps:与insertAdjacentHTML系列“同一系列”的还有insertAdjacentElement方法和insertAdjacentText方法。
insertAdjacentElement方法除了第二个参数是DOM节点(不能是字符串形式)外和insertAdjacentHTML方法都一样。
insertAdjacentText方法则只接收字符串格式的参数,并输出为字符串。其他地方也和insertAdjacentHTML方法一样。
使用js的insertAdjacentHTML方法插入元素
昨天发表的那个网站地图助手里,有几个输入框都需要在鼠标经过时自动选中其中的内容。
实现起来没有难度,但类似于getElementBy...这样的选择器难以在不写重复代码的情况下选中几个不同id的元素。所以我的代码写成了这样:
document.getElementById("a").onmouseover=function (argument) { this.select(); } document.getElementById("b").onmouseover=function (argument) { this.select(); } document.getElementById("y").onmouseover=function (argument) { this.select(); } document.getElementById("c").onmouseover=function (argument) { this.select(); }
感觉这样实在无法见人,于是去贴吧求助。终于知道了一个好办法:js现在有了一个原生的querySelectorAll方法,可以接受一组css选择器风格的字符串来作为选择器(这点和jQuery很像),如下:
document.querySelectorAll('#a,#b,#c,#y');
这样就解决了重复获取元素的问题了。querySelectorAll简直是一个福音啊。
querySelectorAll和querySelector是HTML5中新增的属性,但是IE8也支持。所以放心的用吧~
由于我们是无法对一个元素集合直接添加事件的,只能用循环来加了(所以jQuery用起来还是更方便啊)。使用for循环就可以,forEach也可以(使用forEach更有逼格?)。不过元素集合并不是数组,要使用forEach的话需要借用数组的属性。于是最后的代码如下:
function selectS(s){ return document.querySelectorAll(s); } [].forEach.call(selectS('#a,#b,#c,#y'),function(e){ e.onmouseover=function (argument) { this.select(); } });