JS 进阶(5) DOM操作:dom加载完毕执行js、创建节点、遍历节点、查找节点、删除节点

本文详细介绍了JavaScript中DOM操作的各个方面,包括DOM加载完毕后的执行时机、如何创建、遍历、查找和删除节点。讲解了如jQuery的$(document).ready()和window.onload的区别,以及document.createElement、innerHTML、innerText等创建节点的方法。此外,还讨论了遍历节点的不同方式,如节点树、元素树和NodeList、HTMLCollection等,并讲解了不同浏览器环境下getElementsByClassName、querySelector、querySelectorAll等查找节点方法的使用和兼容性问题。最后,探讨了appendChild、insertBefore、replaceChild等插入和删除节点的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、dom加载完毕执行js

dom可以看成一个树形结构,dom的加载顺序就是从上到下,我们一再强调将js文件放在尾部,就是因为如果js脚本在dom文档构造之前执行,这样js就无法访问dom文档对象模型。

1.1 jquery

  • 等待页面dom树加载完毕,再执行代码
写法一:标准写法
$(document).ready(function(){
	...
});

写法二:简写
$(function(){
	....
})
两种写法是等价的
  • 等待页面所有资源(包括css样式表、dom树、图片、第三方框架)加载完毕,再执行代码
$(window).load(function(){
	...
});

总结:也就是说$(function(){...})会比$(window).load(function(){...})先执行


1.2 js

  • onload事件:等待页面所有资源(包括dom树、图片、第三方框架)加载完毕,再执行代码
window.onload = function(){
	...
}

  • DOMContentLoaded 事件:等待页面dom树加载完毕,再执行代码
    jquery中使用的$(document).ready(function(){});实际上监听的就是 DOMContentLoaded 事件。
function domReady(fn){
    //对于现代浏览器,对DOMContentLoaded事件的处理采用标准的事件绑定方式
    if ( document.addEventListener ) {
        document.addEventListener("DOMContentLoaded", fn, false);
    } else {
        IEContentLoaded(fn);
    }
    //IE模拟DOMContentLoaded
    function IEContentLoaded (fn) {
        var d = window.document;
        var done = false;
        //只执行一次用户的回调函数init()
        var init = function () {
            if (!done) {
                done = true;
                fn();
            }
        };

        (function () {
            try {
                // DOM树未创建完之前调用doScroll会抛出错误
                d.documentElement.doScroll('left');
            } catch (e) {
                //延迟再试一次~
                setTimeout(arguments.callee, 50);
                return;
            }
            // 没有错误就表示DOM树创建完毕,然后立马执行用户回调
            init();
        })();

        //监听document的加载状态
        d.onreadystatechange = function() {
            // 如果用户是在domReady之后绑定的函数,就立马执行
            if (d.readyState == 'complete') {
                d.onreadystatechange = null;
                init();
            }
        }
    }
}

二、创建节点

  • 普通创建节点

    1. 创建新的元素节点:document.createElement(‘元素名’)
    2. 创建新的文本节点:document.createTextNode(‘文本内容’)
    3. 创建新的片段节点:document.createDocumentFragment()
    4. 创建新的注释节点:document.createComment(‘注释’)
  • 高效创建节点

    1. innerHTML
    2. outerHTML
    3. innerText
    4. outerText
方法名说明
document.createElement(‘元素名’)创建新的元素节点
document.createTextNode(‘文本内容’)创建新的文本节点
document.createComment(‘注释’)创建新的注释节点
document.createDocumentFragment()创建新的片段节点
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .li{list-style:none;height:50px;line-height:50px;width:100px;background-color:lightblue;text-align:center;}
  </style>
</head>
<body>
    <script>
    (function(){
    	var ulEle = document.createElement('ul');
    	for(var i=0; i<3 ; i++){
			var liEle = document.createElement('li');
    		liEle.className = 'li';    		
    		liEle.innerHTML = '第'+i+'个li';
    		ulEle.appendChild(liEle);
    	}
    	document.body.appendChild(ulEle);
    })();
    </script>
</body>
</html>
  • 高效创建节点
    当要创建的大批量的节点,使用createElement这类的方法创建节点就非常麻烦。
方法说明
innerHTML用来设置或获取当前标签的起始和结束里面的内容,在读模式下返回与调用元素的所有节点包括元素节点、注释节点、和文本节点对应的HTML标记;而在写模式下innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树安全替换调用元素原先的所有子节点。
outerHTML返回调用它的元素及所有子节点的HTML标签

在写模式下会根据指定的HTML字符串创建新的outer指数,然后用outer指数完全替换调用的元素


2.1 document.createElement

该方法创建的 HTML5标签 是可以兼容IE8以下的浏览器,并在页面中正常显示该标签所设置的样式;参数可以是大小也可以是小写,但是多数情况下建议使用小写。

	var ulEle = document.createElement('ul');
    var liEle = document.createElement('li');	

解决HTML5新元素不被IE6-8识别

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <style>
      /*html5*/
      article {
        font-size: 40px;
        color: red;
      }
    </style>
    <script> 
      (function() {
        if (! 
        /*@cc_on!@*/
        0) return;
        var e = "abbr, article, aside, audio, canvas, datalist, details, dialog, eventsource, figure, footer, header, hgroup, mark, menu, meter, nav, output, progress, section, time, video".split(', ');
        var i = e.length;
        while (i--){
          document.createElement(e[i]);
        }
      })();
    </script>
  </head>
  <body>
    <article>
      You are my sunshine.
    </article>
  </body>
</html>

2.5 innerHTML

用来设置或获取当前元素里面的所有子节点。

innerHTML有两种模式

  • 读模式
    在读模式下返回调用元素下的所有节点包括元素节点、注释节点、和文本节点对应的HTML标记;
    <div id="content">
    	苟利国家生死以
    	<p>This is a <strong>paragraph</strong> with a list following it.</p>
    	<ul>
    		<li>Item1</li>
    		<li>Item2</li>
    		<li>Item3</li>
    	</ul>
    </div>
    <script type="text/javascript">
    	var content = document.getElementById("content");
    	console.log(content.innerHTML);
    </script>

在这里插入图片描述

  • 写模式
    写模式下innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树 完全替换 调用元素原先的 所有 子节点。
   <div id="content">
   		<p>苟利国家生死以</p>
   </div>
   <script>
       var content = document.getElementById("content");
       var str = "<p>This is a <strong>paragraph</strong> with a list following it.</p>"
                   + "<ul>"
                   + "<li>Item 1</li>"
                   + "<li>Item 2</li>"
                   + "<li>Item 3</li>"
                   + "</ul>";
       content.innerHTML = str;
   </script>

在这里插入图片描述


2.6 outerHTML

用来设置或获取调用它的元素及所有子节点。

两种模式

  • 读模式
    读取包括调用元素以及调用元素下的所有子节点。
    <div id="content">
    	苟利国家生死以
    	<p>This is a <strong>paragraph</strong> with a list following it.</p>
    	<ul>
    		<li>Item1</li>
    		<li>Item2</li>
    		<li>Item3</li>
    	</ul>
    </div>
    <script type="text/javascript">
    	var content = document.getElementById("content");
    	console.log(content.outerHTML);
    </script>

在这里插入图片描述

  • 写模式
    用新的dom树,完全替换 包括调用元素以及调用元素下的所有节点。
    <div id="content">
    </div>
    <script>
        var content = document.getElementById("content");
        var str = "<p>This is a <strong>paragraph</strong> with a list following it.</p>"
                    + "<ul>"
                    + "<li>Item 1</li>"
                    + "<li>Item 2</li>"
                    + "<li>Item 3</li>"
                    + "</ul>";
        content.outerHTML = str;
    </script>

在这里插入图片描述


2.7 innerText

读取元素中的所有子节点中的文本或者用文本内容替换所有子节点。

  • 读模式
    只读取文本,去掉所有HTML标签。
    <div id="content">
      <p>This is a <strong>paragraph</strong> with a list following it.</p>
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </div>
    <script>
        var content = document.getElementById("content");
        console.log(content.innerText);
    </script>

在这里插入图片描述

  • 写模式
    使用文本替换调用元素下的所有子节点。
    <div id="content">
      <p>This is a <strong>paragraph</strong> with a list following it.</p>
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </div>
    <script>
        var content = document.getElementById("content");
        content.innerText = "<p>This is a paragraph.</p>";
    </script>

在这里插入图片描述

firefox哪个版本都不支持innerText属性

解决办法在火狐浏览器下使用textContent代替innerText

兼容firefox和chrome的写法

    var content = document.getElementById("content");
    function getInnerText(element){
      return (typeof element.textContent == "string") ? element.textContent : element.innerText;
    }
    function setInnerText(element, text){
      if (typeof element.textContent == "string"){
        element.textContent = text;
      } else {
        element.innerText = text;
      }
    }
    
    setInnerText(content, "Hello world!");
    console.log(getInnerText(content));

2.8 outerText

功能与outerText类似,只不过内容变成了文本。

不建议使用



三、遍历节点

遍历节点浏览器提供了API

  • documentElement 返回文档HTML这个·节点
    在这里插入图片描述

  • 节点树(节点包括:html元素,文本,注释等)

  • 元素树: 仅包含元素节点的树结构


3.1 节点树

在这里插入图片描述
在这里插入图片描述
该方法遍历有一个问题,标签直接的空格也算是一个节点。
在这里插入图片描述

在这里插入图片描述

遍历dom数需要判断当前节点是否问元素

语法: node.nodeType 属性返回节点的类型。
兼容:所有主流浏览器都支持。

节点类型描述返回值
element元素1
attr属性2
text文本3
comment注释8
document代表整个文档(dom树的根节点)9

遍历节点树

      var str = '';
      function travel(space, node){
        if(node.nodeType == 1){		需要判断当前节点是否为元素
          str += space + node.tagName +"<br/>";
        }
        for(var i=0, len=node.childNodes.length; i<len ; i++){
          arguments.callee(space+'|-', node.childNodes[i]);
        }
      }

      travel('',document);
      document.write(str);

3.2 元素树(推荐使用)

在这里插入图片描述

      var str = '';
      function travel(space, node){
        str += space + node.tagName + '<br/>';
        for(var i=0, len=node.childElementCount ; i<len ; i++){
          arguments.callee(space+'|-', node.children[i]);
        }
      }

      travel('',document);
      document.write(str);

3.3 类数组对象 NodeList(节点集合)

NodeList对象是节点的集合。

在节点树中通过childNodes获取到的就是是一个类数组对象NodeList

  • NodeList用于保存一组有序的节点
  • 可以通过方括号来访问NodeList的值,有item方法和length属性
  • 不是Array实例,没有数组对象的方法

如果要进行操作,可以将NodeList先转换为数组。

案例:将类数组对象转换为数组

    <ul id="box">  
      <li>节点一</li>
      <li>节点二</li>
      <li>节点三</li>  
    </ul>
    
    <script>
        var box = document.getElementById("box");
        var nodes = box.childNodes;

        function makeArray(nodeList){
          var arr = null;
          try {	
            return Array.prototype.slice.call(nodeList);	IE不支持该方法。
          }catch (e){
            arr = new Array();
            for(var i = 0, len = nodeList.length; i < len; i++){
              arr.push(nodeList[i]);
            }
          }
          return arr;
        }

        var newNodeList = makeArray(nodes);
        newNodeList.push("<li>节点四</li>");
        console.log(newNodeList);
        
    </script>

3.4 类数组对象 HTMLCollection(HTML元素集合)

以下操作会返回HTMLCollection类数组对象

  • Ele.getElementsByTagName()
  • document.scripts
  • document.links
  • document.images
  • document.forms
  • select.options
  <div id="div">
    <p>
      <span>
        <a href="">1</a>
        <a href="">2</a>
        <a href="">3</a>
      </span>
      <span>
        <a href="">4</a>
        <a href="">5</a>
        <a href="">6</a>
      </span>
      <span>
        <a href="">7</a>
        <a href="">8</a>
        <a href="">9</a>
      </span>
    </p>
  </div>
    <script>
      var spanEle = document.getElementsByTagName('span');
      console.log(spanEle);
    </script>

在这里插入图片描述

nameItem() 方法

HTMLCollection对象的namedItem()方法,返回集合中具有指定name属性或id属性的第一个元素。


3.5 类数组对象 NameNodeMap (元素属性集合)

  • ele.attributes
     var div = document.getElementById('div');
     console.log(div.attributes);

在这里插入图片描述


四、查找节点

IE6~IE8和最新浏览器都可以使用:

  • getElementById() 必须通过document调用,只返回单个对象
  • getElementsByName() 必须通过document调用
  • getElementsByTagName()

最新浏览器可以使用:

  • getElementsByClassName()
  • querySelector()
  • querySelectorAll()

4.1 getElementById()的bug

在低版本IE浏览器中document.getElementById()会获取到指定name属性的值。

	<span name="target">错误的</span>
	<div id="target">正确的</div>
	<script>
		var divEle = document.getElementById('target'); 
		获取到的是<span name="target">错误的</span>
	</script>

修复bug

var getElementById = function(id) {
   var el = document.getElementById(id);
   if(!+"\v1") {		
     if(el && el.id === id) {
       return el;
     } else {
       var els = document.all[id],
           n = els.length;
       for (var i = 0; i < n; i++) {
         if (els[i].id === id) {
           return els[i];
         }
       }
     }
   }
   return el;
 };

!+"\v1":通过各个浏览器对转义字符不同的处理来判断是否为ie浏览器。

( !+"\v1" ) IE中:\v无转义,识别为v,+"\v1"转换数字失败,得到NaN,!表示非,最后解析为true。
其他浏览器,\v转义,类似空格,转换数字后得到1,转非解析为false,不执行后面的代码。


4.2 getElementsByTagName()

  • 通过getElementsByTagName()获取到的是类数组对象
  • document.getElementsByTagName()或者element.getElementsByTagName()都可以。
  • document.getElementsByTagName('*')可以获得文档中所有的元素。
  • document.getElementsByTagName('!')可以获得文档中所有的注释。

4.3 getElementsByClassName()

该方法返回的是一个类数组对象HTMLCollection。
getElementsByClassName可以传入多个类名,类名之间用空格隔开。

    <ul id="myUl">
      <li class="light">1</li>
      <li class="dark light">2</li>
      <li class="light">3</li>
    </ul>
    <script>
        var ul = document.getElementById('myUl');

        var lis1 = ul.getElementsByClassName('light');
        var lis2 = ul.getElementsByClassName('light dark');
        var lis3 = ul.getElementsByClassName('dark light');
        console.log(lis1);
        console.log(lis2);
        console.log(lis3);
    </script>

在这里插入图片描述

兼容IE8以及以前的浏览器和现在主流浏览器

var getElementsByClassName = function(opts) {
	var searchClass = opts.searchClass; // 存储要查找的类名
	var node = opts.node || document;  // 存储要出查找的范围
	var tag = opts.tag || '*'; // 存储一定范围内要查找的标签
	var result = [];
		// 判断浏览器支不支持getElementsByClassName方法
	if (document.getElementsByClassName) { // 如果浏览器支持
		var nodes = node.getElementsByClassName(searchClass);
		if (tag !== "*") {
			for (var i = 0; node = nodes[i++];) {
				if (node.tagName === tag.toUpperCase()) {
					result.push(node);
				}
			}
		} else { 
			result = nodes;
		}
		return result;
	} else { // 使用IE8以下的浏览器能够支持该属性
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var i, j;
		var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
		//或者利用单词边界 var pattern = new RegExp("\\b" + searchClass + "\\b");
		for (i = 0, j = 0; i < elsLen; i++) {
			if (pattern.test(els[i].className)) { // 检测正则表达式
				result[j] = els[i];
				j++;
			}
		}
		return result;
	}
}

4.4 querySelector() 和 querySelectorAll()

  • 主流浏览器都支持,IE8是率先支持的。。。
  • 传入的选择器值要符合CSS规则。
  • 可以通过document调用,也可以通过element调用。
  • querySelector()找不到元素返回null。
  • querySelectorAll() 找不到元素返回空的集合

querySelector() 返回一个元素,如果有多个返回第一个。

    <input type="text" class="foo:bar" value="请输入内容" />
    <div id="myDiv">
      You are my sunshine.
      <ul id="myUl">
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
      <script type="text/javascript">
        var divEle = document.querySelector('#myDiv');
        console.log(divEle);

        var liEle = divEle.querySelector('ul#myUl>li');
        console.log(liEle);
      </script>

在这里插入图片描述

querySelectorAll() 返回元素集合

    <div id="myDiv">
      You are my sunshine.
      <ul id="myUl">
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
    </div>
      <script type="text/javascript">
        var liEle = document.querySelectorAll('ul#myUl>li');
        console.log(liEle);
      </script>

在这里插入图片描述

querySelectorAll()返回的是一个静态的NodeList对象,而getElementsByClassName()和getElementByTagName()返回的是动态NodeList对象。

静态NodeList

  <body>
    <div></div>
    <div></div>
    <div></div>
  </body>
  <script>
      var divs = document.querySelectorAll("div");
      var i = 0;
      while(i < divs.length){
        document.body.appendChild(document.createElement("div"));
        i++;
      }
  </script>

正常执行,循环3次插入元素就结束。


动态NodeList

  <body>
    <div></div>
    <div></div>
    <div></div>
  </body>
  <script>
      var divs = document.getElementsByTagName("div");
      var i = 0;
      while(i < divs.length){
        document.body.appendChild(document.createElement("div"));
        i++;
      }
  </script>

会陷入死循环,divs.length的值会一直增长。


五、插入节点

  • appendChild()
  • insertBefore()
  • replaceChild()
  • cloneNode()
  • norrmalize()
  • SplitText()

5.1 appendChild()

在调用元素的最后一个子节点(节点包括文本)后添加节点,该方法返回新的节点。

    <div id="wrap">
      <ul id="myUl">
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
    </div>
      <script type="text/javascript">
        var myUl = document.querySelector('#myUl');
        var txt = document.createTextNode('4');
        var newLi = document.createElement('li');
        newLi.appendChild(txt);
        
        myUl.appendChild(newLi);
      </script>

在这里插入图片描述

5.2 insertBefore()

在调用元素的指定已有的子节点之前插入新节点。

   <ul id="myUl">
     <li>1</li>
     <li>2</li>
     <li>3</li>
   </ul>
   <script>
     var myUl = document.querySelector('#myUl');
     var txt = document.createTextNode('4');
     var newLi = document.createElement('li');
     newLi.appendChild(txt);

     var li2 = myUl.children[1];

     myUl.insertBefore(newLi,li2);
   </script>

在这里插入图片描述

将新的节点插入到子节点最后:模拟appendChild()

   myUl.insertBefore(newLi,null);

将新的节点插入到开头

	myUl.insertBefore(newLi,myUl.firstElementChild);

5.3 replaceChild()

该方法用新节点替换某个子节点。
语法:replaceChild(要插入的节点,被替换的节点)
返回被替换的节点,被替换的节点会被从dom树移除。

5.3 cloneNode()

创建节点的拷贝,并返回该副本

拷贝的节点要有父节点,如果没有父节点,要通过appendChild()、insertBefore()、replaceChild()等方法进行添加。

接收一个参数默认是false,如果为true即深度复制。深度复制会复制子节点。


5.4 norrmalize()

  • 移除空的文本节点,并连接相邻的文本节点

5.5 SplitText()

splitText(offset) 方法按照指定的 offset 把文本节点分割为两个节点

返回新的文本节点


六、删除节点

removeChild():删除某个节点中指定的子节点,一定要有参数

removeNode():IE的私有

将目标节点从文档中删除,返回目标节点
参数布尔值,默认false(true深度删除)
removeChild和removeNode()方法

innerHTML:将值设置为空,就可以删除调用元素下面的子元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值