• 【javascript学习——《javascript高级程序设计》笔记】DOM操作


    DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次节点树,允许开发人员添加、移除和修改。

    1.节点层次

    <html>
      <head>
          <title>Simple Page</title>
      </head>
      <body>
          <p>Hello World!</p>
      </body>
    </html>

    如上的HTML文档,可以表示为一个层次结构。

    文档元素:每个文档的根节点,即<html>元素。文档元素是文档最外层的元素,文档中其他元素都包含在文档元素中。每个文档只能有一个文档元素。在HTML页面中,文档元素始终都是<html>元素。在XML中,没有预定义的元素,因此任何元素都可以成为文档元素。

    注意:Element titile->Text Simple Page。这个在dom节点操作的时候,不要将text这个节点忘记。

    1.1Node类型

    节点类型由Node类型中定义的下列数值常量白哦是,任何节点类型必居其一。

    • Node.ELEMENT_NODE(1)
    • Node.ATTRIBUTE_NODE(2)
    • Node.TEXT_NODE(3)
    • Node.CDATA_SECTION_NODE(4)
    • Node.ENTITY_REFERENCE_NODE(5)
    • Node.ENTITY_NODE(6)
    • Node.PROCESSING_INSTRUCTION_NODE(7)
    • Node.COMMENT_NODE(8)
    • Node.DOCUMENT_NODE(9)
    • Node.DOCUMENT_TYPE_NODE(10)
    • Node.DOCUMENT_FRAGMENT_NODE(11)
    • Node.NOTATION_NODE(12)

    确定节点类型:

    if(someNode.nodeType == Node.ELEMENT_NODE){  //在IE中无效,因为IE没有公开Node类型的构造函数
            alert("Node is an element");
    }
    if(someNode.nodeType == 1){      //适用于所有浏览器
        alert("Node is an element");
    }

    nodeName和nodeValue属性

    if(someNode.nodeType == 1){
        value = someNode.nodeName;    //nodeName 的值是元素的标签名,因此需要先判断是否是元素
    }

    NodeList:一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点,但是他并不是Array的实例,虽然这个对象也有length属性。NodeList对象的独特之处在于,它实际上是基于DOM结构动态执行查询结果,因此DOM结构的变化能够自动反映在NodeList对象中。

    var firstChild = someNode.childNodes[0];
    var secondChild = someNode.childNodes.item(1);
    var count = someNode.childNodes.length;

    someNode指的是父节点,childNodes指的是父节点下面所有的子节点,包括text。

    将NodeList转换为数组,

    //在IE8及之前版本中无效
    var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
    //兼容        
    function convertToArray(nodes){
        var array = null;
        try{
            array = Array.prototype.slice.call(nodes,0);//针对非IE浏览器
        }catch(ex){
            array = new Array();
            for(var i=0,len=nodes.length;i<len;i++){
                array.push(nodes[i]);
            }
        }
        return array;
    }

    父节点与同胞节点

    对于上述的每个childNodes都有同一个父节点,它们的parentNode属性都指向同一个节点。此外,包含在childNodes列表中的每个节点相互之间都是同胞节点。对于一个节点而言,它有previousSibling和nextSibling属性,对应前后两个节点。

    2.操作节点

    2.1appendChild(),用于向childNodes列表的末尾添加一个节点。更新完成以后将会返回更新节点。

    注意:如果传入到appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。

    2.2insertBefore(),接受两个参数:要插入的节点和作为参照的节点。插入节点以后,被插入的节点会变成参照节点的前一个同胞节点(previousSibing),同时被方法返回。

    //插入称为最后一个节点
    returnNode = someNode.insertBefore(newNode,null);
    alert(newNode === someNode.lastChild);    //true

    //插入后成为第一个节点
    var returnedNoe = someNode.insertBefore(newNode,someNode.firstChild);
    alert(returnedNode === someNode.newNode);  //true
    alert(newNode === someNode.firstNode);  //true

    //插入到最后一个子节点前面
    returnedNode = someNode.insertBefore(newNode,someNode.lastChild);  
    alert(newNode === someNode.childNodes[someNode.childNodes.length - 2]);  //true

    (注:根据《JavaSctipt语言精粹》的建议,将“==”改为“===”,有兴趣的可以看一下这本书,总共只有155页)

    2.3replaceChild(),接受两个参数:要插入的节点和要替换的节点。要替换的节点将会被删除,而以上两种方法并不会删除节点。

    使用replaceChild()插入一个节点时,该节点的所有关心指针都会从被它替换的节点复制过来。尽管从技术上将,被替换的节点仍然还在文档中占据位置。

    2.4removeChild(),移除节点,这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值。与replaceChild()一样,通过removeChild()移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。

    注意:以上方法必须先获得父节点parentNode,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将导致错误。

    2.5cloneNode()用于创建调用这个方法的节点的一个完全相同的副本。

    someNode.cloneNode(true/false);

    true:表示执行深复制,即复制节点及其整个子节点树。

    false:表示浅复制,即只复制节点本身。

    这里需要注意的是:IE9之前的版本不会为空白符创建节点。还有一个IE中存在的bug就是,它会复制事件处理程序,所以这里建议在复制之前最好先移除事件处理程序。

    3.Document类型

    简单来说,在浏览器中,document用于表示HTML页面的最底层节点。可以直接使用它来获取页面上的任意节点。可以试着通过document.nodeChilds进行测试。在console中我们可以看到NodeList[2]……

     Document节点的特征:

    nodeType:9;nodeName:"#document";nodeValue:null;parentNode:null;ownerDocument:null;

    子节点:DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment。

    3.1文档子节点

    内置了两个访问其子节点的快速方式:documentElement,该属性始终指向HTML页面中<html>元素。另一个就是通过childNodes列表访问文档元素。

    这里需要注意的是,一般情况下我们的页面开始是<!DOCTYPE html>,有这个在页面中时,document.childNodes获取的第一个是<!DOCTYPE html>,要通过childNodes遍历得到html元素是document.childNodes[1],使用从整个子节点获取需要看具体情况分析。

    直接获取属性:

    var body = document.body;        //获取对<body>的引用
    var doctype = document.doctype;     //获取对<!DOCTYPE>的引用

    浏览器对于document.doctype的支持不一致,因此这个属性并不常用。

    同样还需要注意的是关于在html外面的注释是否是节点这个问题,不同的浏览器处理是不一样的。

    3.2文档信息

    //获取文档标题
    var originalTitle = document.title;
    
    //设置文档标题
    document.title = "New page title";
    
    //获取完整的URL
    var url = document.URL;
    
    //获得域名
    var domain = document.domain;
    
    //获得来源页面的URL
    var referrer = document.referrer;

    URL、domain、referrer三个属性都和页面请求有关

    document.URL
    >"http://www.cnblogs.com/lyhabc/p/6131034.html"
    document.domain
    >"www.cnblogs.com"
    document.referrer
    >"http://www.cnblogs.com/"

    随便开个页面输出一下,我们可以看到三个属性的差别。

    在这三个属性中,只有domain是可以设置的。但由于安全方面的限制,并非可以给domain设置任何值。

    例如上面这个页面,只能写 document.domain = "www.cnblogs.com"/ document.domain = "cnblogs.com",由于跨域安全设置,来自不同子域的页面无法通过javascript通信,而通过将每个页面的document.domain设置为相同值,这些页面就可以相互访问对方的javascript对象了。

    在内嵌框架中会使用到这个。(http://www.3lian.com/edu/2015/05-22/215443.html这个讲的比较粗浅明白)

    3.3查找元素

    这个是重点!!!!!!!

    1.getElementById(),通过接收获取元素的ID来找到对应元素,这里的ID必须与页面中元素的id严格对应。

    这里要注意的是:在IE7及更早的版本中并不区分id的大小写,还有如果页面中存在多个相同的id值,那么它会返回第一个出现的元素。

    另一个问题是,表单字段的name特性,在IE7种通过getElementById()将会去与表单中name值进行匹配。因此最好不要让表单字段的name特性与其他元素的ID相同。

    2.getElementsByTagName(),通过接受一个参数获取元素的标签名,返回的是包含零个或多个元素的NodeList。

    这里有个“动态”集合的概念

    例如,在页面中有多个div

    var list = document.getElementsByTagName('div');
    console.log(list.length);      //8
    
    document.body.appendChild(document.createElement('div'));

    在浏览器中,直接输出list.length是9。

    对于图像元素来说,还有以下方法。

    var imges = document.getElementsByTagName("img");
    
    <img src="myimage.gif" name="myImage">
    
    var myImage = images.namedItem("myImage");
    var myImage = images["myImage"];

    imgaes[0].src;  //输出第一个图像元素的src特性

    3.getElemnetsByName() ,是只有HTMLDocument类型才有的,即返回带有给定name特性的所有元素。

    常见案例是单选按钮,它们的name必须是一样的。对于单选按钮来说,namedItem()方法只会取得第一项。

    4.其他集合,这些都是HTMLCollection对象

    document.anchors,包含文档中所有带name特性的<a>元素

    document.forms,包含文档中所有<form>元素

    document.images包含文档中所有<img>元素

    document.link,包含文档中所有带href特性的元素

    5.DOM一致性检测

    DOM分为多个级别,也包含多个部分。

    document.implementation属性提供相应信息和功能

    1. DOMImplementation
      1. __proto__:DOMImplementation
        1. constructor:DOMImplementation()
        2. createDocument:createDocument()
        3. createDocumentType:createDocumentType()
        4. createHTMLDocument:createHTMLDocument()
        5. hasFeature:hasFeature()
        6. Symbol(Symbol.toStringTag):"DOMImplementation"
        7. __proto__:Object

    这里主要是使用hasFeature()进行版本检测

    var hasXmlDom = document.implementation.hasFeature("XML","1.0");

    通过返回的布尔值判断是否是对应版本。

    这个功能并不常用,一般情况下,我们在使用一个属性判断是否可以在各种浏览其中使用时,可以直接使用通过try-catch来进行兼容。

    3.6文档写入

    write()、writelin()、open()、close()

    write()会原样写入,writeln()会在字符串末尾添加换行符

    这里需要注意的是,如果你在文档加载完成后使用了write()或writeln()写入,那么写入的内容将会重新整个页面。

    它们可以进行HTML代码的处理,也可以写入<script>只是需要转义符。

    4.Element类型

    Element类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。Element节点具有以下特征:

    nodeType 的值为1

    nodeName 的值为元素的标签名;

    nodeValue 的值为null;

    parentNode 可能是Document或Element;

    nodeName和tagName用于访问元素的标签名

    <div id="myDiv"></div>

    var div = document.getElementBId("myDiv");

    alert(div.tagName);//"DIV"

    alert(div.tagName === div.nodeName);//true

    在HTML中,表签名始终以大写表示;而在XML中(有时候也包括XHTML)中,标签名始终与源代码中的保持一致。

    所以要比较的时候最好使用:

    if(element.tagName.toLowerCase() === "div"){
    
    }

    4.1HTML元素

    id,元素在文档中唯一标识符。

    title,有关元素的附加说明,一般通过工具提示条显示出来。

    lang,元素内容的语言代码,很少使用。

    dir,语言方向,值为“ltr”(left-to-right,从左至右)或“rtl”(right-to-left,从右至左),也很少使用。

    className,与元素class特性对应,即为元素指定的CSS类。没有将这个属性命名为class,是因为class是ECMAScript的保留字。

    (这里插一条,在IE8及以下,无法使用getElementsByClassName()获取对应的元素,因此通过className进行兼容)

    <div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
    
    var div = document.getElementById("myDiv");
    
    div.id    //"myDiv"
    div.className   //"bd"
    div.title    //"Body text"
    div.lang    //"en"
    div.dir    //"ltr"

    同时也可以进行修改

    div.id = "somOtherId";
    div.className = "ft";
    div.title = "Some other text";
    div.lang = "fr";
    div.dir = "rtl";

    操作特性的DOM三个主要方法:getAttribute()、setAttribute()、removeAttribute()

    4.2取得特性,getAttribute()

    var div = document.getElementById("div");
    alert(div.getAttribute("id"));    //"myDiv"
    alert(div.getAttribute("class"));
    alert(div.getAttribute("title"));
    alert(div.getAttribute("lang"));
    alert(div.getAttribute("dir"));

    注意:传递给getAttribute()的特性名与实际的特性名相同。因此要想得到class特性值,应该传入“class”而不是“className”,后者只有在通过对象属性访问特性的时候才使用。

    可以使用自定义特性,同时特性名词不区分大小写。

    根据HTML5规定,自定义特性应该加上data-前缀以便验证,实际浏览器不添加该前缀并不会报错,但是最好按照标准来。

    对于HTML中公认的特性,该元素的DOM对象也将存在对应的属性。

    对于特殊的存在:style和onclick类似事件处理程序

    通过getAttribute()访问时,返回的style特性值中包含css文本,而通过属性来访问它则会返回一个对象。注意,这里是指的内联样式。

    document.getElementById("d").getAttribute("style");
     >"backgroundColor:red;font-size:10px;"
    document.getElementById("d").style;
    >CSSStyleDeclaration {0: "font-size", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: ""…}

    onclick这样的事件处理程序。当在元素上使用时,通过getAttribute()访问,则会返回相应代码的字符串。而在访问onclick属性时,则会返回一个JavaScript函数。

    一般不建议获取HTML公认特性的时候使用getAttribute(),而是使用对象属性。

    4.3设置特性

    div.setAttribute("id","someOtherId");
    div.setAttribute("class","ft");
    div.setAttribute("title","Some other text");
    div.setAttribute("lang","fr");
    div.setAttribute("dir","rtl");

    这个方法既可以操作HTML特性也可以操作自定义特性,而div.id = "someOtherId"这种方法不可以操作自定义特性。

    4.4removeAttributes()

    这个方法用于彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性。

    4.5document.createElement()创建新元素

    var div = document.createElement("div");

    创建完成以后,可以痛过操作元素特性添加更多子节点以及其他操作。

    div.id = "myNewDiv";

    div.className = "box";

    通过appendChild()、insertBefore()、replaceChild()方法,添加到文档树中。

    在IE7以及更早的版本中,有以下已知问题:

    不能设置动态创建的<iframe>元素的name特性。

    不能通过表单的reset()方法重设动态创建的<input>元素。

    动态创建的type特性值为“reset”的<button>元素重设不了表单。

    动态创建的一批name相同的单选按钮彼此毫无关系。

    这些问题可以通过createElement()中指定完整的HTML标签来解决。

        if(client.browser.ie && client.browser.ie<=7){
                //创建一个带有name特性的iframe元素
                var iframe = document.createElement("<iframe name = "myframe"></iframe>");
                //创建input元素
                var input = document.createElement("<input type = "checkbox">");
                //创建button元素
                var button = document.createElement("<button type="reset"></button>");
                //创建单选按钮
                var radio1 = document.createElement("<input type="radio" name="choice" value="1"");
                var radio2 = document.createElement("<input type="radio" name="choice" value="2"");
            }

    5.关于元素的子节点的差别childNode获得的节点

    <ul id="myList">
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>

    在IE中,<ul>元素会有3个子节点,分别是3个<li>元素。但如果是在其他浏览器中,<ul>会有7个元素,包括3个<li>元素和4个文本节点(包括<li>元素之间的空白符)

    通过childNodes属性遍历nodeType属性,需要element.childNodes[i].nodeType === 1,判断一下。

    6.Text类型

    nodeType的值为3;

    nodeName的值为“#text”;

    nodeValue的值为节点所包含的文本;

    parentNode是一个element;

    不支持(没有)子节点。

    在默认情况下,一个元素最多只能包含有一个文本系欸但,而且必须确实存在内容。

    var textNode = div.firstChild;//获取文本节点

    div.firstChild.nodeValue = "Some other message";  //修改文本节点中nodeValue内容

    div.firstChild.nodeValue = "Some <strong>other</strong> message";

    输出结果是"Some &lt;strong&gt;other&lt;/strong&gt; message";

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    本来标题应该是【JavaScript整理】,想要整理的稍微规范并且全面些,拿出了“尘封已久”的《JavaScript高级程序设计》,然后在强迫症的作用下一发不可收拾成了笔记摘录了。这本书还是强烈推荐都看看的,虽然很厚,不过有时候弯路才是真正的捷径,在对学习前端开始入门并且感兴趣以后,可以回归书本一下。

    顺便推荐本书:《CSS禅意花园》

  • 相关阅读:
    Git clone The requested URL returned error: 403 错误
    创建DOTA2本地数据库(一)
    如何打开VPK文件?里面究竟有什么?
    DOTA 2 API(个人资料)
    新的博客,新的开始!
    你应该在开始API开发之前知道的事(下)(翻译)
    你应该在开始API开发之前知道的事(上)(翻译)
    DOTA 2 Match History WebAPI(翻译)
    C#中UnixTime和DateTime的转换(转载)
    搜查令中期总结
  • 原文地址:https://www.cnblogs.com/hodgson/p/6135270.html
Copyright © 2020-2023  润新知