DOM操作的一个小坑
最近在苦读《JavaScript高级程序教程》,真不愧是前端圣经,学到了很多东西。
nodeList、NameNodeMap、HTMLCollection这三个集合是动态的!每当文档发生变化,它们都会得到更新。因此,它们始终保存着最新、最准确的信息。
在DOM这段遇到一个有意思的例子:
例子1: 增加内容
这个例子首先获取div,然后在一个for循环中,往body追加新的div元素。结果会一直追加。
第一个行代码会获取文档中所有<div>元素的HTMLCollection。这个集合是动态的。所以,只要有新的<div>元素被添加到页面中,这个元素也同时添加到
HTMLCollection中。而for循环每次都要对这个集合进行重新求值。所以就会出现这个有趣的例子。
<body> <div></div> <script> // 获取div let myDiv = document.getElementsByTagName('div'); for (let i = 0; i < myDiv.length; i++) { console.log(myDiv); let div = document.createElement('div'); document.body.appendChild(div); // 为防止陷入死循环,这里设置一下 if (myDiv.length === 10) { break; } } </script> </body>
改进1、
将length赋予一个变量。
<body> <div></div> <script> // 获取div let myDiv = document.getElementsByTagName('div'); // 改进 for (let i = 0,len = myDiv.length; i < len; i++) { console.log(myDiv); let div = document.createElement('div'); document.body.appendChild(div); // 为防止陷入死循环,这里设置一下 if (myDiv.length === 10) { break; } } </script> </body>
改进2、
使用 querySelectorAll('div') 代替 getElementByTagName('div')
querySelectorAll()方法是DOM扩展里的方法,这个方法返回的是一个Nodelist实例,但是,返回的值实际上是带有所有属性和方法的NodeList,而底层实现类似于一组元素的快照,而非不断对文档进行搜索的动态查询,所以可以避免使用Nodelist对象通常引起的问题。
这两个返回结果都是一样的。
说完了增加,在看一下减少的问题
例二、
需求:现在我想把同时有 username 和 current 两个类名的标签,去掉其中的current类名。
按理说最后应该要输出三个div 每个div标签有一个类名 username
<body> <div class="username current"></div> <div class="username current"></div> <div class="username current"></div> <script> // 获取 let userNames = document.getElementsByClassName('username current'); // 注意这里,把len赋予一个变量 for(let i = 0,len = userNames.length; i < len; i++){ userNames[i].classList.remove('current'); } </script> </body>
事实上是这样子的
以及这样子的
这是因为,把userNames的长度赋予一个变量导致的问题。len = 3;然后再for循环中,
第二次for循环的时候,i 的值为1,但是这时的userNames的数组长度是2。
因为第一次循环的时候已经把第一个div元素的current类去除了。
所以第二次循环时,remove的是最后一个div的类。
当第三次时,i为2, userNames的长度为1.。 所以这时取得的值为undefined,而undefined是基本数据类型,不能转为对象,理应没有方法。也就导致了语法错误。
改进1、
<script> // 获取 let userNames = document.getElementByClassName('username current'); // 改进 for(let i = 0;i < userNames.length; i++){ userNames[i].classList.remove('current'); } </script>
改进2、
<script> // 获取 // 改进 let userNames = document.querySelectorAll('.username.current'); // 注意这里,把len赋予一个变量 for(let i = 0,len = userNames.length; i < len; i++){ userNames[i].classList.remove('current'); } </script>