好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

获取和操作 DOM 节点

获取 和操作 DOM 节点

DOM 节点也会被称为 DOM 元素。

想要操作 DOM 节点,就必须先 获取 到 DOM 节点。

1. 获取 DOM 节点

获取 DOM 节点的方式有很多,这里例举几个常用的,所有的 DOM 元素都具有以下 方法 :

element.getElementById element.getElementByName element.getElementsByTagName element.getElementsByClassName element.querySelector element.querySelectorAll

1.1 element.getElementById

返回对拥有指定 id 的第 一个 对象的引用。

element.getElementById 是指去 element 节点下根据 id 查找子节点。

通常在程序开始前,没有主动去 获取 过节点,这个时候会使用根节点 document 来进行查找。

    < div   id   =  " html-element "   >  
  我是 一个 元素
   </ div  >  

   < script  >   
   var  element  =  document .  getElementById  (  'html-element'  )  ; 

  element . innerHTML  =   '<a href="//imooc.com">我变成了超 链接 </a>'  ; 
    </ script  >  
 

在使用 JavaScript 操作 DOM 节点的时候,也会把 DOM 节点称为 DOM 对象 ,以契合编程中 对象 的概念,更好理解。

以上例子通过 document.getElementById 获取 id 为 html-element 的 DOM 节点,并通过 修改 innerHTML 属性 ,将这个节点的 内容 进行了 修改 。

1.2 element.getElementByName

返回带有指定 名称 的对象集合。

element.getElementByName 是通过元素的 name 属性 进行查找的,过去操作表单的时候会经常用到。

    < form  >  
     < div  >  
       < label  >  
         < input   type   =  " check Box  "    name   =  " skill "    checked   =  " checked "    value   =  " JavaScript "   >   JavaScript
       </ label  >  

       < label  >  
         < input   type   =  " check Box  "    name   =  " skill "    value   =  " c++ "   >   C++
       </ label  >  

       < label  >  
         < input   type   =  " check Box  "    name   =  " skill "    checked   =  " checked "    value   =  " Java "   >   Java
       </ label  >  
     </ div  >  
   </ form  >  
   < div   id   =  " result "   >     </ div  >  

   < script  >   
   var  check Box es  =  document .  getElementsByName  (  'skill'  )  ; 

   var  skills  =   [  ]  ; 

  check Box es .  forEach  (  function  ( check Box  )   { 
     if   ( check Box  .  getAttribute  (  'checked'  )  )   { 
      skills .  push  ( check Box  . value )  ; 
     } 
   }  )  ; 

document .  getElementById  (  'result'  )  . innerHTML  =   '选中的技能:'   +  skills .  join  (  '、'  )  ; 
    </ script  >  
 

通过 getElementsByName 获取 到的是 DOM 节点的集合,需要注意的是,这个集合不是数组类型的,而是 NodeList ,其不具备数组的 map 、 filter 等 方法 ,但是具备 forEach 方法 。

Tips:IE 和早期浏览器的 NodeList 是没有 forEach 方法 的,具体版本可以通过 Can I Use 查看。

1.3 element.getElementsByTagName

返回带有指定 标签 名的对象集合。

element.getElementsByTagName 是通过 标签 名 获取 DOM 节点的,返回的也是 一个 集合。

    < div  >  
     < p  >  我是第 一个 段落。   </ p  >  
     < p  >  我是第二个段落。   </ p  >  
     < p  >  我是第三个段落。   </ p  >  
     < p  >  我是第四个段落。   </ p  >  
     < p  >  我是第五个段落。   </ p  >  
   </ div  >  
   < div   id   =  " result "      style   ="   color  :   #4caf50  ;   "   >     </ div  >  
   < script  >   
   var  pList  =  document .  getElementsByTagName  (  'p'  )  ; 

   var  res  =   [  ]  ; 
   var  i ,  len ; 
   for   ( i  =   ,  len  =  pList . length ;  i  <  len ;  i ++  )   { 
	res .  push  ( pList [ i ]  . innerText )  ; 
   } 
  
  document .  getElementById  (  'result'  )  . innerHTML  =   '所有 p  标签 的 内容 :<br>'   +  res .  join  (  '<br>'  )  ; 
    </ script  >  
 

此 方法 返回值的类型是 HTMLCollection ,不是 NodeList ,没有 forEach 方法 。

可以使用 for 循环对返回值进行遍历。

Tips: 特别要注意,此 方法 为 getElement s ByTagName,前往不要忘记有个 s 。

1.4 element.getElementsByClassName

返回 一个 包含了所有指定类名的子元素的类数组对象。

element.getElementsByClassName 通过元素的类名来 获取 DOM 节点。

    < div  >  
     < div   class   =  " odd "   >  1   </ div  >  
     < div   class   =  " even "   >  2   </ div  >  
     < div   class   =  " odd "   >  3   </ div  >  
     < div   class   =  " even "   >  4   </ div  >  
     < div   class   =  " odd "   >  5   </ div  >  
     < div   class   =  " even "   >  6   </ div  >  
   </ div  >  
   < div   id   =  " result "   >     </ div  >  
   < script  >   
   var  odd  =  document .  getElementsByClassName  (  'odd'  )  ; 

   var  res  =   [  ]  ; 
 
   var  i ,  len ; 
   for   ( i  =   ,  len  =  odd . length ;  i  <  len ;  i ++  )   { 
    res .  push  ( odd [ i ]  . innerText )  ; 
   } 

   var  resultElement  =  document .  getElementById  (  'result'  )  ; 

  resultElement . innerHTML  =   '所有奇数:<br>'   +  res .  join  (  '<br>'  )  ; 
    </ script  >  
 

与 getElementsByTagName 返回值类型相同,此 方法 返回类型也是 HTMLCollection 。

Tips:注意,getElement s ByTagName 中也有 s 。同时此 方法 也 不支持 IE8。

1.5 element.querySelector

文档对象模型 Document 引用的 querySelector () 方法 返回文档中与指定选择器或选择器组匹配的第 一个 html 元素 Element 。 如果找不到匹配项,则返回 null 。

element.querySelector 是 获取 DOM 节点最常用的 方法 之一,可以传入 CSS 选择器来匹配 获取 DOM 节点。

如使用 CSS 在给 id 为 tip 的元素设置红色字体样式的时候,选择器使用的是 #tip 。

   #tip    { 
   color  :  red ; 
 } 
 

使用 element.querySelector 获取 id 为 tip 的元素,传入的参数也是 #tip ,与 CSS 选择器一致。

    < div  >  
     < div   id   =  " tip "   >  今日大甩卖!!一双袜子    < strong  >  三   </ strong  >   块!三双袜子只要    < strong  >  十   </ strong  >   块!!   </ div  >  
   </ div  >  

   < script  >   
   var  tip  =  document .  querySelector  (  '#tip'  )  ; 

  tip . style . color  =   'red'  ; 
    </ script  >  
 

通过设置 style 下的 color 属性 ,可以 更改字体 颜色。通过 style 设置的样式都是内联样式。

即便传入的选择器能匹配到多个 DOM 对象,此 方法 也只会返回 一个 DOM 对象。

1.6 element.querySelectorAll

返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList 。

此 方法 传入的参数与 querySelector 一致,但会返回匹配到的所有 DOM 对象。

    < ul  >  
     < li  >  我是列表1   </ li  >  
     < li  >  我是列表2   </ li  >  
     < li  >  我是列表3   </ li  >  
     < li  >  我是列表4   </ li  >  
   </ ul  >  

   < button   class   =  " change "   >  变!   </ button  >  

   < script  >   
   var  lis  =  document .  querySelectorAll  (  'li'  )  ; 
   var  btn  =  document .  querySelector  (  '.change'  )  ; 

  btn .  addEventListener  (  'click'  ,   function  (  )   { 
    lis .  forEach  (  function  ( li ,  index )   { 
      li . innerText  =  index ; 
     }  )  ; 
   }  )  ; 
    </ script  >  
 

element.querySelectorAll 返回的也是 一个 NodeList 。

2. 操作 DOM 节点

到目前为止已经做了许多 DOM 操作了,如使用 innerText 修改 文本,使用 style 修改 样式,这些其实都是在操作 DOM。

这里列举两个常用的操作。

2.1 修改 class 属性

修改 节点的 class 属性 ,这个操作频率是非常高的。

如使用 class 来控制元素的 显示 与隐藏。

    < style  >   
    .show    { 
      dis play  :  block ; 
   } 

    .hidden    { 
      dis play  :  none ; 
   } 
    </ style  >  

   < p   class   =  " tip show "   >  我要早睡早起,不能再熬夜了。   </ p  >  
   < button   class   =  " toggle "   >  切换   </ button  >  

   < script  >   
   var  toggleBtn  =  document .  querySelector  (  '.toggle'  )  ; 
   var  tipEle  =  document .  querySelector  (  '.tip'  )  ; 

  toggleBtn .  addEventListener  (  'click'  ,   function  (  )   { 
     var  className  =  tipEle . className ; 

     if   ( className .  indexOf  (  'show'  )   >   -  )   { 
      tipEle . className  =   'tip hidden'  ; 
       return  ; 
     } 

    tipEle . className  =   'tip show'  ; 
   }  )  ; 
    </ script  >  
 

通过 DOM 节点的 className 属性 ,来控制 class。

2.2 设置 / 获取 其他 属性

修改 class 也属于这个场景,但使用 className 更为频繁,所以单独拿出来介绍。

节点的许多状态是使用 属性 表示的,如 复选框 是否选中,就是由 checked 属性 决定。

    < label  >  
     < input   type   =  " check Box  "    class   =  " check Box  "   >  
  爱我别走
   </ label  >  

   < div     style   ="   margin-top  :  px ;   "   >  
     < button   class   =  " toggle "   >  切换!   </ button  >  
   </ div  >  

   < script  >   
   var  check Box   =  document .  querySelector  (  '.check Box '  )  ; 
   var  toggleBtn  =  document .  querySelector  (  '.toggle'  )  ; 

  toggleBtn .  onclick   =   function  (  )   { 
     var  checked  =  check Box  .  getAttribute  (  'checked'  )  ; 

     if   ( checked )   { 
      check Box  .  removeAttribute  (  'checked'  ,   ''  )  ; 
     }   else   { 
      check Box  .  setAttribute  (  'checked'  ,   'checked'  )  ; 
     } 
   }  ; 
    </ script  >  
 

getAttribute 方法 就可以获得某个 属性 的值。

setAttribute 用于给 属性 设置 属性 值。

removeAttribute 则是将 属性 从元素上移除。

这三个 方法 可以用于元素的任意 属性 , 包括 class 。

3. 其他

3.1 将集合转化为数组

通过几种 获取 DOM 节点的 方法 的返回值可以发现,当要 获取 多个 DOM 节点组成的集合的时候,返回的都不是数组。

@H_83_2 301 @ < div > < ul > < li > 1 </ li > < li > 2 </ li > < li > 3 </ li > </ ul > </ div > < script > var lis = document . querySelectorAll ( 'li' ) ; var filtered = lis . filter ( function ( li ) { return Number ( li . innerText % ) ; } ) ; </ script >

如使用上述例子对 获取 到的所有 DOM 节点 用 filter 方法 进行过滤是会报错的。

这个时候就需要通过一些方式,来获得由 DOM 节点组成的数组。

3.1.1 使用数组的 slice 方法

这里并不是让 DOM 节点的集合去 调用 slice 方法 ,而是利用 slice 方法 来将 DOM 节点的集合转化为数组。

    < div  >  
     < ul  >  
       < li  >  i   </ li  >  
       < li  >   lov e   </ li  >  
       < li  >  imooc   </ li  >  
     </ ul  >  
   </ div  >  

   < script  >   
   var  lisColl  =  document .  querySelectorAll  (  'li'  )  ; 
  
   var  lisArray1  =   [  ]  . slice .  call  ( lisColl )  ; 
   var  lisArray2  =  Array . prototype . slice .  call  ( lisColl )  ; 
  
	 var   map   =   function  ( li )   { 
     return  li . innerText ; 
   }  ; 
  
  console .  log  ( lisArray1 .  map  ( map )  .  join  (  ' '  )  )  ;   //  输出 :i  lov e imooc 
  console .  log  ( lisArray2 .  map  ( map )  .  join  (  ' '  )  )  ;   //  输出 :i  lov e imooc 
    </ script  >  
 

slice 方法 可以接收两个参数,分别是起始下标和结束下标,其作用是浅复制起始下标到结束下标的所有项,然后产生 一个 新数组返回,如果不提供参数,则直接浅复制所有项,形成 一个 新数组返回。

使用 [].slice.call(类数组) 或 Array.prototype.slice.call(类数组) 即可将 一个 类数组转化为数组。

通过在控制台观察 NodeList 和 HTMLCollection 类型,可以发现他们是符合类数组特性的。

所以就可以通过这种方式来转化成数组。

数组的 slice 方法 在执行的时候内部是使用循环来操作数组项的,所以操作 一个 类数组不会出现问题,使用 call 方法 将操作的数组指定为传入的伪数组,就达到了将类数组转化为数组的目的。

3.1.2 将数组的原型 方法 挂载到目标对象的原型上

    < div  >  
     < ul  >  
       < li  >  i   </ li  >  
       < li  >   lov e   </ li  >  
       < li  >  imooc   </ li  >  
     </ ul  >  
   </ div  >  

   < script  >   
  NodeList . prototype . join  =  Array . prototype . join ;   // 提供 join  方法  

   var  lisColl  =  document .  querySelectorAll  (  'li'  )  ; 

  lisColl . __proto__ . map  =  Array . prototype . map ;   // 提供 map  方法  

   var   map   =   function  ( li )   { 
     return  li . innerText ; 
   }  ; 

  console .  log  ( lisColl .  map  ( map )  .  join  (  ' '  )  )  ;   //  输出 :i  lov e imooc 
    </ script  >  
 

通过在 NodeList 原型上提供数组的 方法 ,就可以直接进行 方法 的 调用 。

其原理可以参考原型相关章节。

3.1.3 使用 for 循环

使用 for 循环遍历集合,将每一项放入新数组。

    < div  >  
     < ul  >  
       < li  >  i   </ li  >  
       < li  >   lov e   </ li  >  
       < li  >  imooc   </ li  >  
     </ ul  >  
   </ div  >  

   < script  >   
   var  lisColl  =  document .  querySelectorAll  (  'li'  )  ; 
   var  lis  =   [  ]  ; 
  
   var  i ,  len ; 
   for   ( i  =   ,  len  =  lisColl . length ;  i  <  len ;  i ++  )   { 
    lis .  push  ( lisColl [ i ]  )  ; 
   } 
  
   var  str  =  lis
     .  map  (  function  ( li )   { 
       return  li . innerText
     }  ) 
     .  join  (  ' '  )  ; 

  console .  log  ( str )  ;   //  输出 :i  lov e imooc 
    </ script  >  
 

这种方式没有特殊情况通常不会去使用。

3.1.4 使用 Array.from 方法

Array.from() 方法 从 一个 类似数组或可迭代 对象创建 一个 新的,浅拷贝的数组实。(MDN)

Array.from 可以将 一个 类数组转化为数组。

  var  arrayLike  =   { 
   :   '9'  , 
   :   '9'  , 
   :   '6'  , 
   :   ' bye!'  , 
  length :   , 
 }  ; 

 var  str  =  Array .  from  ( arrayLike )  .  join  (  ''  )  ; 

console .  log  ( str )  ;   //  输出 :996 bye! 
 

该 方法 由 ES2015 提供,所以旧版的浏览器 不支持 。

3.1.5 使用扩展运算符

扩展运算符也是由 ES2015 提供的。

    < div  >  
     < ul  >  
       < li  >  i   </ li  >  
       < li  >   lov e   </ li  >  
       < li  >  imooc   </ li  >  
     </ ul  >  
   </ div  >  

   < script  >   
   var  lisColl  =  document .  querySelectorAll  (  'li'  )  ; 
   var  arr  =   [  ... lisColl ]  ; 
  
  console .  log  ( Array .  isArray  ( lisColl )  )  ;   //  输出 :false 
  console .  log  ( Array .  isArray  ( arr )  )  ;   //  输出 :true 
    </ script  >  
 

... 即扩展运算符,根据使用场景,他还能被作为剩余参数操作符使用。

通过 Array.isArray 可以判断 一个 值是不是数组。

3.2 null 判断

当 获取 节点的 方法 没有匹配到任何元素的时候,是可能返回 null 或者 空集合的。

  var  el  =  document .  querySelector  (  '#dfsafds'  )  ; 
 var  elList  =  document .  querySelectorAll  (  '.dfsafds'  )  ; 

el . innerHTML  =   '<p>我写的 代码 从来不会报错!</p>'  ; 
elList [  ]  . innerHTML  =   '<p>我写的 代码 从来不会报错!</p>'  ; 

 // Cannot set property 'innerHTML' of null 
 

碰到这种情况,上述 代码 就报错了,假如后面 代码 存在渲染逻辑,则不会再继续执行,最后换来一份 辞退报告 。

所以在没有把握的情况下一定要进行空判断。

  var  el  =  document .  querySelector  (  '#dfsafds'  )  ; 

 if   ( el )   { 
  el . innerHTML  =   '<p>我写的 代码 从来不会报错!</p>'  ;   
 }   else   { 
  console .  log  (  '节点还没渲染出来'  )  ; 
 } 
 

或者使用 try ... catch ... 。

  var  el  =  document .  querySelector  (  '#dfsafds'  )  ; 

 try   { 
  el . innerHTML  =   '<p>我写的 代码 从来不会报错!</p>'  ; 
 }   catch   (  err  )   { 
  console .  error  ( err )  ; 
  console .  log  (  '节点还没渲染出来'  )  ; 
 } 
 

4. 小结

操作 DOM 是前端程序员的基本功,也是编写网页的重要知识之一。

获取 DOM 节点的 方法 有很多,部分 方法 返回的是 NodeList 或 HTMLCollection 类型,而不是数组,不能像操作数组一样操作这些集合,转换成数组可以更方便的利用数组的原生 方法 对其进行操作。

操作节点的时候,特别是动态渲染的节点,需 要做 空判断,防止程序报错中断执行。

DOM 与事件 ? ?DOM 和 JavaScript 的关系

查看更多关于获取和操作 DOM 节点的详细内容...

  阅读:45次

上一篇

下一篇

第1节:什么是 JavaScript    第2节:学习环境准备    第3节:调试方案    第4节:JavaScript 变量    第5节:JavaScript 数据类型    第6节:JavaScript if 语句    第7节:for 语句    第8节:JavaScript 算数运算符    第9节:JavaScript 比较运算符    第10节:JavaScript 逻辑运算符    第11节:JavaScript 函数    第12节:JavaScript 表达式    第13节:JavaScript 对象    第14节:JavaScript 字符串    第15节:JavaScript 数字    第16节:JavaScript 数组    第17节:JavaScript switch 语句    第18节:JavaScript while 语句    第19节:JavaScript 的 break 与 continue    第20节:JavaScript with    第21节:document.cookie    第22节:JavaScript Function    第23节:JavaScript Math    第24节:JavaScript Date    第25节:JavaScript RegExp    第26节:JavaScript JSON    第27节:什么是 DOM    第28节:DOM 和 JavaScript 的关系    第29节:获取和操作 DOM 节点    第30节:DOM 与事件    第31节:DOM 事件绑定    第32节:DOM 事件对象    第33节:DOM 事件流    第34节:事件相关的优化    第35节:自定义事件    第36节:表单校验    第37节:什么是 BOM    第38节:常用的 BOM 相关对象    第39节:BOM 常用属性和方法    第40节:AJAX    第41节:异常处理    第42节:三元运算符    第43节:逗号操作符    第44节:void    第45节:typeof    第46节:delete 操作符    第47节:debugger    第48节:getter & setter    第49节:new 运算符与构造函数    第50节:JavaScript 原型    第51节:JavaScript instanceof    第52节:JavaScript this    第53节:严格模式    第54节:作用域    第55节:闭包    第56节:变量提升    第57节:对象包装器    第58节:Lodash    第59节:moment    第60节:swiper    第61节:ECMAScript 6    第62节:Node.js    第63节:Babel    第64节:CSS 预处理器    第65节:代码规范    第66节:TypeScript    第67节:WebComponents    第68节:Vue、React、Angular    第69节:小程序    第70节:JavaScript 关键字    第71节:分号导致的问题    第72节:对象属性访问问题    第73节:this 使用问题    第74节:浮点数精度问题    第75节:独一无二的 NaN    第76节:避免全局污染    第77节:控制台观察对象问题    第78节:根据环境选择语言特性    第79节:相关资源