DOM知识梳理

DOM

咱理解,JavaScript是由于ECMAScript + DOM +
BOM组成的。ECMAScript是JS中之一部分语法,而BOM主要是浏览器对象(window)对象的一些相关知识的集结。而DOM,则是文档对象相关的学问之集。

咱理解,HTML和JS之间的相互是经波实现之。而DOM是针对HTML(XML)文档的一个API。因此,如果我们想实现与用户的彼此,那么就算用用DOM提供的API,获取HTML元素,然后于该因素上绑定相应的轩然大波,实现与用户的互相。所以,对DOM的理解与操纵就展示相当关键。

本文章主要根据《JavaScript高级程序设计(三)》中之DOM相关章节,对DOM的重点知识作出一个梳,并通过插自己个人的组成部分懂。

节点层次

形容过HTML代码的地人当都懂,我们用给各级一个元素添加缩进,然后在书相关的HTMl标签及内容,最后显示在网页上。因此这种嵌套的HTML代码和内容即做了节点层次。

本着ECMAScript理解的地球人应当还明白,JS中之各一个目标都是依据一个引用类型创建的,而引用类型可以是JS原生提供的援类型(Array、Function、RegExp、Object等),也可是从定义的援类型(通过new关键字调用引用类型(也得以让构造函数))。而持有目标都是Object的实例对象,都好继承Object.prototype上的性能与方式

倘若于DOM中,也同等发出如此看似的编制。在DOM中,最顶层的种是Node类型,其他具节点都可连续Node类型下之性质和措施。而Node类型实际上就是一定给JS中的Object构造函数。

既是,那就算线省Node类型下有什么性与章程

Node类型

  • 特性(在某个特定的节点通过持续的法门调用以下属性)
    • nodeType
    • nodeName
    • nodeValue
    • ·············
    • childNodes(指针,指向NodeList对象)
    • parentNode
    • nextSibling
    • previousSibling
    • firstChild
    • lastChild
    • ownDocument(每个节点都只好属于一个Document节点)
  • 方法(在某特定的节点通过连续的道调用以下方式)
    • ··· 查找节点 ···
    • 查找元素的措施在Document类型中
    • ························
    • ··· 插入节点 ···
    • appendChild(ele)
    • insertBefore(ele, target): 如果target为null,则规则同appendChild
    • ························
    • ··· 删除节点 ···
    • removeChild(ele)
    • ························
    • ··· 替换节点 ···
    • replaceChild(ele, target)
    • ························
    • ··· 复制节点 ···
    • cloneNode(boolean) true: 表示深复制, false: 表示浅复制
    • ························
    • ··· 处理文档节点 ··· 很少用~
    • normalize()

Node类型上之习性与法吧尽管那么多了,再啰嗦一蹩脚,所有的任何节点都好继续Node类型上的性能与方式

Document类型

JS通过Document类型表示文档。document对象是HTMLDocument的一个实例,表示整个HTML页面。同时,document对象也是window对象下的一个特性,因此得以用那作全局对象来访问。

  • 属性
    • document.documentElement
      (表示HTML元素),同时可以通过document.childNodes[1]获取HTML元素
    • document.body (表示body元素)
    • document.head (表示head元素) —HTML5新增
    • document.compatMode
      (表示浏览器采用哪种渲染方式,’CSS1Compat’表示专业模式,
      ‘BackCompat’表示混杂模式) —HTML5初长
    • document.charset
      (表示文档中其实应用的字符集,也可用来指定新字符集) —HTML5初长
    • document.dataset
      (表示通过dataset访问于定义属性,如document.dataset.myname)
      —HTML5新增加
    • document.docType (表示 元素), 存在浏览器兼容性问题 —HTML5初加
    • document.title (表示 < title > 元素)
    • ··· 网页请求 ···
    • document.URL (获取URL地址)
    • document.domain (获取URL中之域名,pathname)
    • document.attributes
      (获取有节点的习性,返回NamedNodeMap对象,与NodeList类似)
    • ··· 焦点管理,无障碍性访问 ···
    • document.activeElement:
      获取页面上赢得焦点之要素,通过tab键或者focus函数获得焦点
      —HTML5新加
    • ··· 判断文档是否加载成功 ···
    • document.readyState:存在个别只价,一凡’loading’,二凡’complete’。如果document.readyState

      ‘complete’,表明文档已经加载成功。即于DOMContentLoaded事件过后。
      —HTML5初长

  • 方法
    • ··· 查找元素 ···
    • document.getElementById(id) 返回该因素
    • document.getElementsByTagName(classname)
      返回包含零个或多只元素的HTMLCollection对象,与NodeList对象一般
    • document.getElementsByName(ele)返回带有给定name属性的因素,同样返回HTMLCollection对象
    • document.getElementsByClassName(className)
      返回所有匹配的NodeList对象
      (但是每当Document类型、Element类型上调用该方法)
    • document.querySelector(selector) selector表示CSS选择符
      返回跟该模式匹配的首先个因素,如果没找到,返回null
      (Document类型, DocumentFragment类型,
      Element类型都可调用此方式
      )
    • document.querySelectorAll(selector) selector代表CSS选择符
      返回一个相当成功之NodeList对象 (Document类型,
      DocumentFragment类型, Element类型都得调用此道
      )
    • ··· 创建元素 ···
    • document.createElement()
      (创建好之素处于游离状态,需要经过appendChild插入)
    • ··· 创建文本节点 ···
    • document.createTextNode()
      (创建好之因素处于游离状态,需要经过appendChild插入)
    • ··· 确定因素大小 ···
    • document.getBoundingClientRect()
    • ··· 焦点管理,无障碍性访问 ···
    • document.hasFocus():用于判断页面上是不是获得焦点,获得回true;否则回false

Element类型

  • 属性
    • id
    • title
    • lang
    • className
  • 方法
    • getAttribute(ele) 获取有属性
    • setAttribute(name, value) 设置有属性
    • removeAttribute(ele) 移除某个属性
    • getElementsByTagName(ele) 获取标签名吗ele的素
插标记

动态插入DOM节点有以下办法:使用像 createElement()和
appendChild()之类的DOM方法,以及以innerHTML。对于有些之DOM更改而言,两种植艺术效率都差不多。然而,对于充分的DOM更改,使用innerHTML要较用正式DOM方法创建同的DOM结构快得多。当把innerHTML设置也某某值经常,后台会创一个HTML解析器,然后用中的DOM调用来创造DOM结构,而不基于JavaScript的DOM调用。由于其中方法是编译好的使未讲实施之,所以实行快得差不多。

当采取innerHTML, outerHTML,
inertAdjacentHTML方法时,需要留意一点之凡,由于这三单办法还是一直调换指定元素下的DOM节点,因此当让替换的要素是事件处理程序时,被轮换的事件处理程序尚未受一道替换,而是依然在内存中。所以,在轮换前,需要手动接触被轮换元素的事件处理程序。这属于DOM方面的前端性能优化问题。

div.removeEventListener('click', fn, false)
或者是
div.onclick = null
  • 属性
    • innerHTML属性:用于替换当前因素下之拥有子元素。如document.body.innertHTML
      = ‘< h1 > 哈哈哈 <
      /h1 >’,此时即使因此h1标签替换掉了body元素下的具备子元素。IE8+以上浏览器支持
    • outerHTML属性:用于替换自身及其具有子元素。IE9+以上浏览器支持
  • 方法
    • insertAdjacentHTML方法:这个主意好配合innerHTML属性一起行使,代替appendChild,
      insertBefore方法。IE6+以上的浏览器还支持就道。此方法需要简单个参数,第一单参数为加的季独字符串。第二独参数是索要插入的DOM节点。使用办法非常简单。

      • ‘beforebegin’: 在当下元素前插入一个兄弟元素
      • ‘beforeend’:
        在此时此刻元素元素之下插入一个初的子元素或者当率先独子元素之前插入一个初的子元素
      • ‘afterbegin’:
        在脚下因素以下插入一个初的子元素或在结尾一个子元素之后栽一个新的子元素
      • ‘afterend’: 在目前因素之后栽一个附近的同辈元素

<div class="inner">
  <div class="child">1</div>
</div>

let inner = document.querySelector('.inner')
let element = '< div class="element" >new element< /div >'
inner.insertAdjacentHTML('beforebegin', element) // 作为.inner前一个兄弟元素存在
inner.insertAdjacentHTML('beforeend', element) // 作为.inner第一个子元素
inner.insertAdjacentHTML('beforebegin', element) // 作为.inner后一个兄弟元素存在
inner.insertAdjacentHTML('beforebegin', element) // 作为.inner最后一个子元素存在
DOM元素节点遍历

于写HTML时,我们会就此tab或者转车键来针对一一标签进行排版布局。当我们采取DOM中之childNodes或者firstChild、nextSibling方法时,会收获到换行之后的一纸空文本节点(nodeType
=== 3)。如

    <p>previous</p>
    <div class="inner">
      <div class="child">1</div>
      <div class="child">2</div>
      <div class="child">3</div>
      <div class="child">4</div>
      <div class="child">5</div>
    </div>
    <p>next</p>

    let div = document.querySelector('.inner')
    console.log(div.childNodes)
    // 返回 (9) [div.child, text, div.child, text, div.child, text, div.child, text, div.child]
    // 这种返回值是不符合我们的预期的。

据此,存在以下方式可就此来博取元素节点,排除不必要的文件节点。这几种属性和方式是扩大在Element.prototype原型对象及之。支持之浏览器有IE
9+、Firefox 3.5+、 Safari 4+、Chrome ֖、Opera 10+。

Element.prototype.childElementCount // 子元素节点数量
Element.prototype.firstElementChild // 第一个子元素节点
Element.prototype.lastElementChild // 最后一个子元素节点
Element.prototype.previousElementSibling // 上一个兄弟元素节点
Element.prototype.previousElementSibling // 下一个兄弟元素节点

div.childElementCount // 5
div.firstElementChild // <div class="child">1</div>
div.firstChild        // <div class="child">1</div>
div.lastElementChild  // ... 5 ...
div.lastElementChild  // ... 5 ...
div.previousElementSibling // <p>previous</p>
div.previousSibling // '' 注意区别 previousSibling返回空文本节点
div.nextElementSibling // <p>next</p>
div.nextSibling // '' 注意区别 nextSibling返回空文本节点

当然,也可以动用children属性来代表childNodes。children属性会回子元素同样是因素节点的NodeList集合,而忽略注释和空白节点。即div.children.length
=== div.childElementCount

classList属性

HTML5每当Element.prototype上增产了classList属性,用于对有元素的色进行操作。以往一般是是因此className属性对项目进行操作,由于className返回字符串,所以想去某个类名时得进行局部麻烦的操作。

<div class="outer happy fun">...</div> 
// 删除happy
var classNames = div.className.split(/\s+/);
var pos = -1,
 i,
 len;
for (i=0, len=classNames.length; i < len; i++){
 if (classNames[i] == "user"){
 pos = i;
 break;
 }
}
classNames.splice(i,1);
div.className = classNames.join(" ");

采取classList属性可以免上述的操作。classList返回类数组对象,存在以下办法

  1. add(value): 增加类名
  2. remove(value): 移除类名
  3. contains(value): 是否带有类名,包含则回true;否则回false
  4. toggle(value):
    如果是value类,则去该类名;如果不存在value类,则上加该类名

因而,可以动用classList属性简化上面的操作

let div = document.querySelector('.outer')
div.classList.remove('happy')
contains方法

斯道用于确认有节点下是否带有其他一个DOM节点,如果是则赶回true;否则回false;需要传入一个DOM节点作为参数。IE6+以上浏览器都支持。

document.documentElement.contains(document.body) // true
document.body.contains(document.head) // false

Text类型

  • 属性
    • nodeValue | data (访问Text节点中之公文)

DocumentFragment类型

用途:离线操作DOM元素,避免DOM节点大量底又排和重绘,造成性能问题

  • 方法
    • document.createDocumentFragment() (表示创建文档片段)

NodeList对象

知道 NodeList 及其“近亲”NamedNodeMap 和
HTMLCollection,是从整体达标透彻理解 DOM
的关键所在。这三独聚众都是“动态的”;换句话说,每当文档结构发生变化时,它们还见面获取更新。因此,它们一直都见面保留着时、最精确之消息。从本质上说,所有NodeList
对象都是于访 DOM 文档时实时运行的查询。

素大小

偏移量(offset dimension)

苟想清楚有元素于页面上的偏移量,将是元素的 offsetLeft 和 offsetTop
与那
offsetParent的同样属性相加,如此循环直至根元素,就足以博得一个为主准确的价值。以下简单独函数就好用来分别取元素的不当和上偏移量。

function getElementLeft(element){
 var actualLeft = element.offsetLeft;
 var current = element.offsetParent;
 while (current !== null){
 actualLeft += current.offsetLeft;
 current = current.offsetParent;
 }
 return actualLeft;
}

function getElementTop(element){
 var actualTop = element.offsetTop;
 var current = element.offsetParent;
 while (current !== null){
 actualTop += current. offsetTop;
 current = current.offsetParent;
 }
 return actualTop;
}

客户区大小(client dimension)

假若规定浏览器视口大小,可以采取 document.documentElement 或
document.body(在IE7 之前的版本被)的clientWidth 和 clientHeight。

function getViewport(){
 if (document.compatMode == "BackCompat"){
 return {
 width: document.body.clientWidth,
 height: document.body.clientHeight
 };
 } else {
 return {
 width: document.documentElement.clientWidth,
 height: document.documentElement.clientHeight
 };
 }
}

滚动大小(scroll dimension)

·················

规定因素大小

document.getBoundingClientRect()方法,
返回一个矩形对象。包含4只属性:left、top、right和bottom。这些性被出了元素以页面中互相对于视口的职位。