JavaScript学习日志(五):DOM

时间:2022-05-09 19:07:09

一,基本定义
DOM是针对HTML和XML文档的API,根据W3C的HTML DOM标准,html文档中所以内容(无论是元素还是标签还是注释还是元素属性)都是节点。

二,Node类型:
每一个节点都含有一个nodeType属性,对应着不同的数字,一共有12个,这里只记住前三个:
1.代表元素节点,也是最多的
2.代表属性节点,就是元素的属性,也是节点
3.代表文本,一个空格,一个回车都是代表#text节点
9.代表document文档

如果nodeType=1,元素节点,则nodeName就是标签名,注意这里是大写的(如“DIV”),nodeValue始终是null。

注意:nodeValue和innerHTML的区别
nodeValue指的是当前节点的值,这个节点是具体的,如果只是一个元素节点,那么没有任何值,它下面的子节点的值是它子节点的nodeValue,而且这个nodeValue包括所有的内容,像换行符也会包括,不是它的,所以它为null;而innerHTML指的是该节点下所有的子节点的字符串形式,包括它们的值。

html: <div id=“aa”>
    这里有一句话
   </div>

js: var aa = document.getElementById(“aa”);
aa.nodeValue; //null
aa.attributes[’id’].nodeValue; // aa
aa.childNodes[0].nodeValue; // (空行)
这里有一句话
(空行)
aa.innerHTML; // 这里有一句话

每一个节点都有一个childNodes属性,它保存着一个NodeList对象(就是你取一个节点,然后打印出来,就是这个对象,对象展开下面就是该节点下面所有的子节点),可以通过childNodes[a]来访问值,这个NodeList也有length值,它是类数组,但是它不是数组,同样不可以用数组的一些迭代运算。不过它有一个特殊的方法,item(a)可以访问到里面的子节点,
例:var secondChildNode = someNode.childNodes.item(1)。访问子节点的时候要注意,如果是常规的写法,没有写在一行里,分行写的,那么每一个换行都有一个#text节点。例如:
html: <div id=“aa”>
    <li></li>
    <li></li>
  </div>

js:
var div = document.getElementById(“aa”);
console.log(div.childNodes);

结果:
#text
li
#text
li
#text
(上面每一个都是对象,可展开的,里面就是他自身node节点属性)

如果需要把NodeList转换成数组来进行一系列的操作,可以用Array.prototype.slice()方法。不过这个方法在IE8之前无效,所以如果那样需要手动塞入:

function convertToArray(nodeList){
  var array = null;
  try{
    array = Array.prototype.slice.call(nodeList, 0);    //先检测是否是IE8之前版本
  } catch(ex){
    array = new Array();
    for(var i=0; i<nodeList.length; i++){
      array.push(nodeList[i])
    }
  }
  return array
}

三,节点属性:

parentNode: 父节点
firstChild: 第一个子节点
lastChild: 最后一个子节点
previousSibling: 前一个兄弟节点,NodeList.firstChild的这个属性一定是null
nextSibling: 后一个兄弟节点,NodeList.lastChild的这个属性一定是null
ownerDocument: 所有的节点最后一个属性都是这个,指向当前文档节点,可以直接找到它,唯一一个

四,操作节点(带child的都是操作的子节点)

appendChild(node):向子节点的末尾添加一个节点node,添加的节点必须是定义的或者是查找出来的,不能像jquery那样手动去写字符串。
例:
var newNode = document.createElement(“div”),
newText = document.createTextNode(“hello world!”);
newNode.appendChild(newText);
someNode.appendChild(newNode);

insertBefore(a, b):在子节点b前面添加一个a节点,如果b为null,则a添加至最后,和appendChild()方法一样

replaceChild(a, b): 用a节点来替换子节点b

removeChild(node):移除子节点node

cloneNode():可以传参数true,如果不传,则为浅复制,就是只复制这个节点,而不包括它的子节点,如果传了,则为深复制,会包含该节点以及它下面的所有的子节点

五,查找元素

getElementById() //ID
getElementsByTagName() //标签名,得到数组,如果传的是”*”,则表示全部
getElementsByName() //name值
getElementsByClassName() //IE5,6,7,8中无效,所以不要用这个

上面四个都是基于document对象来查找

someNode.nameItem(name) //根据name属性值来查找

六,特性值

getAttribute()
setAttribute()
removeAttribute()

可以直接给属性赋值来修改或者设置属性值,但是注意,这里的属性一定要是内部包含的(或者本身具备的属性),而不是自定义的属性
div.id = “aa”;
div.className = “cc”;

attributes属性:
每一个节点都有这个属性,该属性后可接一些方法(nodeName全部为大写)

someNode.attributes.getNamedItem(name); //获得nodeName为name的节点,注意,这里的attribute查找是在该节点的自身里面查找,而不是子节点。
等同于:someNode.attributes[name]; //简写

someNode.attributes.removeNamedItem(name); //移除nodeName为name的节点

someNode.attributes.setNamedItem(node); //设置一个新的节点,这个用的比较少,还是用setAttribute()比较好

七,创建元素
document.createElement() //元素节点
document.createTextNode() //文本节点

八,Text类型(所有的方法都是基于文本节点,offset、count都是数字,text是字符串)

appendData(text): 将text文本添加到节点末尾
deleteData(offset, count): 从offset的位置开始删除count个字符
insertData(offset, text): 从offset的位置开始添加text
replaceData(offset, count, text): 用text来替换文本,从offset开始到offset+count结束
splitText(offset): 从offset位置将当前文本节点分成两个文本节点
substringData(offset, count): 提取从offset开始到offset+count结束的文本字符串

normalize():父节点使用这个方法,将内部的文本子节点全部合并成一个,就是字符串拼接

九,DOM操作技术

动态脚本:

function loadScript(url){
    var scriptNode = document.createElement(“script”);
    scriptNode.src = url;
    scriptNode.type = “text/javascript”;
    document.body.appendChild(scriptNode);
}

动态样式:

function loadScript(url){

var cssNode = document.createElement(“link”);
  cssNode.href = url;
  cssNode.type = “text/css”;
  cssNode.rel = “stylesheet”;
  document.getElementsByTagName(“head”)[0].appendChild(cssNode);
}

=======================

DOM扩展:

1,选择器

querySelector(): 类似于jquery的选择器,传入的css选择符
querySelectorAll(): 也是传入css选择符,只不过返回的是所有的匹配到的,一个数组,相当于NodeList

2,元素遍历:
由于之前的childNodes包含文本节点、注释节点等,不利于我们去查找获取子节点,所以推出了新的API:

childElementCount: 获取子节点的个数(只是元素节点)
firstElementChild: 第一个元素子节点
lastElementChild: 最后。。。。
previousElementSibling: 。。。。
nextElementSibling: 。。。。

3,classList属性(返回的是一个DOMTokenList对象,这个对象的结构类似于这样:
{
0: ‘class1’,
1: ‘class2’,
2: ‘class3’,
value: ‘class1 class2 class3’
}
):

elementNode(元素节点).classList.add(value); 添加value类,如果有就不添加了
elementNode(元素节点).classList.contains(value); 列表中是否存在这个值,如果存在返回true,否则false
elementNode(元素节点).classList.remove(value); 删除value类
elementNode(元素节点).classList.toggle(value); 如果列表中有,就删除,没有就添加

4,焦点
focus();
document.hasFocus(); 判断文档是否获得焦点

5,document.head,目前只有Safari 5和谷歌浏览器能用,所以还是用getElementsByTagName方法

6,自定义属性

html5为元素添加自定义属性的时候,一定要用 data- 开头,目的是提供语义信息,如果要访问这个属性值,不能用div.data-myname,会报错,只能用dataset,后面跟的是 data- 后面的myname,

div.dataset.myname = 123; 设置自定义属性值

7,innderHTML属性
返回子节点所有的内容,包括元素、注释、文本,但是IE和Opera返回的是大写的,所以不同的浏览器返回的也不同。不是所有的元素都有这个属性,像table相关的都不支持这个。

8,outerHTML
返回的是包含当前节点的所有内容

9,insertAdjacentHTML()方法,两个参数

element.insertAdjacentHTML(“beforebegin”, “<p>hello</p>”); //作为前一个同辈元素插入,就是同级
element.insertAdjacentHTML(“afterbegin”, “<p>hello</p>”); //作为第一个子元素插入,是在子节点里面
element.insertAdjacentHTML(“beforeend”, “<p>hello</p>”); //作为最后一个子元素插入,也是在子节点里面
element.insertAdjacentHTML(“afterend”, “<p>hello</p>”); //作为后一个同辈元素插入

10,scrollIntoView();    // 项目中遇到的做城市列表选择右侧的首字母跳转功能
someNode.scrollIntoView(); //如果不传参数或者传true,默认节点的顶端与视口顶部平行,如果传false,默认节点的底部与视口顶部平行

11,children属性:
和childNodes差别,children只包含元素子节点,IE9以后是只包含元素节点,IE8及之前也包含注释节点

12,contains(someNode):检测某节点下是否包含此子节点

DOM3级,类似方法:compareDocumentPosition(someNode),返回值
1 //无关
2 //居前(在参考节点之前)
4 //居后
8 //包含(给定节点是参考节点的祖先)
16 //被包含(是子节点,等同于contains)

13,innerText,Firefox不支持,
和innerHTML区别,一个返回的是纯文本,不包含元素节点标签等,一个返回的html代码,包含所有节点

14,outerText
div.outerText = “hello world”;
等同于
var text = document.createTextNode(“hello world”)
div.parentNode.replaceChild(text, div)

=======================

DOM2和DOM3

DOM1级主要定义的是HTML和XML文档的底层结构,DOM2和DOM3则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性。

获得浏览器视口大小:

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

    }

  }  

}

监测某元素是否在顶部,如果不是就使其滚到顶部

function scrollToTop(element){
  if (element.scrollTop != 0) {
     element.scrollTop = 0
  }
}