哈喽elements 2019-11-19
getElementById() 和 gettElementByTagName()。querySelector()方法querySelector()方法接收一个CSS选择符,返回与该模式匹配的第一个元素,如果没有找到匹配的元素,返回null。// 取得body元素
var body = document.querySelector("body");
// 取得ID为“myDiv”的元素
var myDiv = document.querySelector("#myDiv");
// 取得类为"selected"的第一个元素
var selected = document.querySelector(".selected");
// 取得类为"button"的第一个图像元素
var selected = document.querySelector("img.button");querySelectorAll()方法NodeList的实例,如果没有匹配,NodeList就是空的。// 取得某div中所有em元素
var ems = document.getElementById("myDiv").querySelectorAll("em");
// 取得类为“selected”的所有元素
var selected = document.querySelectorAll(".selected");
// 取得所有p元素中的所有strong元素
var strongs = document.querySelectorAll("p strong");NodeList中的每一个元素,可以使用item()方法,也可以使用方括号语法。matchesSelector()方法matchesSelector()方法。接收一个参数,即CSS选择符,如果调用元素与该选择符匹配返回true,否则返回false。function matchesSelector(element, selector) {
if (element.matchesSelecotr) {
return element.matchesSelecotr(selector)
} else if (element.msMatchesSelecotr) {
return element.msMatchesSelecotr(selector)
} else if (element.mozMatchesSelecotr) {
return element.mozMatchesSelecotr(selector)
} else if (element.webkitMatchesSelecotr) {
return element.webkitMatchesSelecotr(selector)
} else {
throw new Error("Not supported.");
}
}对于元素间的空格,IE9及之前版本不会返回文本节点,而其他所有浏览器都会返回文本节点。为了弥补这一差异,而又同时保持DOM规范不变,Element Traversal 规范新定义了一组属性。
childElementCount: 返回子元素(不包括文本节点和注释)的个数firstElementChild: 指向第一个子元素;firstChild的元素版lastElementChild: 指向最后一个子元素;lastChild的元素版previousElementSibling: 指向前一个同辈元素;previousSibling的元素版nextElementSibling: 指向前一个同辈元素;nextSibling的元素版// 跨浏览器遍历某元素的所有子元素
// 老版的兼容性代码
var i,
len,
child = element.firstChild;
while(child != element.lastChild) {
// 检查是不是元素
if (child.nodeType == 1) {
processChild(child);
}
child = child.nextSibling;
}
// 使用新版的方法
var i,
len,
child = element.firstChild;
while(child != element.lastElementChild) {
processChild(child);
child = child.nextElementSibling;
}getElementsByClassName()方法// 取得所有类中包含"username"和"current"的元素
// 类名的先后顺序无所谓
var allCurrentUsernames = docment.getElementsByClassName("username current");
// 取得ID为"myDiv"的元素中带有类名"selected"的所有元素
var selected = document.getElementById("myDiv").getElemenstByClassName("selected");getElementsByClassName()方法的浏览器 IE9+ Firefox3+ Safari3.1+ Chrome Opera9.5+className属性添加、删除和替换类名。因为className中是一个字符串,所以即使只是修改字符串一部分,也必须每次都设置整个字符串的值。classList属性。classList属性是新集合类型 DOMTokenList的实例。与其他DOM集合类似,DOMTokenList 有一个表示自己包含多少元素的length属性,而要去的每个元素可以使用item()方法,或者方括号语法。此外,这个新类型还定义如下方法:
add(value): 将给定的字符串值添加到列表中。如果值已经存在,就不添加了。contains(value): 表示列表中是否存在给定的值,如果存在返回true,反之false。remove(value): 从列表中删除给定的字符串。toggle(value): 如果列表中已经存在给定的值,删除它;如果没有,添加它。classList属性,除非你需要删除所有类名,或者完全重写元素的class属性,否则就用不到className属性了。classList的浏览器 Firefox3.6+ Chromedocument.activeElement属性,始终会引用DOM中当前获得了焦点的元素。元素获得焦点的方式有页面加载、用户输入(通常是通过Tab键)和在代码中调用focus()方法。var button = document.getElementById("myButton");
button.focus();
console.log(document.activeElement === button); // truedocument.activeElement中保存的是document.body元素的引用。文档加载期间,document.activeElement的值为nulldocument.hasFocus()方法,这个方法用于确定文档是否获得了焦点。var button = document.getElementById("myButton");
button.focus();
console.log(document.hasFocus()); // trueDocument.readyState属性有两个可能的值:
loading正在加载文档complete已经加载完文档if (document.readyState == "complete") {
...
}compatMode的属性,告诉开发人员浏览器采用了哪种渲染模式。document.compatMode标准模式下等于"CSS1Compat",混杂模式下等于"BackCompat"。if (document.compatMode == "CSS1Compat") {
console.log("Standards mode");
} else {
console.log("Quirks mode");
}document.head属性,与docuemnt.body对应var head = document.head || document.getElementsByTagName("head")[0];charset属性表示文档中实际使用的字符集,也可以用来指定新字符集。默认值是"UTF-16",可以通过<meta>元素、响应头部或直接设置charset属性修改这个值。document.Characterset。console.log(document.charset); // "UTF-16" document.charset = "UTF-8";
defaultCharset表示根据默认浏览器及操作系统的设置,当前文档默认的字符集应该是什么。如果文档没有使用默认的字符集,那charset和defaultCharset属性值可能会不一样。if (document.charset != document.defaultCharset) {
console.log("Custom character set being used.");
}data- ,目的是为元素提供与渲染无关的信息,或者提供语义信息。这些属性可以任意添加、随便明明,只要以data-开头即可。<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
dataset属性来访问自定义属性的值。dataset属性的值时DOMStringMap的实例,也就是一个名值对的映射。在这个映射中,每个data-name形式的属性都会有一个对应的属性,只不过属性没有data-前缀。var div = document.getElementById("myDiv");
// 取得自定义属性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
// 设置值
div.dataset.appId = 2345;
div.dataset.myname = "Michael";
// 有没有"myname"值呢?
if (div.dataset.myname) {
console.log("Hello, " + div.dataset.myname);
}innerHTML属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的HTML标记。innerHTML会根据指定的值创建新的DOM树,然后用这个DOM树完全替换调用元素原先的所有子节点。<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>
<!-- 对于上面的div来说 innerHTML属性会返回如下字符串 -->
<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>innerHTML的值都会按照浏览器处理HTML的标注方式转换为元素(同样因浏览器而异)。如果设置的值仅是纯文本而没有HTML标签,那么结果就是设置纯文本。div.innerHTML = "Hello world!"; div.innerHTML = "Hello & welcom, <b>\"reader\"!</b>"; // 以上操作得到: <div id="content">Hello & welcome, <b>"reader"!</b></div>
使用innerHTML属性也有一些限制,大多数浏览器中通过innerHTML插入<script>元素并不会执行其中的脚本。IE8及更早的版本是唯一能够在这种情况下执行脚本的浏览器,但必须满足2个条件:
<script>元素指定defer属性<script>元素必须位于(微软所谓的)“有作用域的元素”(scoped element)之后。<script>元素被认为是“无作用域的元素”(NoScoped element),也就是在页面中看不到的元素,与<style>元素或注释类似。没有(不支持)innerHTML属性的元素有:
<col><colgroup><frameset><head><html><style><table><tbody><thead><tfoot><tr><title>元素也没有application/xhtml+xml的XHTML文档中设置innerHTML有严格的限制。在XHTML文档中使用innerHTML时,XHTML代码必须完全符合要求。outerHTML返回调用它的元素及所有子节点的HTML标签。outerHTML会根据指定的HTML字符串创建新的DOM子树,然后用这个DOM子树完全替换调用元素。<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>
<!-- 在div上调用outerHTML会返回相同的代码,包括div本身 -->
<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>outerHTML属性,会替换调用的元素本身div.outerHTML = "<p>This is a paragraph.</p>";
// 上面的代码等价于下面的代码
var p = document.createElement("p");
p.appendChild(document.createTextNode("This is a paragraph."));
div.parentNode.replaceChild(p, div);insertAdjacentHTML()接收两个参数:插入位置和要插入的HTML文本。第一个参数必须是下列之一:
// 作为前一个同辈元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
// 作为第一个子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
// 作为最后一个子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
// 作为后一个同辈元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");innerHTML outerHTML insertAdjacentHTML() 时,最好先手工删除要被替换的元素的所有事件处理程序和JavaScript对象属性(第13章将进一步讨论事件处理程序)。innerHTML仍然还是可以为我们提供很多遍历的。插入大量HTML标记时,设置innerHTML或outerHTML时就会创建一个HTML解析器,这个解析器是在浏览器级别的代码(通常是C++编写的)基础上运行的,因此比执行JavaScript快的多。innerHTML或outerHTML的次数控制在合理的范围内。scrollIntoView()作为标准方法。scrollIntoView()可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现在视口中。
IE8引入了一个新的概念叫“文档模式”(document mode)。页面的文档模式决定了可以使用什么功能。换言之,文档模式决定了你可以使用哪个级别的CSS,可以在JavaScript中使用哪些API,以及如何对待文档类型(doctype)。到了IE9总有有以下4种文档模式:
X-UA-Compatible或等价的<meta>标签来设置。<meta http-equiv="X-UA-Compatible" content="IE=IEVersion"> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"> <meta http-equiv="X-UA-Compatible" content="IE=7">
这里的IE版本(IEVersion)有以下不同的值,不一定与上述4中文档模式对应。
Edge: 始终以最新的文档模式来渲染页面。忽略文档类型声明。EmulateIE9: 如果有文档类型声明,则以IE9标准模式渲染,否则将文档模式设置为IE5。EmulateIE8: 如果有文档类型声明,则以IE8标准模式渲染,否则将文档模式设置为IE5。EmulateIE7: 如果有文档类型声明,则以IE7标准模式渲染,否则将文档模式设置为IE5。9: 强制以IE9标准模式渲染页面,忽略文档类型声明8: 强制以IE8标准模式渲染页面,忽略文档类型声明7: 强制以IE7标准模式渲染页面,忽略文档类型声明5: 强制将文档模式设置为IE5,忽略文档类型声明document.documentMode 属性可以知晓给定页面使用的是什么文档模式,它会返回文档模式的版本号(在IE9中,可能返回的版本号为5、7、8、9)children属性。这个属性是HTMLCollection的实例,只包含元素中同样还是元素的子节点。除此之外,children 与 childNodes没有区别。children属性中也会包含注释节点,但IE9之后的版本只返回元素节点。contains() 祖先节点调用这个方法,接收一个参数是要检查的后代节点。如果祖先节点包含传入的后代节点返回true,否则false。document.documentElement.contains(document.body); // true
compareDocumentPosition()也能够确定节点间的关系。| 掩码 | 节点关系 |
|---|---|
| 1 | 无关(给定的节点不在当前文档中) |
| 2 | 居前(给定的节点在DOM树中位于参考节点之前) |
| 4 | 居后(给定的节点在DOM树中位于参考节点之后) |
| 8 | 包含(给定的节点是参考节点的祖先) |
| 16 | 包含(给定的节点是参考节点的后代) |
contains()方法,应该关注的是掩码16.可以对compareDocumentPosition()的结果执行按位与。var result = document.documentElement.compareDocumentPosition(document.body); console.log(!!(result & 16));
contains函数:function contains(refNode, otherNode) {
if (typeof refNode.contains == "function" &&
(!client.engine.webkit || client.engine.webkit >= 522)) {
// 浏览器支持contains方法直接使用
return refNode.contains(otherNode);
} else if (typeof refNode.compareDocumentPosition == "function") {
// 浏览器支持compareDocumentPosition方法
// 用返回结果和16进行按位与,再转换成布尔值返回
return !!(refNode.compareDocumentPosition(otherNode) & 16);
} else {
// 针对Safari设计的验证方法
// 在文档树中向上递归验证是否有refNode
// 到达文档树顶端,parentNode 的值为null,循环结束
var node = otherNode.parentNode;
do {
if (node === refNode) {
return true;
} else {
node = node.parentNode;
}
} while (node !== null);
return false;
}
}IE原来有innerHTML和outerHTML已被HTML5纳入规范。但另外两个插入文本的专有属性则没有这么好的运气。
innerTextouterTextscrollIntoView()纳入规范后,仍有几个专有方法可以在不同浏览器中使用。下列都是对HTMLElement类型的扩展,因此在所有元素中都可以调用:
scrollIntoViewIfNeeded(alignCenter): 只在当前元素在视口中不可见的情况下,才滚动浏览器窗口或容器元素,最终让它可见。如果当前元素可见,这个方法什么都不会做。如果将可选的alignCenter参数设置为true,则表示尽量将元素显示在视口中部(垂直方向)。Safari和Chrome实现了这个方法scrollByLines(lineCount): 将元素的内容滚动到指定的行高,lineCount可以是正值也可以是负值。Safari和Chrome实现了这个方法scrollByPages(lineCount): 将元素的内容滚动到指定的页面高度,具体高度由元素的高度决定。Safari和Chrome实现了这个方法scrollIntoView()和scrollIntoViewIfNeeded()的作用对象是元素的容器,而scrollByLines()和scrollByPages()影响的是元素自身// 将页面主体滚动5行 document.body.scrollByLines(5); // 在当前元素不可见的时候,让它进入浏览器的视口 document.images[0].scrollIntoViewIfNeeded(); // 将页面主体往回滚动1页 document.body.scrollByPages(-1);
scrollIntoView()是唯一一个所有浏览器都支持的方法,因此最常用。Vue和React是数据驱动视图,如何有效控制DOM操作?能不能把计算,更多的转移为js计算?因为js执行速度很快。patch函数-->patch,对比tag,对比tag与key,对比children