评论

(五)DOM

DOM

DOM

理解包含不同层次节点的DOM
使用不同的节点类型
克服浏览器兼容性问题以及各种陷阱

DOM描绘了一个层次化的节点数,允许开发人员添加 移除 修改页面的一部分

1.1 节点层次

DOM可以将HTML或XML描绘成一个多层节点构成的结构。
节点拥有不同的类型,每种类型表示文档中不同的信息,每个节点拥有各自的特点,数据和方法,另外与其他节点也存在某种关系。
总共有12种节点类型。

1.1.1 Node类型

DOM1级定义了一个Node接口,该接口将由DOM中所有节点类型实现。
js中的所有节点类型都继承自Node类型,因此所有节点类型都享有共同的属性和方法。
每个节点都有一个 nodeType属性 ,用于表明节点的类型。

比较nodeType 和 Node.ELEMENT_NODE 常量 如果二者相等 则意味着taobao确实是一个元素

<div id="taobao">taobao</div>

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



let taobao = document.getElementById("taobao")
console.log(taobao.nodeType) // 1

if(taobao.nodeType == Node.ELEMENT_NODE){
    console.log('taobao is an ELEMENT')
}

  1. nodeName 和 nodeValue属性

对于元素节点
nodeName 中保存的始终都是元素标签名
nodeValue始终都是null

console.log(taobao.nodeValue)  // null
console.log(taobao.nodeName) // 元素的标签名   DIV
  1. 节点关系
    每个节点都有一个childNodes属性,其中保存着NodeList对象,NodeList是一个类数组对象。
    访问NodeList中的节点,可以通过方括号,也可以通过item()
let all = document.getElementById("all")
console.log(all.childNodes) // 其中保存着NodeList对象,NodeList是一个类数组对象。
console.log(all.childNodes.length)

console.log(all.childNodes[1]) // 方括号和item(效果一样)
console.log(all.childNodes.item(1))

父节点 parentNode
兄弟节点 previousSibling nextSibling
第一个孩子节点
最后一个孩子节点

console.log(taobao.parentNode) // 父亲节点
console.log(taobao.previousSibling)  // 上一个兄弟节点
console.log(taobao.nextSibling)      // 下一个兄弟节点

console.log(all.childNodes[0]) //第一个孩子节点
console.log(all.firstChild)    // 第一个孩子节点
let nodeArr = Array.prototype.slice.call(all.childNodes , 0);  // 将类数组对象转为数组

console.log(all.childNodes[all.childNodes.length - 1]) // 最后一个孩子节点
console.log(all.lastChild)  //最后一个孩子节点
  1. 操作节点
    appendChild()
    在childNodes末尾添加一个节点,返回新增的节点。如果传入到appendChild()中的节点已经是文档的一部分了,那会将该节点移到新位置
    insertBefore()
    传入两个参数,要插入的节点,作为参照的节点。插入节点后,被插入的节点会变成参照节点的一个preciousSiblings节点
    如果参照节点是null,那么效果和appendChild()一样
    replaceChild()
    传入两个参数,要插入的节点和要替换的节点
    removeChild()
    只接一个参数,要移除的节点
    上面四个方法操作的都是某个节点的子节点,所以必须先取得父节点

ownerDocument()
该属性表示整个文档的文档节点。

// 操作节点
let all = document.getElementById("all")
let xianyu = document.getElementById("xianyu")
let tianmao = document.getElementById("tianmao")

all.appendChild(tianmao)
all.insertBefore(tianmao , xianyu)
all.replaceChild(tianmao , xianyu)
all.removeChild(tianmao)

  1. 其他方法
    cloneNode()
    接受一个布尔值,表示是否深复制
    true 深复制 会赋值整个节点以及其子节点数
    false 浅赋值,只复制节点本身
let anotherXianyu = xianyu.cloneNode(true); // 深复制
let anotherXianyu1 = xianyu.cloneNode(false); // 浅复制

console.log(anotherXianyu)
console.log(anotherXianyu1)

1.1.2 Document类型

js通过Document类型表示文档。在浏览器中,document是HTMLDocument的一个实例,表示整个页面。
而且document是window对象的一个属性,因此可以通过全局对象来访问。
Document节点具有下列特征

console.log(document.nodeName)  // #document
console.log(document.nodeValue) // null
console.log(document.parentElement) // null
console.log(document.parentNode) // null
console.log(document.ownerDocument) //null
  1. 文档的子节点
document.documentElement  // <html>
document.body // <body>
  1. 文档信息
console.log(document.title)
console.log(document.URL)
console.log(document.domain)
  1. 查找元素
    getElementById()
document.getElementById("")
document.getElementsByName("")
document.getElementsByTagName("")
  1. 特殊集合

  2. DOM一致性检测

  3. 文档写入
    document.open()
    document.write()
    document.writeln()
    document.close()

1.1.3 Element类型

  1. HTML元素
    每个HTML元素都有以下特性
    id title dir className lang
<div id="id" class="black" dir="ltr" title="标题" lang="en">中国</div>

let ele = document.getElementById("id") 
console.log(ele.id) // 
console.log(ele.className) // black
console.log(ele.dir) // 文字对齐方式
console.log(ele.lang) // en
console.log(ele.title) // 标题
setTimeout(()=>{
    ele.className = "red";
    ele.dir="rtl"
} , 1000)
  1. 取得特性
    通常直接获得特性,只有在获取自定义属性时才会用getAttribute()
<div id="id" class="black" dir="ltr" title="标题" lang="en" myName="wujie">中国</div>

let ele = document.getElementById("id") 
console.log(ele.getAttribute("id"))
console.log(ele.getAttribute("class"))
console.log(ele.getAttribute("title"))
console.log(ele.getAttribute("dir"))
console.log(ele.getAttribute("lang"))

// 获取自定义属性
console.log(ele.getAttribute("myName"))  //wujie
console.log(ele.myName)  // undefined
  1. 设置特性
    setAttribute() 既可以设置HTML特性,也可以设置自定义属性
<div id="id" class="black" dir="ltr" title="标题" lang="en" myName="wujie">中国</div>

let ele = document.getElementById("id") 
ele.setAttribute("class" , "red");
ele.setAttribute("title" , "新标题");

ele.myTitle = '我的标题'; // 直接设置自定义特性是不行的
console.log(ele.getAttribute("myTitle")) // null
ele.setAttribute("myTitle" , "我的标题")
console.log(ele.getAttribute("myTitle")) // 我的标题

彻底删除特性 以及特性的值
removeAttribute()

  1. attributes属性
    Element 类型时唯一使用attributes属性的DOM 节点类型。
    attributes包含元素的每一个特性以及部分方法

attributes通常用来遍历元素的所有属性

  1. 创建元素
    document.createElement()可以创建元素
    这个方法只接受一个参数,就是元素的标签名

然后通过
appendChild
insertBefore
replaceChild
把元素放进

let ele = document.getElementById("id") 

let div = document.createElement("div")
div.className = "red";
div.innerHTML = "createElement"
ele.appendChild(div)
  1. 元素的子节点
    由于文本 注释 等等也算子节点 ,所以获取元素的子节点时需要注意。
let ul = document.getElementsByTagName("ul")[0]
let ulChildArr = Array.prototype.slice.call(ul.childNodes , 0)  // 将childNodes转为数组
console.log(ulChildArr) // [text, li, text, li, text, li, text]
// 过滤掉其他节点 只留下元素节点 即 nodeType 为1 的节点
let ulChildEleArr = ulChildArr.filter((item , index , arr) => {
    return item.nodeType == '1'
})
console.log(ulChildEleArr)  // [li, li, li]

1.1.4 Text类型

nodeType 为 3
nodeValue 为文本
nodeName 为 #text
parentNode 是一个 Element

<div id="txt-div">这是一个文本</div>

// 文本节点
let txtDiv = document.getElementById("txt-div");  
// [text, div, text]
let textNode = txtDiv.childNodes[0]
console.log(textNode.nodeName) // #text
console.log(textNode.nodeType) // 3
console.log(textNode.nodeValue) // 这是一个文本
console.log(textNode.parentNode)

  1. 创建文本节点

  2. 规范化文本节点

  3. 分割文本节点

1.1.5 Comment节点

注释节点

1.1.6 CDATASection类型

针对的是XML文档

1.1.7 DocumentType

1.1.8 DocumentFragment

1.1.9 Attr类型

元素的特性在DOM中以Attr类型表示
从技术角度讲 特性就是元素中attributes属性的节点

不建议直接访问特性节点
直接使用 setAtribute getAttribute removeAttribute更方便

1.2 DOM操作技术

1.2.1 动态脚本

// 例如动态加入一个 
let script = document.createElement("script");
script.type = "text/javascript";
script.src = './node.js';
document.appendChild(script)

1.2.2 动态样式

与动态脚本类似 不过<link>需要加到<head></head>里面

// 封装成函数
function loadStyle(url){
    let style = document.createElement("link")
    style.rel = "stylesheet";
    style.type = "text/css";
    style.href = url;

    let head = document.getElementsByTagName("head")[0];
    head.appendChild(style)
}

1.2.3 操作表格

1.2.4 使用NodeList

理解 NodeList 以及其近亲 NameNodeMap HTMLCollection是理解DOM的关键
NodeList是动态的,每次访问NodeList都会运行一次基于文档的查询

1.3 小结

DOM由各种节点组成,简要总结如下

  1. 最基本的节点是Node,用于抽象的表示文档中独立的一部分,所有其他类型都继承自Node
  2. Document类型表示整个文档。在js中,document是Document的一个实例,
    使用document对象,有很多方式可以查询和取得节点
  3. Element类型表示文档中所有HTML或XML元素
    理解DOM就是理解DOM对性能的影响,DOM操作是js中开销最大的部分。
    而因访问NodeList导致的问题最多,因为NodeList是动态的,每次访问NodeList都会运行一次基于文档的查询
    所以尽量要减少DOM操作
最后一次编辑于  2020-05-25  
点赞 0
收藏
评论
登录 后发表内容