DOM简单来说就是一套js访问Document对象的一套增删改查规则,文档由许多节点构成,需要重点关注的有Element、Document、Text、Attribute四种节点。
每种节点具有一些公共的属性,包括nodeType、nodeName、nodeValue、parentNode、nextSibling、previousSibling、nextElementSibling、previousElementSibling、ownerDocument、childNodes(类数组对象),其中 parentNode、nextSibling、previousSibling、firstChild、lastChild、nextElementSibling、previousElementSibling、firstElementChild、lastElementChild 如果不存在则为 null
var parent1 = document.getElementById("parent1");
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
console.log(div1.nodeName); //DIV,自动转为大写
console.log(div1.nodeType); //1
console.log(div1.nodeValue); //null
每个节点都有一个childNodes属性,保存着一个NodeList对象。NodeList对象是一个类数组对象,动态的、实时的
console.log(parent1.childNodes[1]); //<div id="div1">This is a div</div>,在chrome中换行也被当做了一个节点,所以在获取node节点时,最好先判断一下nodeType
//上面代码等价于下面代码
console.log(parent1.childNodes.item(1)); //<div id="div1">This is a div</div>
//非IE8以下的写法
var arr = Array.prototype.slice.call(someNode.childNodes, 0); //childNodes转化为数组对象
var newarr = Array.prototype.slice.call(arguments, 0); //arguments类数组转化为数组对象
//可以用下面的代码将一个nodeList转化为一个数组对象,兼容IE8
function convertToArray(nodes1) {
var array1 = null;
try {
array1 = Array.prototype.slice.call(nodes1, 0); //针对非IE浏览器
} catch (ex) {
array1 = new Array();
for (var i = 0; i < array1.length; i++) {
array1.push(nodes1[i]);
}
}
return array1;
}
console.log(div1.nextSibling); //#text
操作节点的方法有
someNode.appendChild(newNode) 末尾追加节点,返回追加的节点
someNode.insertBefore(newNode,null) 在parent节点的子节点的某个位置插入节点,返回插入的节点,如果后一个参数为null,则效果等同appendChild()
someNode.replaceChild(newNode, someNode.firstChild) 在parent节点的子节点中用新节点替换子节点中的一项
someNode.removeChild(someNode.firstChild) 在parent节点的子节点中移除
cloneNode(true) 克隆节点,不克隆事件,IE会复制事件,所以在复制节点前,先移除事件;当参数为true时,复制子节点
var div3 = document.createElement("div");
var returnedNode1 = div1.appendChild(div3);
console.log(returnedNode1 == div3); //true
console.log(div1.lastChild == div3); //true
传入文档的新节点是现在文档的一部分,则结果是将该节点从原来的位置转移到新位置。任何DOM节点不能同时出现在文档的多个位置上。
var returnedNode2 = parent1.appendChild(parent1.firstChild);
console.log(returnedNode2 == parent1.firstChild); //false
console.log(returnedNode2 == parent1.lastChild); //true
var returnedNode3 = parent1.insertBefore(div3, null); //插入成为最后一个节点
console.log(div3 == parent1.lastChild); //true
var returnedNode4 = parent1.insertBefore(div3, parent1.firstChild); //返回插入的元素
console.log(returnedNode4 == div3); //true;
console.log(div3 == parent1.firstChild); //true
//替换节点replaceChild() 移除节点removeChild()
var returnedNode5 = parent1.removeChild(div3, parent1.firstChild);
console.log(returnedNode5); //<div></div>
var returnedNode6 = parent1.removeChild(parent1.lastChild);
console.log(returnedNode6); //<div id="div1">This is a div</div>
var ul1 = document.getElementById("ul1");
var deepList = ul1.cloneNode(true);
console.log(deepList); //<ul id="ul1"><li>item1</li><li>item2</li><li>item3</li></ul>
var shallowList = ul1.cloneNode();
console.log(shallowList); //<ul id="ul1"></ul>
Document类型
document实例 》 HTMLDocument类型 》 Document类型
JS通过Document类型表示文档。在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面
document也是window的一个属性,可以直接访问
var html1 = document.documentElement; //获取对<html>的引用
var html2 = document.childNodes[0]; //通过childNodes间接获取
var body1 = document.body; //直接获取body
var doctype1 = document.doctype; //取得对<!DOCTYPE>的引用,有兼容性问题
var originTitle1 = document.title;
var url1 = document.URL; //获取完整url
var domain1 = document.domain; //获取一级域名例:www.baidu.com
var referrer1 = document.referrer;
document.write();
document.writeIn();
Element元素
HTML元素 》 HTML子类型 》 HTMLElement类型 》 Element类型
查找元素的方法
docuement.getElementById();
document.getElementsByTagName(); 返回一个HTMLCollection对象,也是一个动态集合。HTMLCollection有length属性、item()、namedItem()方法
特性
所有HTML元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示。HTMLElement类型直接继承自Element并添加了一些属性。添加的这
些属性分别对应于每个HTML元素中都存在的下列标准特性。
id
title
lang
dir
className
取得特性
getAttribute(); 可以取得自定义特性。
setAttribute(); 设置的特性名会自动转化为小写
removeAttribute();
根据HTML5规范,自定义特性应该加上data-前缀以便验证。最上面的五种直接用js的方法来操作比较快,其他自定义属性用getAttribute 或者setAttribute等方法
通过js的方法来操作属性
var div = document.getElementById("div1");
console.log(div.id, div.className, div.title, div.lang, div.dir);
//设置
div.id = "newDiv";
//通过node节点的方式来获取
div.getAttribute("id");
div.getAttribute("class");
//获取自定义特性
div.getAttribute("data-selfAttribute");
有两类特殊的属性,他们虽然有对应的属性名,但是属性的值与通过getAttribute()返回的值并不相同,即style和onclick处理函数
getAttribute()返回的值是字符串;
.style返回的是一个对象
创建元素
var div = document.createElement("div"); //传入标签名
var div = document.createElement("<div class=\"aaaa\">hello world!</div>"); //传入一段html文本
//遍历时的注意事项
for (var i = 0; var len = element.childNodes.length;i < len;i++){
if (element.childNodes[i].nodeType == 1) {
//do something ,先判断类型再执行操作
}
}
操作文本节点的方法有
appendData(text):将text添加到节点末尾
deleteData(offset,count):从offset指定的位置开始删除count个字符
insertData(offset,text):在offset处插入指定的字符串
replaceData(offset,count,text):用text替换从fosset指定的位置开始到offset+count出的字符串
splitText(offset):从offset指定的位置将当前文本节点分为两个文本节点。
substringData(offset,count):提取从offset指定的位置开始到fooset+count位置处的字符串
//创建文本节点并添加到div中
var div = document.createElement("div");
div.className = "aaa";
var text = document.createTextNode("Hello world!");
div.appendChild(text);
document.body.appendChild(div);
通过normallize和splitText两个方法来拼合文本节点和打断文本节点
var element = document.createElement("div");
element.className = "message";
var textNode1 = document.createTextNode("This is the first node, ");
element.appendChild(textNode1);
var textNode2 = document.createTextNode("This is the another node");
element.appendChild(textNode2);
document.body.appendChild(element);
console.log(element.childNodes.length); //2
element.normalize();
console.log(element.childNodes.length); //1
console.log(element.firstChild.nodeValue); //This is the first node, This is the another node,
element.firstChild.splitText(10); //注意操作的是子节点
console.log(element.childNodes.length); //2
console.log(element.firstChild); //This is th
document.querySelector();
document.querySelectorAll()
//跨浏览器遍历所有元素
var i,
len,
child = element.firstChild;
while (child != element.lastChild) {
if (child.nodeType === 1) {
processChild(child);
}
child = child.nextSibling;
}
//使用element traversal遍历
var i,
len,
child = element.firstElementChild;
while (child != element.lastElementChild) {
processChild(child);
child = child.nextElementSibling;
}
HTML5新增一种该操作类名的方式classList,它是一个类似于nodelist的对象,有属性,有方法
length
add(value):将给定的字符串值添加到类表中,如果值已经存在了,就不添加了
contains(value):表示列表中是否存在给定的值,如果存在则返回true,否则返回false。
remove(value):从列表中删除给定的字符串。
toggle(value):
div.classList.remove("disabled");
div.classList.add("current");
div.classList.toggle("user");
确定元素中是否包含既定的类名
if (div.classList.contains("bd") && !div.classList.contains("disabled")) {
//执行操作
}
//迭代类名
for (var i = 0; len = div.classList.length; i < len;i++){
doSomthing(div.classList[i]);
}
//动态脚本设置
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
loadScript("client.js"); //不知道何时加载完毕
//动态样式表
function loadStyles(url) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
loadStyles("client.css") //不知道何时加载完毕
HTML5单独增加的API
document.querySelector() 根据css规则来选择元素,返回第一个匹配元素,没有则返回null
document.querySelectorAll() 根据css规则来选择元素,返回一个 NodeList 对象,没有则返回空的 NodeList
matchesSelector() 如果调用元素与该选择符匹配,则返回true,否则,返回false;例子:
if(document.body.matchesSelector("body.page1")){ //true}
getElementsByClassName("className1 className2 ...") 通过className选取元素,返回nodeList对象
classList属性 一个class的属性对象。拥有add(value) contains(value) remove(value) toggle(value) 四个方法,方便操作class
document.activeElement属性 始终指向DOM当中当前获得了焦点的元素
默认情况下,文档刚刚加载完成时,document.activeElement中保存的是document.body元素的引用。文档加载期间,document.activeElement的值为null。
document.hasFocus() 确定文档是否获得了焦点,页面中的元素获得了焦点,再调用document.hasFocus() 返回true,代表用户正在与页面交互
readyState属性 文档是否已经加载完毕的指示器,其值有两个loading和complete 示例:
if(document.readyState == "complete"){ //... }
compatMode兼容模式属性 标准模式其值为CSS1Compat,混杂模式为BackCompat 示例:
if(document.compatMode == "CSS1Compat"){//...}else {/...}
document.head属性 直接获取head引用,示例:
var head = document.head || document.getElementsByTagName("head")[0]
document.charset字符集属性
data- 自定义数据属性,目的是提供与渲染无关的是信息,或者提供语义信息。 设置好之后,可以通过元素的dataset属性来访问
如果是驼峰写法,则会自动将驼峰分开来,转变成小写。
innerHTML 对应元素的子元素,设置值时只会替换子节点的内容,尽量把所有元素拼接成字符串后再append
outterHTML 设置时,会替换节点本身
scrollIntoView()方法 针对容器 该方法可以在所有HTML元素上调用,通过滚动浏览器窗口或某个容器元素,调用元素就可以出现再是口中。如果传入true,则调用元素会尽可能顶部与视口平齐。如果传入false,则调用元素会近可能全部出现在视口中,顶部不一定平齐。
contains方法 判断某个节点是不是另一个节点的后代 示例:
* alert(document.documentElement.contains(document.body)); //true
下面三个方法,safari 和 chrome实现了
scrollIntoViewIfNeeded(alignCenter) 针对容器 只在当前元素再视口中公布可见的情况下,才滚动浏览器窗口或容器元素 alignCenter 设置为true时,会尽可能出现在视口中部
scrollByLines(lineCount) 针对元素 将元素的内容滚动指定的行高,正值和负值均可
scrollByPages(pageCount) 针对元素 将元素的内容滚动指定的页面高度,具体高度有元素的高度决定。
myDiv.style 获取元素样式,其中style里面包含的只有行间样式,没有嵌套和引用的
document.defaultView.getComputedStyle(element,null).color 获取计算后的样式,包括浏览器默认样式, 第二个参数通常设置为null
cuttentStyle属性 IE中不支持getComputedStyle 方法,但是有相同的属性来获取计算后的样式,注意border不能一次性获取,因为有四条边
offsetHeight 包括上下border padding
offsetWidth
offsetTop 元素的左外边框至包含元素的左内边框之间的像素距离,其中offsetLeft 和 offsetTop 属性与包含元素有关,
包含元素的引用保存再offsetParent属性中。offsetParent 属性不一定与parentNode的值相等。例如td元素的offsetParent 是
作为其祖先元素的table,因为table是DOM层次中距离td最近的一个具有大小的元素
offsetLeft
clientHeight 包含内容、上下padding,不包含上下border
clientWidth
scrollHeight 不包含滚动条,元素内容的总高度
scrollWidth
scrollLeft 被隐藏在padding左边的内容宽度,包含border
scrollTop
//自定义属性示例:
var div = document.getElementById("mydiv");
//设置自定义属性
div.dataset.appId = "45124";
//获取自定义属性
var appId = div.dataset.appId;
var myName = div.dataset.myName;
焦点管理
HTML5添加了辅助管理DOM焦点的功能。首先就是,这个属性始终会引用DOM中当前获得焦点的元素。
元素获得焦点的方式有页面载入、用户输入和在代码中调用focus()方法
var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button); //true
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true,证明用户正在与页面交互
function getElementLeft(element) {
var actualLeft = element.offsetLeft;
var current = element.offsetParent; //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;
}
/*获取客户区大小*/
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
}
}
}
//确定文档总高度
var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);
var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
function scrollToTop(element) {
if (element.screenTop != 0) {
element.screenTop = 0;
}
}
//确定元素大小
function getBoundingClientRect(element) {
var scrollTop = document.documentElement.scrollTop;
var scrollLeft = document.documentElement.scrollLeft;
if (element.getBoundingClientRect) {
if (typeof arguments.callee.offset != "number") {
var temp = document.createElement("div");
temp.style.cssText = "position: absolute; left: 0; top: 0;";
document.body.appendChild(temp);
arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
document.body.removeChild(temp);
temp = null;
}
var rect = element.getBoundingClientRect();
var offset = arguments.callee.offset;
return {
left: rect.left + offset,
right: rect.right + offset,
top: rect.top + offset,
bottom: rect.bottom + offset
}
} else {
var actualLeft = getElementLeft(element);
var actualTop = getElementTop(element);
return {
left: actualLeft - scrollLeft,
right: actualLeft + element.offsetWidth - scrollLeft,
top: actualTop - scrollTop,
bottom: actualTop + element.offsetHeight - scrollTop
}
}
}
网友评论