Home  >  Article  >  Web Front-end  >  JavaScript learning summary [9], DOM Ready

JavaScript learning summary [9], DOM Ready

黄舟
黄舟Original
2017-02-10 09:42:061232browse

1、DOM

## DOM(Document Object Model ) is the document object model, which is abstracted from the document. The object of DOM operation is the document. DOM presents the HTML document as a tree structure with elements, attributes and text, that is, a node tree. Through DOM, JS can create dynamic HTML, which can make web pages display dynamic effects and realize interactive functions with users. DOM provides us with an interface for dynamically controlling HTML using programs (also called API), so DOM is where JS gives HTML toolsBe at the core of dynamic interaction and effect capabilities. If you want to operate DOM safely, you must wait until all HTML in the page is parsed into DOM nodes before you can operate, so we must understand DOMReady. Before that, let’s review the DOM nodes.

 (1) Common node types

 Common node typesThere are the following 7 types:

##< ;!DOCTYPE html> is the document type node. 10DocumentFragment (document fragment node) represents A part or paragraph of a document that does not belong to the document tree. 11

 (2), node type description

 Element node, is an HTML tag element, such as

,

,

    , etc.

     Attribute node, is the attribute of the element node, such as id, class, name, etc. Attribute nodes cannot be regarded as element nodes, so attributes are not considered part of the document tree in the DOM. In other words, the attribute node is part of the element node that contains it, and it is not a separate node in the document. appear in the tree.

     Text node, is a node that only contains text content. It can contain more information or just white space. The text content of elements and attributes in the document tree are represented by text nodes.

     Comment node , is the comment in the document, and its form is .

     Document node , is the entire document, the root node of the document tree, is all other nodes in the document 's parent node. It should be noted here: the document node is not the root element of the HTML document. When constructing the DOM tree, the root element is not suitable as the root node, so there is the document node, and the root element appears as a child node of the document node. Consider the entire HTML document code as a document node. This node contains a document type node and an element node , two child nodes.

     Document type node,Each Document has a DocumentType attribute, is the document type node.

     Document fragment node, is a lightweight or minimal Document object. It represents a part or a paragraph of the document. It does not Belongs to the document tree. But it has a special behavior, which is very useful. For example, when a DocumentFragment node is requested to be inserted into the document, it is not the DocumentFragment itself that is inserted, but all its descendant nodes. At this time, DocumentFragment becomes a useful placeholder to temporarily store the nodes that are inserted into the document in sequence. It is also helpful for cutting, copying, pasting and other operations of the document. Like the variable defined by inserting elements in JS code, this variable only serves as a temporary placeholder. This is called a document fragment node.

     Document fragments are also called document fragments. To create a document fragment, you can use the document.createDocumentFragment() method, which can directly insert n children under the parent node. node. In theory, document fragmentation can improve DOM operation performance. Document fragmentation can greatly improve page performance in low-version browsers, but in advanced browsers, there is almost no performance improvement, and it will also affect performance. Therefore, is not recommended to use . This thing has basically been eliminated. Below is an example of creating a document fragment.

     Example:Insert a document fragment under the ul element


    <body>
    <ul id="listNode"></ul>
    
    <script>
    //创建一个文档碎片
    var frag = document.createDocumentFragment();
    //使用循环设置创建10个li元素
    for(var i = 0; i < 10; i++){
        //创建一个li元素
        var oLi = document.createElement(&#39;li&#39;);
        //li元素显示的内容
        oLi.innerHTML = &#39;list &#39; + i;
        //创建完毕后插入文档碎片中
        frag.appendChild(oLi);
    }
    //最后将文档碎片插入到父节点ul元素下
    document.getElementById(&#39;listNode&#39;).appendChild(frag);
    </script>
    </body>

     (3), node type, node name and node value

      属性的一系列操作是与元素的类型息息相关的,如果我们不对元素的节点类型作判断,就不知道如何操作:例如:obj.xx = yy 还是 obj.setAttribute(xx, yy),setAttribute() 方法可添加一个新属性并指定值,或者把一个现有的属性设定为指定的值,如果我们知道节点的类型,就可以直接设置或者是使用方法设置,所以我们有必要判断节点的类型,避免耗费资源,造成意想不到的结果。判断节点类型可使用 nodeType 属性用数值常量进行判断,其操作很简单,就是判断某个节点的节点类型是否等于该节点类型的数值常量。

      实例:节点类型判断


    <body>
    <!-- 这是一个注释。 -->
    <div id="div1">这是一个div元素节点。</div>
    
    <script>
    //判断是否为注释节点
    var commentNode = document.body.childNodes[1];
    if(commentNode.nodeType == 8){
        alert('该节点是注释节点。');
    }
    
    //判断是否为元素节点
    var divNode = document.getElementById('div1');
    if(divNode.nodeType == 1){
        alert('该节点是元素节点。');
    }
    
    //判断是否为文本节点
    var textNode = document.getElementById('div1').childNodes[0];
    if(textNode.nodeType == 3){
        alert('该节点是文本节点。');
    }
    </script>

      其实我们在获取节点的子节点时,不使用 childNodes 属性,而使用 children 属性,就可以避免这一问题,因为通过 childNodes 属性返回的是子节点集合,不仅包括元素节点,而且还包括文本节点,浏览器会将标签之间的空白默认为文本节点,而使用 children 属性,则只返回元素节点,不包括文本节点,还不包括注释节点。

      节点名称和节点值,直接使用实例演示:


    <body>
    <!-- nodeName 和 nodeValue 演示 -->
    <div id="div1">节点名称和节点值。</div>
    <script>
    //元素节点 = nodeType:1
    var divNode = document.getElementById('div1');
    console.log('元素节点的节点名称和值:' + divNode.nodeName + '/' + divNode.nodeValue);
    //nodeName:返回 元素的标签名(DIV)全部大写。nodeValue:返回 null
    
    //属性节点 = nodeType:2
    var attrNode = divNode.attributes[0];
    console.log('属性节点的节点名称和值:' + attrNode.nodeName + '/' + attrNode.nodeValue);
    //nodeName:返回 属性的名称(id)。nodeValue:返回 属性的值(div1)
    
    //文本节点 = nodeType:3
    var textNode = divNode.childNodes[0];
    console.log('文本节点的节点名称和值:' + textNode.nodeName + '/' + textNode.nodeValue);
    //nodeName:返回 #text。nodeValue:返回 节点所包含的文本
    
    //(comment)注释节点    = nodeType:8
    var commentNode = document.body.childNodes[1];
    console.log('注释节点的节点名称和值:' + commentNode.nodeName + '/' + commentNode.nodeValue);
    //nodeName:返回 #comment。nodeValue:返回 注释的内容
    
    //(DocumentType)文档类型节点 = nodeType:10
    console.log('文档类型节点的节点名称和值:' + document.doctype.nodeName + '/' + document.doctype.nodeValue);
    //nodeName:返回 document的名称(html)。nodeValue:返回 null
    
    //(DocumentFragment)文档片段节点 = nodeType:11
    var farg = document.createDocumentFragment();
    console.log('文档片段节点的节点名称和值:' + farg.nodeName + '/' + farg.nodeValue);
    //nodeName:返回 #document-fragment。nodeValue:返回 null
    </script>

    2、DOMReady

      (1)、JS 在页面中的位置

      页面中的 JS 代码,可以引入外部的 JS 文件,也可以放在 标签中或 标签中,放在 body 中的 JS 会在页面加载的时候被执行,而 head 中的 JS 会在被调用的时候才执行。

      放在 标签中或 标签中 的区别:

      浏览器解析 HTML 文档是从上到下、从左到右依次进行的,如果把 JS 放在 head 里的话,则先被解析,但这时候 body 还没有被解析,所以会返回空值,也就是会出错。放在 head 中的 JS 代码会在页面加载完成之前就读取,而放在 body 中的 JS 代码,会在整个页面加载完成之后读取。这就说明了,如果我们想定义一个全局对象,而这个对象是页面中的某个按钮时,我们必须将其放入 body 中,道理很明显:如果放入head,那当你定义的时候,那个按钮都没有被加载,可能获得的是一个 undefind。

      脚本应该放置的位置:

      页面中的 JS 会在浏览器加载页面的时候被立即执行,有时候我们想让一段脚本在页面加载的时候执行,而有时候我们想在用户触发一个事件的时候执行脚本。

      需调用才执行的脚本或事件触发执行的脚本放在 HTML 的 head 部分中,head 部分中的脚本,可以保证脚本在任何调用之前被加载。

      当页面被加载时执行的脚本放在 HTML 的 body 部分。放在 body 部分的脚本通常被用来生成页面的内容。

      body 和 head 部分可同时有脚本:文件中可以在 body 和 head 部分同时存在脚本。

      外部脚本:

      有时候需要在几个页面中运行同样的脚本程序, 这时就需要用到外部脚本,而不需要在各个页面中重复的写这些代码。

      (2)、JS 在页面中的应用

      ①、放在 body 部分中:


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    <script>
    document.getElementById('main').style.color = 'red';
    </script>
    </body>
    </html>

      上面的实例,通过 JS 改变了 h1 标题的 color 属性,当打开页面时标题显示为红色。

      ②、放在 head 部分中:


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    <script>
    document.getElementById('main').style.color = 'red';
    </script>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    </body>
    </html>


      将同样的 JS 代码放在 head 部分中,就无法正常运行了,浏览器报错:未捕获的类型错误:不能读取一个空元素的样式属性。出现这样的错误就是没有分清 HTML标签和 DOM 节点之间的区别,HTML 是超文本标记语言,用于展示内容,而行为交互是需要通过 DOM 操作来实现的,HTML 标签要通过浏览器解析,才能变成 DOM 节点,当我们向地址栏输入一个 URL 时,开始加载页面,然后就能够看到内容,在这期间就有一个 DOM 节点构建的过程,节点是以树的形式组织的。JS 对于  DOM 的操作必须在 DOM 树构建完毕后,而上面的实例,head 部分中的 JS 会被浏览器先解析,但是这时候 body 中的元素还没有被解析,DOM树并没有构建完毕,所以就出事了。那如果就想把 JS 代码放在 head 部分中,还不想出错,该怎么解决呢?下文再做具体分析。

      (3)、DOMReady

      HTML 标签需要通过浏览器解析才会变成 DOM 节点,在刷新 URL 地址的时候就有 DOM 节点的构建过程,当页面上所有的 HTML 标签都转换为节点以后,DOM 树才构建完毕,这就简称为 DOMReady。

      那浏览器是如何将 HTML 标签解析变成节点的呢,浏览器是通过渲染引擎来实现的,渲染引擎的职责就是渲染,即把请求的 HTML 内容显示到浏览器屏幕上。所谓渲染,就是浏览器把请求到的 HTML 内容显示在屏幕上的过程,所谓渲染引擎,就是浏览器的内核,是浏览器最核心的东西。

      各大浏览器的渲染引擎:

      Firefox、Chrome 和 Safari 是基于两种渲染引擎构建的:

     Firefox uses the Geoko kernel, which is a rendering engine independently developed by Mozilla. Gecko is an open source engine. Gecko is also a cross-platform kernel that can be used on major operating systems such as Windows, Linux and Mac OS X. in operation.

     Safari and Chrome both use the WebKit kernel. WebKit and WebCore are both derivatives of KHTML. KHTML is one of the HTML page rendering engines developed by KDE. KHTML has the advantage of being fast and less tolerant of syntax errors than the Gecko engine used by Mozilla products. WebKit is an open source rendering engine. It was originally developed for the Linux platform and was later ported to Mac and Windows by Apple.

     

    AndIE uses the Trident kernel (also known as MSHTML), which is Microsoft's Windows operating system (Windows) The rendering engine used by the web browser Internet ##Explorer. This kernel program was first used in IE 4 in 1997 and has been continuously used since. New technologies are added and released with new versions of IE, but Trident is only available on Windows platforms.

     

    The basic process of the rendering engine after obtaining the content:

     

    Parse HTML to build DOM tree -> Build render tree -> Layout render tree -> Draw render tree

     

    The rendering engine begins to parse the HTML and converts the tag into a DOM tree. Then, it parses the style information in the external CSS file and the style tag. These style information and the style information in the HTML The visibility directive will be used to build another tree - the render tree - the tree used to render the DOM tree - the render tree.

     

    render tree consists of a number of colors and Composed of rectangles with attributes such as size, they will be displayed on the screen in the correct order.

     

    render After the tree is built, the layout process will be executed, which will determine the exact coordinates of each node on the screen. The next step is drawing, which traverses the render tree and draws each node using the UI backend layer.

     

    It is worth noting that this process is completed step by step. For a better user experience, the rendering engine will be used as early as possible It renders content to the screen and does not wait until all HTML is parsed before building and laying out the render tree. It displays part of the content after parsing part of the content, and at the same time, it may be downloading the rest of the content through the network.

     

    The general process of opening a page in a browser:

     ①. The order of browser downloading is from top to bottom, and the order of rendering is also from top to bottom. Downloading and rendering are performed at the same time.

    ## ②. When rendering to a certain part of the page, all the parts above it have been downloaded (this does not mean that all related All elements of the link have been downloaded).

      ③、如果遇到语义解释性的标签嵌入文件(JS 脚本,CSS 样式),那么此时IE的下载过程会启用单独连接进行下载。

      ④、并且在下载后进行解析,解析过程中,停止页面所有往下元素的下载。

      ⑤、样式表在下载完成后,将和以前下载的所有样式表一起进行解析,解析完成后,将对此前所有元素(含以前已经渲染的)重新进行渲染。

      ⑥、JS、CSS中如有重复定义,则之后定义的函数将覆盖前面定义的函数。

     

    3、DOMReady 实现

      脚本在 HTML DOM 加载渲染布局显示完成后才能运行,且要放在 body 部分内容的后面,而 DOMReady 则定义使脚本无论放在哪里都能执行。

      (1)、使用定时器

      把 JS 代码放在 head 部分中,还不想出错,就是等 DOM 树构建完毕后,再执行脚本,那么是否可以使用定时器延迟脚本的执行,避免这个错误呢。


    <!DOCTYPE html><html><head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
        <script>
        //在DomReady完毕后2秒执行。打开页面可以看到一个样式变化的过程。
        setTimeout(function (){
        document.getElementById('main').style.color = 'red';
    },2000);</script></head><body><h1 id="main">这是h1标题中的一些文本。</h1></body></html>


       测试上面的代码,可以看到,在打开页面时标题显示为黑色,过一会后才会转变为红色,虽然这样不会报错了,但这并不是我们想要的效果。那可以再将延迟时间缩短,不就解决了吗,我们将时间设置为 30 毫秒再试试。


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    <script>
    //将事件缩至30毫秒
    setTimeout(function (){
        document.getElementById('main').style.color = 'red';
    },30);
    </script>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    </body>
    </html>

      测试上面代码,在打开页面时显示为红色,但如果刷新页面的话,还是能看到黑色的闪动了一下,虽然无伤大雅,但这样还存在着一个很严重的问题,如果 DomReady 时间超过了 30 毫秒,那还是会出错,显然这方法是不可行的

      (2)、使用 window.onload

      window.onload 事件是在浏览器绘制完 DOM 节点,再加载完页面上的所有资源后,然后执行脚本。也就是说在文档解析渲染,资源加载完成之前,不让脚本执行。


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    <script>
    window.onload = function (){
        document.getElementById('main').style.color = 'red';
    };
    </script>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    </body>
    </html>

      测试上面的代码,打开页面后显示为红色,再刷新也不会出现黑色的闪动,显然该方法是可行的。如果把 JS 代码放在 head 部分中,一般情况下都需要绑定一个监听,即window.onload 事件,等全部的 HTML 文档渲染完成后,再执行代码,这样就妥妥的了。

      该方法在文档外部资源不多的情况下,是没什么问题,但如果网站有很多图片,我们要用 JS 做到在点击每张图片时弹出图片的 src 属性,这时候就有问题了,而且是出大事了,我们都知道 DOM 树很快就构建完成了,但是这么多图片还在缓慢的加载中,想要先执行 JS 的效果,就得等到所有的图片全部加载完毕后才能实现,而在这期间页面不会响应用户任何操作,浏览器就跟死了一般。所以使用 window.onload 对于很多实际的操作(比如DOM操作,事件绑定等)就显得太迟了,比如图片过多,window.onload 却迟迟不能触发,影响用户体验。而 DOMReady 就可以满足提前绑定事件的需求。

      (3)、jQuery 实现 DOMReady

      最简单的方法就是使用 jQuery,jQuery 是一个 JS 函数库,封装了大量的 JS 方法,使用 jQuery 可以极大地简化 JS 编程。


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <script>
    //jQuery 实现
    $(document).ready(function (){
        document.getElementById('main').style.color = 'red';
    });
    </script>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    </body>
    </html>

     

      (4)、JS 实现 DOMReady

      用 JS 实现 DOMReady 其实也很简单,可以添加一个监听事件,即 addEventListener,该方法的语法为:document.addEventListener("事件名称", 函数, false);,false 表示在冒泡阶段捕获。再传入DOMContentLoaded 事件,这个事件是从 onload 事件延伸而来的,当一个页面完成加载时,初始化脚本的方法是使用 onload 事件,该方法的缺点是仅在所有资源都完全加载后才被触发,如果页面的图片很多的话,从用户访问到 onload 触发可能需要较长的时间,所以开发人员随后创建了一种自定义事件,DOMReady,他在 DOM 构建之后、资源加载之前就可以被触发,他的表现形式就是 DOMContentLoaded 。jQuery 源码中也是使用该方法完成的。


    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>JavaScript实例</title>
    <script>
    function domReady(fn){
        document.addEventListener('DOMContentLoaded', fn, false);
    }
    
    domReady(function (){
        document.getElementById('main').style.color = 'red';
    });
    </script>
    </head>
    <body>
    <h1 id="main">这是h1标题中的一些文本。</h1>
    </body>
    </html>

     

      上面代码,我们给参数传入一个回调函数,将 DOMReady(封装函数) 方法封装为一个函数方便以后使用,该方法支持所有现代浏览器,但是不支持 IE9 之前的浏览器。

     

    4、HTML 嵌套规则

      了解 HTML 嵌套规则,是进行 DOM 操作的基础。

      HTML 存在许多种类型的标签,有的标签下面只允许特定的标签存在,这就叫 HTML 嵌套规则。

      如果不按 HTML 嵌套规则写,浏览器就不会正确解析,会将不符合嵌套规则的节点放到目标节点的下面,或者变成纯文本。

      所以在编写任何代码时,都需要按照规则编写,有利于解析,有利于操作,有利于优化,有利于维护,有利于重构。

      HTML 元素可简单的分为块状元素和内联元素两类。下面是一些需要注意的嵌套规则:

      ①、块元素可以包含内联元素或某些块元素,但内联元素却不能包含块元素,他只能包含其他的内联元素,li元素内可以包含 p 元素。


    <div>
        <h1></h1>
        <p></p>
    </div>
    
    <a href=""><span class=""></span></a>
    
    <ul>
        <li>
            <div></div>
        </li>
    </ul>


      ②、块元素不能包含在p元素内。

    <p>这是一些文本
        <div style="width:100px;height:200px;border:1px solid black;"></div>
    </p>
    
    <p>这是一些文本
        <ul>
            <li>苹果</li>
            <li>香蕉</li>
        </ul>
    </p>

      测试上面的代码,虽然他们都能被正常显示,但是并不处在同一层。

      ③、有几个特殊的块元素只能包含内联元素,不能包含块元素,这几个特殊的块元素是 h1-h6、p 和 dt。

      ④、块元素与块元素并列,内联元素与内联元素并列。

    <div>
        <h2></h2>
        <p></p>
    </div>
    
    <div>
        <a href=""></a>
        <span class=""></span>
    </div>

    5、DOM 操作

      DOM 节点是一个非常复杂的东西,对于他的每一个属性的访问,有可能会向上搜寻到 n 多个原型点,因此 DOM 操作是个很耗性能的操作。

      使用 DOM 操作很复杂,所以建议尽量使用现成的框架来实现业务,比如 MVVM 框架,将所有的 DOM 操作,都转交给框架内部做精细有效的处理。


    以上就是JavaScript学习总结【9】、DOM Ready的内容,更多相关内容请关注PHP中文网(www.php.cn)!

     

      

     

Node type

Description Numeric constant
Element(element node) HTML tag element. 1
Attr (attribute node) Element node properties. 2
Text (text node) Element node Or the text content in the attribute node. 3
Comment (comment node) represents a comment Content. 8
Document (document node) represents the entire Document (the root node of the DOM tree, i.e. document). 9
DocumentType(document type node)

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn