DOM操作

什么是DOM( Document Object Model)
DOM定义了表示和修改文档所需的方法。DOM对象即为宿主对象,由浏览器厂商定义,用来操作html和xml功能的一类对象的集合。也有人称DOM是对HTML以及XML的标准编程接口。

DOM基本操作

1. 对节点的增删查改
    • 查看元素节点
      • document 代表整个文档
      • document.getElementById() // 元素id在ie8以下的浏览器,不区分id大小写,而且也返回匹配name属性的元素
      • getElementsByTagName() // 标签名
      • getElementsByName(); // 需注意,只有部分标签可生效(表单,表单元素,img,iframe)
      • getElementsByClassName() // 类名 ->ie8和ie8以下的ie版本中没有,可以多个class一起
      • querySelector() // css 选择器 在ie7和ie7以下的版本中没有(非实时,得到的是一个副本)
        // document.querySelector('div > span .demo')
      • querySelectorAll() // css选择器在ie7和ie7以下的版本中没有(非实时,得到的是一个副本)

例:点击不同按钮切换展示不同div

<script type="text/javascript">
var btn = document.getElementsByTagName('button');
var div = document.getElementsByClassName('content');
for(var i = 0; i< btn.length; i++) {
  (function(n){
    btn[n].onclick = function(){
      for(var j = 0; j< btn.length; j++) {
        btn[j].className = '';
        btn[j].style.display= 'none';
      }
      this.className = "active";
      div[n].style.display = "block";
    }
  })(i)
}
</script>
2. 遍历节点树
  • parentNode -> 父节点(最顶端的parentNode为#document)
  • childNodes -> 子节点们(文本节点、注释节点、元素节点。。。)
  • firstChild -> 第一个子节点
  • lastChild -> 最后一个子节点
  • nextSiblings -> 后一个兄弟节点
  • previousSiblings ->前一个兄弟节点

上面的方法不区分节点类型:包含 文本节点、注释节点、元素节点等各种类型的节点(兼容所有浏览器)

3. 基于 元素节点 树遍历
  • parentElement -> 返回当前元素的父元素节点(IE9以下不兼容)
  • children (常用)-> 只返回当前元素的元素子节点
  • node.childElementCount === node.children.length -> 当前元素节点的子元素阶段个数(IE不兼容)
  • firstElementChild -> 返回的是第一个元素节点(IE不兼容)
  • lastElementChild -> 返回的是最后一个元素节点(IE不兼容)
  • nextElementSibling/previousElementSibling -> 返回后一个/前一个兄弟元素节点(IE不兼容)

部分方法IE9以下不兼容

4. 节点类型
  • 元素节点 ------ 1
  • 属性节点 ------ 2
  • 文本节点 ------ 3
  • 注释节点 ------ 8
  • document ------ 9
  • DocumentFragment ------ 11

数字对应nodeType 返回值

例如:返回一个节点所有的元素节点

function returnElementChild(node) {
  var temp  = { // 定义一个类数组
    length: 0,
    push: Array.prototype.push, // 拥有数组的方法
    splice: Array.prototype.splice // 拥有数组的形式
  }
  var child = node.childNodes, len = child.length
  for(var i = 0; i< len; i++) {
    if(child[i].nodeType === 1) {
      temp.push(child[i])
    }
  }
  return temp;
}
5. 节点的四个属性
  • nodeName
    元素的标签名,以大写形式表示只读
  • nodeValue
    Text节点或Comment节点的文本内容,可读写
  • nodeType
    该节点的类型,只读
  • attributes
    Element节点的属性集合

节点的一个方法 Node.hasChildNodes();// true or false

DOM 结构树

DOM结构树.png

// document -->HTMLDocument.prototype -->Document.prototype

DOM基本操作

    1. getElementById 方法定义在Document.prototype上,即Element节点上不能使用
    1. getElementsByName 方法定义在HTMLDocument.prototype上,即非html中的document不能使用(xml document, Element)
    1. getElementsByTagName方法定义在Document.prototype和Element.prototype上
    1. HTMLDocument.prototype定义了一些常用的属性,body,head分别指代HTML文档中<body><head>标签
      // document.body document.head
    1. Document.prototype上定义了documentElement属性,指代文档的根元素,在HTML文档中,他总是指代<HTML>元素
      // document.documentElement -> html
    1. getElementsByClassName、querySelectorAll、querySelector在Document.prototype,Element.prototype类中均有定义

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

function returnSiblings(e, n) {
  while(e && n) {
    if (n>0) {
      e = e.nextElementSibling;
      n--;
    } else 
    {
      e = e.previousElementSibling;
      n++;
    }
  }
  return e;
}

上面的nextElementSibling/ previousElementSibling有兼容性问题(IE9以下不兼容),考虑用nextSibling可以兼容ie,但是nextsibling返回的不仅仅是元素节点,可能是文本节点,注释节点...

下面兼任处理:

function returnSiblings(e, n) {
  while(e && n) {
    if (n>0) {
      if(e.nextElementSibling) {
        e = e.nextElementSibling;
      } else {
        for(e = e.nextSibling; e && e.nodeType !== 1; e = e.nextSibling);
      }
      n--;
    } else 
    {
      if(e.previousElementSibling) {
         e = e.previousElementSibling;
      } else {
        for(e = e.previousSibling; e && e.nodeType !== 1; e = e.previousSibling);
      }
      n++;
    }
  }
  return e;
}

DOM基本操作--->增 删 改

    1. document.createElement(); // 创建元素节点
    2. document.createTextNode(); // 创建文本节点
    3. document.createComment();// 创建注释节点
    4. document.createDocumentFragment(); // 创建文档碎片节点
    1. parentNode.appendChild();
      // 任何一个元素节点都有这个方法,类似数组的push追加一个节点
      // appendChild 是一个剪切操作(如果节点已经存在,则会删除原来的,剪切到新的位置)
    2. parentNode.insertBefore(a, b); // insert a before b, a和b 是并列的
    1. parent.removeChild(a); // 父节点删除子节点a, 返回被删除的a节点
    2. child.remove(); // child删除自己
      -替换
    3. parent.replaceChild(new, origin);//拿new替换origin元素,返回origin元素
  • Element节点的一些属性

    1. innerHTML ----> 获取/改变一个元素内的html
    2. innerText(火狐不兼容)/textContent(老IE不兼容) ----> 获取/改变文本内容(注意:如果元素本身有内容 设置文本内容时会覆盖原来的内容)
  • Element节点的一些方法

    1. ele.setAttribute(attName, attVal)
    2. ele.getAttribute(attName)

如:封装函数insertAfter(); 功能类似insertBefore();(可忽略老版本浏览器)

Element.prototype.insertAfter = function(targetNode, afterNode) {
  var beforeNode = afterNode.nextElementSibling;
  if (beforeNode == null) {
    this.appendChild(targetNode);
  }else{
    this.insertBefore(targetNode, beforeNode);
  }
}
  • 查看滚动条的滚动距离
    1. window.pageXOffset/pageYOfset
      IE8及IE8以下不兼容
    2. document.body/documentElement.scrollLeft/scrollTop
      兼容性比较混乱,用时取两个值相加,因为不可能存在两个同时有值
      例:封装兼容性方法,求滚动轮滚动距离getScrollOffset()
function getScrollOffset() {
  if(window.pageXOffset) {
    return {
      x: window.pageXOffset,
      y: window.pageYOffset
    }
  } else {
    retutn {
      x: document.body.scrollLeft + documnet.documentElement.scrollLeft,
      y: document.body.scrollTop + document.documentElement.scrollTop
    }
  }
}
  • 查看可视窗口的尺寸
    • window.innerWith/innerHeight
      • IE及IE8以下不兼容
    • document.documentElement.clientWidth/clientHeight
      • 标准模式下,任意浏览器都兼容
    • document.body.clientWidth/clientHeight
      • 适用于怪异模式下的浏览器
        封装兼容性方法,返回浏览器视口尺寸getViewportOffset()
function getViewportOffset() {
  if(window.innerWidth) {
    return {
      w: window.innerWidth,
      h: window.innerHeight
    }
  } else {
    if(document.compatMode === 'BackCompat') { // 怪异模式
      return {
        w: document.body.clientWidth,
        h: document.body.clientHeight
      }
    } else {
      return {
        w: document.documentElement.clientWidth,
        h: document.documentElement.clientHeight
      }
    }
  }
}
  • 查看元素的几何尺寸
    • domEle.getBoundingClientRect();
    • 兼容性很好
    • 该方法返回一个对象,对象里面有left, top, right, bottom 等属性。left和top代表该元素左上角X和Y坐标,right和bottom代表元素右下角的X和Y坐标
  • height和width属性老版本IE并未实现
  • 返回的结果并不是“实时的”
<!doctype html>
<html>
    <head></head>
    <body>
        <div style="background: red; width: 100px; height: 100px; left: 100px; top: 100px;position: absolute;"></div>
        <script>
            var div = document.getElementsByTagName('div')[0];
            let box = div.getBoundingClientRect();
            console.log(box);
            div.style.width = "200px";
            console.log(box);
        </script>
    </body>
</html>
image.png
  • 查看元素尺寸
    • dom.offsetWidth, dom.offsetHeight (视觉上的尺寸,包含padding)
  • 查看元素的位置
    • dom.offsetLeft, dom.offsetTop
    • 对于无定位父级的元素,返回相对文档的坐标。对于有定位父级的元素,返回相对于最近的有定位的父级的坐标
    • dom.offsetParent
    • 返回最近的有定位的父级,如无,返回body, body.offsetParent 返回null

例: 求任意元素相对于文档的坐标getElementPosition

function getElementPosition() {
  
}
  • 让滚动条滚动
    • window上有三个方法
    • scroll(), scrollTo(), scrollBy();
      scroll和scrollTo 滚动到某个点,多次调用 不能累加
    • 三个方法功能类似,用法都是将x, y 坐标传入。即实现让滚动轮滚动到当前位置
    • 区别:scrollBy() 会在之前的数据基础之上做累加
      例: 利用scrollBy()快速阅读的功能
var start = document.getElementById('start'); // 开始按钮
var stop = document.getElementById('stop'); // 结束按钮
var timer = 0, key = true;
start.onclick = function() {
   if(key) {
      timer  = setInterval(function(){
       window.scrollBy(0, 10);
      }, 100);
      key = false;
    }
}
stop.onclick = function() {
  clearInterval(timer );
  key = true;
}
脚本化CSS
  • 读写元素css属性
    • dom.style.prop
      • 可读写行间样式,没有兼容性问题,碰到float这样的保留字属性,前面应加css
      • eg: float -——>cssFloat
      • 复合属性必须拆解,组合单词变成小驼峰式写法
      • 写入的值必须是字符串格式
// div.style 获取的是行间样式,即style="width: 100px;height:200px"上的样式, 没写就没有
var div = document.getElementsByTagName('div')[0];
div.style.width = "200px";
div.style.height = "200px";
div.style.backgroundColor = "red"; // 组合单词background-color变成小驼峰式
div.style.borderWidth = "5px" // 符合属性必须拆解(border-width 是border中的一个属性)
// div.style.border = "5px solid black" 现在浏览器也支持这种写法
  • 查询计算样式
    • window.getComputedStyle(ele, null);
    • 计算样式只读
    • 返回的计算样式的值都是绝对值,没有相对单位
    • IE8及IE8以下不兼容
var div = document.getElementsByTagName('div')[0];
var computedStyle = window.getComputedStyle(div, null);
console.log(computedStyle.width);
  • 查询样式(IE独有的属性)
    • ele.currentStyle
    • 计算样式只读
    • 返回的计算样式的值不是经过转换的绝对值

例:封装兼容性方法getStyle(elem, prop)

function getStyle(elem, prop) {
  if(window.getComputedStyle) {
    return window.getComputedStyle(elem, null)[prop];
  } else {
    return elem.currentStyle[prop];
  }
}

getComputedStyle的第二个参数,用来获取伪元素的样式表
如获取div伪元素的宽度:

// div::after{content:""; width: 50px;height:50px; display:inline-block;}
var div = document.getElementsByTagName('div')[0];
window.getComputedStyle(div, "after").width;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  •   DOM(文档对象模型)是针对 HTML 和 XML 文档的一个 API(应用程序编程接口)。   DOM 描绘...
    霜天晓阅读 3,623评论 0 7
  •   DOM 1 级主要定义的是 HTML 和 XML 文档的底层结构。   DOM2 和 DOM3 级则在这个结构...
    霜天晓阅读 1,428评论 1 3
  • 文档对象模型 DOM DOM 是 JavaScript 操作⽹页的接口,全称为“文档对象模型”(Document ...
    yuhuan121阅读 364评论 0 0
  • 1.抽取了DOM操作中常用的部分 2.DOM属性和方法的对象归属可能并不完全准确 3.某些兼容性和特点做了标识(绝...
    一直以来都很好阅读 262评论 0 0
  •   JavaScript 与 HTML 之间的交互是通过事件实现的。   事件,就是文档或浏览器窗口中发生的一些特...
    霜天晓阅读 3,477评论 1 11