----------------------------------------------------------------------------------------------第一部分 DOM基本知识

一、定义:

    1、DOM: Document Object Model,是操作html和css的,是一系列对象的集合, 是html和xml的标准编程接口。

    2、document 代表着整个文档,但不是指整个html,确切说是document包含html。

二、增删改查:

 (1)、查询(选择多个元素的返回的是一个类数组)

    i、getElementById('idName');返回仅一个对象。

    P.S. 元素id 在Ie8以下的浏览器,不区分id大小写,而且也返回匹配name属性的元素

   ii、getElementsByTagName('标签名');返回该标签的所有的集合,可看做一个类数组,即使仅有一个,访问时也要用数组访问的方式

    iii、 getElementsByClassName('类名(也可以是用空格分隔的多个类名)');返回满足该类名的所有的集合,可看一个类数组,即使仅有一个,访问时也要用数组访问的方式

  

  1. <div class = 'demo demo1'></div>
  2. var divs = document.gerElementsByClassName('demo demo1');//true

  兼容问题:IE8 及 IE8以下 没有getElementsByClassName('')方法,或者说不兼容

   iv、getElementsByName('标签中属性name的值');返回满足该条件的所有的集合,可看做一个类数组,即使仅有一个,访问时也要用数组访问。

   局限:只有部分元素name生效(表单,表单元素,img,iframe); 

   v、此方法返回的是一个副本,即非实时,1. (a)、即通过其不可影响html和css的内容样式,不实用,但jquery中选择元素用的就是这种方法;(2)、选取的选取这一刻的dom,之后动态添加的也符合选取条件的dom选取不到;   2.在IE7 及IE7一下浏览器没有,不兼容

      通过css选择器的写法来选择dom节点

    a、 document.querySelector('Css选择器写法');返回的是满足条件的一组中的第一个。

    b、document.querySelectorAll('Css选择器写法');返回的满足要求的一组元素。  

   vi、document

    代表整个文档

   

 (2)、创建:

    i、document.createElement()  创建元素节点

    ii、document.createTextNode()  创建一个文本节点

    iii、document.createComment()  创建一个注释节点

    iv、document.createDocumentFragment()  创建一个dom文档碎片

 (3)、插入:

    i、parentNode.appendChild()    在parentNode中插入一个子元素节点,且插入的位置为最后一个子元素(较为常用的方法)

     限制:必须要先能获取到父节点

      初始dom结构为:

  

  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. </ul>

      创建及插入操作:

  

  1. var oUl = document.getElementsByTagName('ul')[0];
  2. // 创建dom
  3. var oLi = document.createElement('li');
  4. oLi.setAttribute('class', 'insert');
  5. var oText = document.createTextNode('3');
  6. // 插入 文本节点插入oLi下,oLi元素节点插入oLi下
  7. oLi.appendChild(oText);
  8. oUl.appendChild(oLi);

    最终的dom结构:

  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. <!--增加的-->
  5. <li class="insert">3</li>
  6. </ul>

    ii、parentNode.insertBefore(a, b)    在b节点前插入a节点

  这就上demo代码了,上边的理解了,触类旁通,这个也就能理解,大同小异罢了

 (4)、删:

    parent.removeChild()  删除parent节点下的某个子节点,正好同appendChild方法相反

 (5)、替换:

    parent.replaceChild(new, origin)   用new节点来替换parent下的origin字节点

    我们利用上面添加的例子,我们改 oUl.appendChild(oLi); 为 oUl.replaceChild(oLi, oUl.children[0]); 则将oUl下的第一个子元素节点替换为我们创建的dom节点,如下dom结构

  1. <ul>
  2. <!--替换的-->
  3. <li class="insert">3</li>
  4. <li>2</li>
  5. </ul>

   

三、dom节点:

  (1)、 节点类型:

    元素节点 - 1, 属性节点 - 2, 文本节点 - 3, 注释节点 - 8, document节点 - 9, DocumentFragment节点 - 11

    在控制台,通过  节点名.nodeType 可返回节点类型,通过返回的节点类型判断,我们可以做很多事。

  (2)、 遍历节点的一些属性(任何类型dom节点):

    a.、parentNode  返回父节点

    b.、childNodes  返回子节点们(类数组)

    c、firstChild  第一个子节点

    d、 lastChild 最后一个子节点

    e、nextSibling 后一个兄弟节点

    f、previousSibling 前一个兄弟节点

  一个坑: 请问如下结果?

    

  1. <ul class="parent">
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. <li>6</li>
  8. </ul>
  9.  
  10. <script>
  11. var oPar = document.getElementsByTagName('ul')[0];
  12. var oChild = oPar.childNodes;
  13. console.log(oChild.length); // 6 or 13
  14. </script>

 

    答案其实是13,为什么呢?因为dom节点有好多种,有元素节点,属性节点,文本节点等等,现在你应该有点明白了,我们来打印oChild来看看

    

  1. console.log(oChilds); // [text, li, text, li, text, li, text, li, text, li, text, li, text]

    所以这就很容易得到解释了,第一个li前的空格和换行作为一个文本节点,第一个li是一个元素节点,后面5个li情况一样, 然后是最后一个li的后面形成一个文本节点,所以一共是6*2 + 1 = 13个dom节点

    下面这道题如果你能得到正确答案,说明你理解了,哈

  

  1. <ul class="parent"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li> <li>6</li>
  2. </ul>
  3. //同样问ul下有几个dom节点?

    你想的很对,骚年,就是8个dom节点,6个li元素节点 + 第5个li后空格形成一个文本节点 + 最后一个li后换行形成一个文本节点 = 8个dom节点,嘿嘿

 (3)、 遍历元素节点的一些属性(除children慎用)(只针对元素节点)

    a、parentElement 返回父级 元素节点(IE不兼容)

    b、children 返回子级的 元素节点

    c、childElementCount == node.children.length(IE不兼容)

    d、firstElementChild 返回第一个子级 元素节点(IE不兼容)

    e、lastElementChild 返回最后一个子级 元素节点(IE不兼容)

    f、nextElementSibling 返回后一个兄弟 元素节点(IE不兼容)

    g、previousElementSibling 返回前一个兄弟 元素节点(IE不兼容)

    

    看到这你可能会想,好多方法啊,这要怎么记住啊,好痛苦,但细心的你会发现这些方法和上面的方法是如此的相似,所以只要上面的方法都记住了,下面的自然也就能掌握。

    首先这些方法是用来遍历元素节点(过滤了其他类型的节点),你可能想我可以用这些方法来解决上面那该死的问题,但是这些方法有很多IE都不兼容,仅仅children好用一些,

 那怎么办呢?通过JS我们自己封装这些方法让它兼容IE就可以了,而过滤通过nodeType来判断选择就可以。

     

  (4)、 dom节点的一些属性:

    a、nodeName(只读,不可写)(元素的标签以大写形式表示)

    b、nodeValue(可读可写)(仅文本节点 和 注释节点有)

    c、attributes 属性节点类数组集合

    d、nodeType 该节点的类型,只读

   (5)、节点方法:

    hasChildNodes(), 判断是否该节点存在子节点(所有类型的)。

  (6)、DOM结构树:dom元素的继承关系,阐述了dom上一些方法的来源

  类似对象原型的关系,上级是下级的原型,而每一个都为一个构造函数,而上级为其原型。可这样理解

  

  a、Node代表所有节点类型;

  b、 Document理解为继承Node的一个构造函数,而document是Document构造函数的事例对象,继承了Document.prototype上的所有方法。但浏览器是禁止我们使用Doucment来通过new操作符来创建,  但如果我们在Document.prototype上增加属性,我们可以通过document来查看。

  

  1. Document.prototype.abc = 'abc';
  2. console.log(document.abc); // abc

  HTMLDocument,有上边的图,我们不难猜出HTMLDocument是继承自Document的。这样说,Document下有两个,分别为XMLDocument和HTMLDocument,其文件后缀名分别为.xml和.html,则如果是xml文件,则其中的document为XMLDocument的实例对象,若是html文件,则其中的document为HTMLDocument的实例对象。  

   c、CharacterData同Document一样是继承自Node的一个对象,而Text和Comment则继承自CharacterData,然后所有的文本节点则继承自Text,而所有的注释节点则继承自Comment。

     d、Element是继承自Node的对象,而HTMLElement则继承自Element,然后所有的元素节点都继承自HTMLElement

   e、Attr是继承自Node的对象,而所有的属性节点则都继承自Attr

如果理解对象原型链继承机制的话,这些应该很好理解的

    (7)、DOM基本操作的一些注意事项

    i、getElementById方法定义在Document.prototype上,即Element节点上不能使用。

    ii、getElementsByName方法定义在HTMLDocument.prototype上,即除html中的document以外不能使用(xml document,Element)

    iii、getElementsByTagName方法定义在Document.prototype 和 Element.prototype上,则docuemnt和element都可使用

    iv、HTMLDocument.prototype定义了一些常用的属性,body,head,分别指代HTML文档中的<body><head>标签,所以直接用document.body和docuemtn.head即可访问body和head标签

    v、Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总是指代<html>元素

    vi、getElementsByClassName、querySelectorAll、querySelector在Document,Element类中均有定义

       

     (8)、element节点的一些属性:

        i、innerHTML   代表的是该element节点下html内容

        ii、innerText(火狐不兼容) / textContent(老版本IE不好使)   代表的是该element节点下的文本内容

     (9)、Element节点的一些方法

        i、ele.setAttribute()  写element的一些属性

        ii、ele.getAttribute()  读element下的一些属性

小总结:

  1、获取dom节点常用的方法:

    getElementById('idName'); 只能id用

    getElementsByTagName(''); 都能用,无兼容

    getElementsByClassName(''); 都能用, IE8及以下不兼容

  2、document.body  => body

    document.head => head

    document.documentElement => html

四、以上内容的简单实践:

  1、模仿实现chldren方法

    

  1. //重写children
  2. Element.prototype.retChild = function(){
  3. var child = this.childNodes,
  4. len = child.length,
  5. obj = {
  6. 'length' : 0,
  7. 'push' : Array.prototype.push
  8. }
  9. for(var i = 0; i < len; i++ ) {
  10. if(child[i].nodeType == 1){
  11. obj.push(child[i]);
  12. }
  13. }
  14. return obj;
  15. }

  

  1. Element.prototype.retChildren = function(){
  2. var arrObj = {
  3. length: 0,
  4. push: Array.prototype.push
  5. }
  6.  
  7. for(var node = this.firstChild; node; node = node.nextSibling){
  8. if(node.nodeType == 1){
  9. arrObj.push(node);
  10. }
  11. }
  12. return arrObj;
  13. }

  2、封装函数,返回元素e的第n层祖先元素节点

  1. Element.prototype.findIndexParent = function (n){
  2. var ret = this.parentNode? this.parentNode : this;
  3. while(--n) {
  4. if(!ret.parentNode) {
  5. return ret;
  6. }
  7. ret = ret.parentNode;
  8. }
  9. return ret;
  10. }

  3、封装函数,返回元素e的第n个兄弟节点,n为正,返回后面的兄弟节点,n为负,返回前面的,n为0,返回自己

  1. // 封装函数,返回元素e的第n个兄弟节点,n为正,返回后面的兄弟节点,n为负,返回前面的,n为0,返回自己
  2. Element.prototype.retIndexSibling = function (n) {
  3. var ret = this;
  4. // n === 0
  5. if(n === 0) {
  6. return this;
  7. }
  8. // n !=== 0
  9. while(n) {
  10. ret = n > 0? ret.nextSibling : ret.previousSibling;
  11. // 没有n个兄弟元素节点,则返回本身
  12. if(!ret) {
  13. return this;
  14. }
  15. ret.nodeType === 1 && n > 0 && n--;
  16. ret.nodeType === 1 && n < 0 && n++;
  17. }
  18. return ret;
  19. }

  4、请编写一段JavaScript脚本生成下面这段DOM结构。要求:使用标准的DOM方法或属性。提示 dom.className 可以读写class

    <div class="example">
       <p class="slogan">text</p>
    </div>

  1. // 创建div标签 且添加属性
  2. var oDiv = document.createElement('div');
  3. oDiv.className = 'example';
  4. // 创建p标签 且添加属性 填充内容
  5. var oP = document.createElement('p');
  6. oP.className = 'slogan';
  7. oP.innerHTML = 'text';
  8. // 按顺序插入
  9. oDiv.appendChild(oP);
  10. document.body.appendChild(oDiv);

  5、封装函数insertAfter();功能类似insertBefore();提示:可忽略老版本浏览器,直接在Element.prototype上编程

  

  1. //封装insertAfter()
  2. Element.prototype.insertAfter = function(targetNode, afterNode){
  3. var nextSib = afterNode.nextElementSibling;
          //如果父节点没有子元素或afterNode不存在的容错处理
  4. if(this.children.length <= 1 || !nextSib){
  5. this.appendChild(afterNode);
  6. }else {
  7. this.insertBefore(targetNode, nextSib);
  8. }
  9. }

  6、封装remove(); 使得child.remove()直接可以销毁自身

  1. Element.prototype.remove = function (){
  2. // 像那些属性节点,注释节点,文本节点等等根本不可能做父节点,所以可以说parentNode返回的一般都是父元素节点
  3. var definedParent = this.parentNode;
  4. definedParent.removeChild(this);
  5. }

  7、将目标节点内部的节点顺序逆序。
    eg:<div> <a></a> <em></em></div>

  1. // 将所有子元素逆序
  2. Element.prototype.reverseChildren = function () {
  3. var children = this.children;
  4. var len = children.length;
  5. for(var i = 0; i < len; i++) {
  6. this.insertBefore(children[i], children[len - i - 1]);
  7. this.insertBefore(children[len - i - 1], children[i]);
  8. }
  9. }

  8、parentElement 返回父级 元素节点(IE不兼容),  个人直接用node.parentNode就可以了,感觉除了元素节点外,其他类型节点都不适合做父节点

  9、childElementCount (IE不兼容),  我们直接用node.children.length代替他即可解决不兼容问题

  10、firstElementChild 返回第一个子级 元素节点(IE不兼容),我们用node.children[0]即可

  11、lastElementChild 返回最后一个子级 元素节点(IE不兼容), 我们用直接返回node.dhildren的最后一个元素就可

  12、nextElementSibling 返回后一个兄弟 元素节点(IE不兼容),js封装

  

  1.     // 返回后一个兄弟 元素节点
  2. Element.prototype.nextEleSibling = function () {
  3. // 利用for循环的赋初值, 判断, 调整, 循环 这四种特性
  4. for(var ret = this.nextSibling; ret && ret.nodeType !== 1; ret = ret.nextSibling) {}
  5. return ret;
  6. }

  13、previousElementSibling 返回前一个兄弟 元素节点(IE不兼容), js封装, 原理同上

  1. // 返回前一个兄弟 元素节点
  2. Element.prototype.nextEleSibling = function () {
  3. // 利用for循环的赋初值, 判断, 调整, 循环 这四种特性
  4. for(var ret = this.previousSibling; ret && ret.nodeType !== 1; ret = ret.previousSibling) {}
  5. return ret;
  6. }

    

  

--------------------------------------------------------------------第一部分 end

------------------------------------------------------------------------------------------------------------------------------------第二部分 DOM操作

一、DOM操作:https://www.cnblogs.com/Walker-lyl/p/5250091.html

  

  1、基本操作

  3、css脚本化

  4、事件

  

--------------------------------------------------------------------第二部分 end

-------------------------------------------------------------------第三部分 JS加载

一、异步加载

  时间线

  

-------------------------------------------------------------------第三部分 end

总结: 在我看来DOM的大概可以分为DOM基础知识、DOM操作、JS记载三部分,然后再细分即可,这是在写博客时想出来的,不管对不对,能够让自己记住并理解知识点就可以,等到理解更深再说,学习的快乐莫过于遇到困难后的坚持,直到解决问题,甚至有些自己的独特理解,不能仅仅为了以后找工作而学,而是因为自己的兴趣才学,因为自己想学才培养这方面的兴趣,在我们不能真正理解一个东西时,我们没资格说我们对其没兴趣,因为我们根本就不了解,还谈何是否有兴趣呢。

--------------------------------------------------------------------end

  

    

Js之DOM(一)的更多相关文章

  1. js的DOM对象

    1.js的Array对象           ** 创建数组(三种)                          - var arr1 = [1,2,3];                    ...

  2. python学习笔记十三 JS,Dom(进阶篇)

    JS介绍 JavaScript 是属于网络的脚本语言!JavaScript 被数百万计的网页用来改进设计.验证表单.检测浏览器.创建cookies,以及更多的应用:JavaScript 是因特网上最流 ...

  3. 框架操作DOM和原生js操作DOM比较

    问题引出 对于Angular和React操作DOM的速度,和原生js操作DOM的速度进行了一个比较: 一个同学做的demo 代码如下: <!DOCTYPE html> <html n ...

  4. JavaScript基础15——js的DOM对象

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. jQuery对象与JS原生dom对象之间的转换

    jQuery就是JS的一个扩展库,工具库,提供很多方便快捷的方法,所以将JS对象转换为jQuery对象后,能更方便地操作这个对象.但是jQuery对象也不是万能的,有一些JS对象有的能,jQuery对 ...

  6. JS1 js获取dom元素方法

     js获取dom元素方法  1.通过ID选取元素(getElementById) 1)使用方法:document.getElementById("domId")         其 ...

  7. JS的DOM操作及动画

    JS的DOM操作DOM:Document Object ModelBOM:Bowers(浏览器) Object Model找到元素:var a=document.getElementById(&quo ...

  8. js操作DOM对象

    js操作DOM对象  (Document Object Model)文档对象模型 nodeType返回值 1:元素节点 2:属性节点 3:文本节点 8:注释节点 9: 文档节点 nodeName 节点 ...

  9. DOM是什么?有什么用处?js与DOM啥关系?

    本文转载于:https://blog.csdn.net/u012155729/article/details/78135393 转载仅供自己后期学习 DOM简介大家都想知道dom是什么,翻了各种文档, ...

  10. 继续JS之DOM对象二

    前面在JS之DOM中我们知道了属性操作,下面我们来了解一下节点操作.很重要!! 一.节点操作 创建节点:var ele_a = document.createElement('a');添加节点:ele ...

随机推荐

  1. golang的函数

    在golang中, 函数是第一类值(first-class object), 即函数可以赋值与被赋值. 换言之, 函数也可以作为ReceiverType, 定义自己的method. 实例: http. ...

  2. 管理员必备的20个Linux系统监控工具

    需要监控Linux服务器系统性能吗?尝试下面这些系统内置或附件的工具吧.大多数Linux发行版本都装备了大量的监控工具.这些工具提供了能用作取得相关信息和系统活动的量度指标.你能使用这些工具发现造成性 ...

  3. 在线演示平台 | Highcharts中文网 (曲线图、区域图、3D图等等)

    http://www.hcharts.cn/ 在线演示平台 | Highcharts中文网

  4. 48.Warning: (vsim-3534) [FOFIR] - Failed to open file "sp_rom_8x256_sr.mif" for reading.

    当在仿真ROM IP核文件时,会出现这种警告,而这种警告的结果是ROM不能输出数据,原因是mif文件要放在modelsim工程文件目录下.类似的,有时候会报错,Failed to open file& ...

  5. iTween基础之功能简介

    一.iTween 介绍 .二.iTween 原理.三.iTween 下载.四.iTween 类介绍.五.主要功能介绍 原文地址:http://blog.csdn.net/dingkun520wy/ar ...

  6. cnblogs用户体验

    在使用博客园的这段时间内,我们感觉有优点也有缺点,下面谈谈我们的看法: 1.是什么样的用户?有什么样的心理?对cnblogs的期望值是什么? 我们是学生用户,使用cnblogs主要是提交作业记录自己的 ...

  7. Kibana4学习<二>

    生产环境部署 Kibana4 是是一个完整的 web 应用.使用时,你需要做的只是打开浏览器,然后输入你运行 Kibana 的机器地址然后加上端口号.比如说:localhost:5601 或者 htt ...

  8. Android:apk文件结构

    Android apk文件,即Android application package文件. 每个要安装到Android平台的应用都要被编译打包为一个单独的文件,后缀名为.apk,其中包含了应用的二进制 ...

  9. perl随记(1)

    chmod 755 test,改变文件权限,rwx 421 chomp,如果字符串结尾有换行符,chomp 可以去掉它 正则表达式量词:*表示有或无,+表示1或多,?表示0或1 my,局部变量,只在定 ...

  10. 使用Java 8 API,根据传递的分隔符,连接list中所有的元素

    public class MethodReferenceDemo1 { @FunctionalInterface interface StringListFormatter { String form ...