JS-DOM

作者: 哎呦呦胖子斌 | 来源:发表于2018-10-19 16:42 被阅读0次
    有的没的

    DOM就是把html视为一个层次结构(树形结构)的文档

    文档(Document):一个页面就是一个文档,html或者xml文件,html主要用来展示数据,xml侧重于存储数据

    html文件看做是一个文档,由于万物皆对象,所以把这个文档看成是一个对象,文档中的所有标签都可以看成是一个对象。

    元素(Element):Html文档中的所有标签

    页面中的每个标签都是一个元素,每个元素都可以看成是一个对象,标签可以嵌套,标签中有标签,元素中有元素。html页面中都有一个跟标签,html,它也称为根元素。

    节点(Node):文档中的所有内容都可以称之为节点:标签、属性、文本。

    根元素(root):文档中的第一个元素,html文档就是<html>,只有一个

    文本节点

    属性节点

    dom可以做什么

    1. 找对象(元素)

    2. 设置元素属性

    3. 设置元素样式

    4. 动态创建和删除元素

    5. 事件—触发响应

        --事件源(事件的触发者)

        --事件名称

        --事件响应程序

         一个栗子:

             点击操作:事件

            按钮:事件源

            点击:事件名称

             被点击了:触发了

            弹框了:响应

        html标签中的id属性中存储的值是唯一的,id属性就像是人的身份证号码一样,不能重复,他是页面中的唯一标识;

        var btObj = document.getElementById(‘id属性的值’);返回的是一个元素对象,他有很多的属性,可以通过’.属性’来获取属性;

        btObj.onclick = f2;(f2后面不要加括号)

    innerText、textContent和innerHTML

    设置标签中的文本内容,应该使用textContent属性,谷歌、火狐支持,IE8不支持;innerText属性,谷歌、火狐、IE8都支持,它是IE8的标准

    获取标签中的文本内容,textContent属性,谷歌、火狐支持,IE8不支持(输出undefined);inertText属性,谷歌、火狐、IE8都支持

    如果这个属性在浏览器中不支持,那么这个属性的类型是undefined

    //设置任意标签中间的任意文本内容
    
      function  setTextContent (element , text){
    
      if(typeof(element.textContent) === undefined){
    
      element.innerText = text;
    
     }else {
    
      element.textContent = text;
    
     }
    
     }
    
      //获取任意标签中间的文本内容
    
      function  getTextContent (element){
    
      if(typeof(element.textContent) === undefined){
    
      return  element.innerText;
    
     }else {
    
      return  element.textContent;
    
     }
    
     }
    

        innerHTML也可以设置文本内容,并且任何浏览器都是支持的;而且它还可以设置html标签。同样,获取标签的时候,innerHTML也能获取到标签。

    总结:

        想要设置标签内容,就用innerHTML,如果想要设置文本内容,innerText或者textContent或者innerHTML,推荐使用innerHTML,没有兼容性问题。

        获取的时候,innerText可以获取标签中的文本内容,但是如果标签中还有标签,那么最里面的标签文本也能获取到;innerHTML在获取标签中的文本时,能获取到标签中的文本,如果标签中还有标签,那么获取到的就是标签中的标签。

    自定义属性
    <ul  id="score">
    
      <li  score='10分'>你的成绩</li>
    
      <li  score='20分'>他的成绩</li>
    
     <li  score='30分'>她的成绩</li>
    
      <li  score='40分'>它的成绩</li>
    
      <li  score='50分'>谁的成绩</li>
    
    </ul>
    
    var  list = document.getElementsByTagName('li');
    
      for(var  i = 0;i<list.length;i++){
    
      list[i].onclick = function(){
    
      alert(this.getAttribute('score'));
    
      //score属性时设置在<li>标签上的,而this指的是DOM对象,直接this.score是获取不到这个属性值的,
    
      //要通过getAttribute方法获取标签的某个属性
    
      //同样,要设置标签的属性,要使用list[i].setAttribute()方法,其中有两个参数,一个属性名,一个属性值
    
     }
    
     }
    

        一般在设置自定义属性的时候,不通过上面的方式对标签添加属性,如果标签很多的话会造成代码重复,一般是通过循环遍历,使用list[i].setAttribute()方式添加标签元素。

        移除自定义属性时,使用的方法是element.removeAttribute(‘属性名’);属性和值都没有了,这种方式也可以移除元素自带的属性。

    节点

         节点有三个属性:nodeType、nodeName、nodeValue

    nodeType:节点的类型,1:标签,2:属性,3:文本

    nodeName:节点的名字,标签节点:大写的标签名字;属性节点:小写的属性名字;文本节点:#text

    nodeValue:节点的值:标签节点:null;属性节点:属性值;文本节点:文本内容

    12行代码
    <div  id="dv">
    
         <ul id="uu">第一个子节点
    
      <li>第一个子元素</li>
    
      <li>前一个兄弟元素</li>前一个兄弟节点
    
      <li  id="some">吼吼</li>后一个兄弟节点
    
      <li>后一个兄弟元素</li>
    
      <li>最后一个子元素</li>最后一个子节点
    
      </ul>
    
      </div>
    
    var  ulObj = document.getElementById('uu');
    
      //ul的父元素
    
      console.log(ulObj.parentElement);
    
      //ul的父节点
    
      console.log(ulObj.parentNode);
    
      //ul的子元素
    
      console.log(ulObj.children);
    
      //ul的子节点
    
      console.log(ulObj.childNodes);
    
      console.log('----------------------------------------------');
    
      //ul的第一个子元素
    
      console.log(ulObj.firstElementChild);
    
      //ul的第一个子节点
    
      console.log(ulObj.firstChild);
    
      //ul的最后一个子元素
    
      console.log(ulObj.lastElementChild);
    
      //ul的最后一个子节点
    
      console.log(ulObj.lastChild);
    
      var  someObj = document.getElementById('some');
    
      //某个元素的前一个兄弟元素
    
      console.log(someObj.previousElementSibling)
    
      //某个元素的前一个兄弟节点
    
      console.log(someObj.previousSibling);
    
      //某个元素的后一个兄弟元素
    
      console.log(someObj.nextElementSibling);
    
      //某个元素的后一个兄弟节点
    
      console.log(someObj.nextSibling);
    

        分割线后面的代码在IE8中会有写问题,所有的获取元素的不再支持,输出undefined,在获取节点时,以获取第一个节点(firstChild)为例,如果第一个节点中有文本,则这个方法返回的还是第一个节点,如果第一个节点中没有文本,则这个方法返回的是第一个元素。但在IE11中又重新支持。恩,IE这样玩也是……

        所以就有了下面的兼容性代码:

    function  getFirstElementChild(element){
    
      if(element.firstElementChild){
    
     return element.firstElementChild;
    
     }else{
    
      var  node = element.firstChild;
    
      //一直判断node是否存在,并且是否是标签(标签的nodeType==1),如果是则返回,如果不是,则获取node的后一个兄弟节点
    
      while(node && node.nodeType!= 1){
    
      node = node.nextSibling;
    
     }
    
      return  node;
    
     }
    
     }
    
    获取元素的方法

    根据id属性的值获取元素,返回来的是一个元素对象

    getElementById(‘id属性的值’)

    根据标签名字获取元素,返回来的是一个伪数组,里面保存了多个DOM对象

    getElementsByTagName(‘标签名字’)

    //下面的几个,有的浏览器不支持

    根据name属性的值获取元素,返回来的是一个伪数组,里面保存了多个DOM对象

    getElementsByName(‘name属性的值’)

    根据类样式的名字来获取元素,返回来的是一个伪数组,里面保存了多个DOM对象

    getElementsByClassName(‘类样式的名字’)

    根据选择器获取元素,返回来的是一个元素对象

    querySelector(‘选择器的名字’)

    根据选择器获取元素,返回来的是一个伪数组,里面保存了多个DOM对象

    querySelectorAll(‘选择器的名字’)

    创建元素的三种方式
    document.write

    document.write(‘标签代码及内容’)

    这种方式创建元素有缺陷:如果在页面加载完毕后再通过这种方式创建元素的话,整个页面就会被覆盖掉。

    对象.innerHTML

    对象.innerHTML(‘标签代码及内容’)

    在谁里面添加标签,就用谁做对象

    <input  type="button"  value="动态创建列表"  id="createList">
    
    <div  id="list"></div>
    
      var  arrName = ['陈信宏', '温尚翊', '石锦航', '蔡升晏', '刘谚明'];
    
      var  divObj = document.getElementById('list');
    
      document.getElementById('createList').onclick = function () {
    
      var  str = '<ul>';
    
      for (var  i = 0; i < arrName.length; i++) {
    
     str += '<li>';
    
      str += arrName[i];
    
      str += '</li>';
    
     }
    
      str += '</ul>';
    
      divObj.innerHTML = str;
    
      var  list = divObj.getElementsByTagName('li');
    
      for (var  j = 0; j < list.length; j++) {
    
     list[j].style.cursor = 'pointer';
    
      list[j].onmouseover = function () {
    
      this.style.backgroundColor = 'green';
    
     }
    
      list[j].onmouseout = function () {
    
      this.style.backgroundColor = '';
    
     }
    
     }
    
     }
    
    createElement
    var  appendChd = document.getElementById('append');
    
      document.getElementById('addChild').onclick = function(){
    
      var  pObj = document.createElement('p');
    
      setTextContent(pObj,'我是一个p标签');
    
      appendChd.appendChild(pObj);
    
     }
    

    一个栗子:动态创建表格

      var  arrTable = [
    
     {name:'百度',href:'https://www.baidu.com/'},
    
     {name:'谷歌',href:'https://www.google.cn/'},
    
     {name:'百度',href:'https://www.baidu.com/'},
    
     {name:'谷歌',href:'https://www.google.cn/'},
    
     {name:'百度',href:'https://www.baidu.com/'},
    
     {name:'谷歌',href:'https://www.google.cn/'}
    
     ]
    
      document.getElementById('createTable').onclick = function(){
    
      var  tableObj = document.createElement('table');
    
      var  tabDivObj = document.getElementById('table');
    
      tabDivObj.appendChild(tableObj);
    
      tableObj.border = '1';
    
      tableObj.cellPadding = '0';
    
      tableObj.cellSpacing = '0';
    
      for(var  i = 0;i<arrTable.length;i++){
    
      var  col = document.createElement('tr');
    
      tableObj.appendChild(col);
    
      var  row1 = document.createElement('td');
    
      row1.innerText = arrTable[i].name;
    
      row1.style.padding = '10px';
    
      var  row2 = document.createElement('td');
    
      row2.innerHTML = "<a href='"+arrTable[i].href+"'>"+arrTable[i].name+"</a>";
    
      row2.style.padding = '10px';
    
      tableObj.appendChild(row1);
    
      tableObj.appendChild(row2);
    
     }
    
     }
    

    何时使用匿名函数,何时使用命名函数?

        如果是循环的方式添加事件,推荐使用命名函数;如果不是循环的方式添加事件,推荐使用匿名函数。

    元素的相关方法

    appendChild(元素) 追加元素,旧元素后移,新元素在第一个位置

    insertBefore(新元素,旧元素) 插入元素

    replaceChild(新元素,旧元素) 替换旧元素

    removeChild(旧元素) 删除旧元素

    为元素绑定事件

    为同一个元素绑定多个相同的事件

    1. 对象.on事件名 = 函数(命名函数、匿名函数)

    element.onclick = function(){}

    2.addEventListener(); 谷歌、火狐是支持的,IE8****不支持

    三个参数

    第一个参数:事件的类型------事件的名字没有on

    第二个参数:事件的处理函数------命名函数、匿名函数

    第三个参数:布尔类型,false表示事件是冒泡阶段(从里向外),true表示事件是捕获阶段(从外向里)

    3.attachEvent(); 只有IE8****支持

    两个参数

    第一个参数:事件类型------事件的名字,有on

    第二个参数:事件的处理函数------命名函数、匿名函数

    兼容性代码

    //为任意元素绑定任意事件
    
    function  addEventListener(element,type,fn){
    
      //判断一个对象有没有一个方法,直接对象.方法名,不要加括号
    
      //加括号的意思就是执行方法,得到的是方法的返回值
    
      if(element.addEventListener){
    
      element.addEventListener(type,fn,false);
    
     }else  if(element.attachEvent){
    
      element.attachEvent('on'+type,fn);
    
     }else {
    
      element['on'+type] = fn;
    
     }
    
    }
    

    addEventListener和attachEvent对比

    相同点:

    都可以为元素绑定事件

    不同点:

    1. 方法名不一样

    2. 参数个数不一样addEventListener参数有三个,attachEvent参数有两个

    3. addEventListener中事件的名字没有on,attachEvent中事件的名字有on

    4. addEventListener谷歌、火狐、IE11支持,IE8不支持,attachEvent谷歌、火狐、IE11不支持,IE8支持

    5. addEventListener方法中的this是当前绑定对象,attachEvent方法中的this是window

    为元素解绑事件

    注:用什么样的方式绑定事件,就要用什么样的方式解绑事件

    1. 对象.on事件名字 = null;

    2. remoceEventListener()

    三个参数:

    第一个参数:事件的类型------事件的名字没有on

    第二个参数:事件的处理函数------命名函数

    第三个参数:布尔类型,false表示事件是冒泡阶段(从里向外),true表示事件是捕获阶段(从外向里)

    这种方式解绑事件,需要在绑定事件的时候使用命名函数,最后解绑的时候使用同样的函数名

    function  f1(){};
    
    document.getElementById('btn').addEventListener('click',f1,false);
    
    document.getElementById('btn').removeEventListener('click',f1,false);
    

    3. detachEvent()

    两个参数:

    第一个参数:事件类型------事件的名字,有on

    第二个参数:事件的处理函数------命名函数

    同样,在绑定事件的时候需要使用命名函数,在解绑的时候使用同样的函数名

    兼容代码

    //为任意元素解绑任意事件
    
    function  removeEventListener(element,type,fnName){
    
      //判断一个对象有没有一个方法,直接对象.方法名,不要加括号
    
      //加括号的意思就是执行方法,得到的是方法的返回值
    
      if(element.removeEventListener){
    
      element.removeEventListener(type,fnName,false);
    
     }else  if(element.detachEvent){
    
      element.detachEvent('on'+type,fnName);
    
     }else {
    
      element['on'+type] = null;
    
     }
    
    }
    
    阻止浏览器的默认事件

    两种方式:

    1. return false:

    2. e.preventDefault() 这种方式IE8不支持

    事件冒泡

    多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素的事件触发了,外面元素的相同事件(相同事件的意思是,相同类型的事件)也会被触发。

    阻止事件冒泡

    在想要阻止的事件处理函数中,最后调用这么一句话

      document.getElementById('btn').onclick = function(){
    
      window.event.cancelBubble = true;
    
     }
    

    谷歌、IE8****都支持,火狐不支持

    或者是使用事件处理对象

      document.getElementById('btn').onclick = function(e){
    
      e.stopPropagation();
    
     }
    

    谷歌、火狐支持,IE8****不支持

    可以看到,IE8中的window.event和谷歌火狐中的e对象时相同的,在IE8中,没有e这个事件处理参数,所以不能调用其对应方法。

    事件流
    冒泡事件流

    事件的传播是从下往上传,即从DOM树的叶子到根。

    image.png
    捕获事件流

    事件的传播是从上往下,即从跟到叶子

    image.png
    var  divObjs = [my$('div1'),my$('div2'),my$('div3')];
    
      divObjs.forEach(function(element){
    
      element.addEventListener('click',function(e){
    
      console.log(this.id);
    
      console.log(e.eventPhase);
    
     },true);
    
     })
    
    /**
    
     * 1.冒泡事件
    
     * 2.目标事件
    
     * 3.捕获事件
    
     *
    
     * 标识这是什么事件的属性在事件参数对象中存在,也就是上面的e,e.eventPhase
    
     * 哪个对象触发的点击事件,那么这个对象就是目标对象,它触发的事件就是目标事件,对应的e.eventPhase属性值为2
    
     * 通过冒泡触发的事件,对应的对象的e.eventPhase属性值就为1
    
     * 通过捕获触发的事件,对应的对象的e.eventPhase属性值就为3
    
     */
    

    总结:

    事件的出发过程中可能会出现事件冒泡,为了阻止事件冒泡:

    window.event.cancelBubble = true;谷歌、IE8支持,火狐不支持,

    window.event是一个对象,是IE中的标准;

    e.stopPropagation();谷歌、火狐支持,IE8不支持,

    window.event和e都是事件参数对象,一个是IE的标准,一个是火狐的标准,事件参数e在IE8的浏览器中是不存在的,此时用window.event来代替。

    事件的阶段有三个,通过e.eventPhase这个属性可以知道当前的事件是什么阶段的,如果这个属性的值是1,表示为捕获阶段,2表示目标阶段,3表示冒泡阶段;一般默认为冒泡阶段,很少用捕获阶段。

    一个栗子,事件的类型在e.type属性中

    //为同一个元素绑定不同的事件,指向相同的事件处理函数
    
      my$('div1').onclick = f1;
    
      my$('div1').onmouseover = f1;
    
      my$('div1').onmouseout = f1;
    
      function  f1 (e){
    
      console.log(e.type)
    
     }
    
    offset系列

    在style标签中设置的样式属性时获取不到的,但在标签的style属性中设置的样式属性时可以获取到的。以后获取元素的高和宽用offset系列。

    元素.offsetWidth; 元素的宽(有边框的,和元素中的内容是没有关系的)

    元素.offsetHeight; 元素的高(有边框的,和元素中的内容是没有关系的)

    元素.offsetLeft; 元素距离左边的距离

    元素.offsetTop; 元素距离上边的距离

    解释一下后面两个

    没有脱离文档流时

    offsetLeft:父级元素的****margin + 父级元素的padding + 父级元素的border + 自己的margin

    脱离文档流时

    offsetLeft:大小和父级元素的margin、padding、border已经没有关系了,只和自己的****left****和margin****有关,但相对的位置是相对父元素的位置(也就是说,这个时候,找到子元素的父元素是关键)

    scroll系列

    scrollWidth:元素中内容的实际宽度(没有边框),当没有内容或者内容没有超出元素时,还是元素的宽度

    scrollHeight:元素中内容的实际高度(没有边框),当没有内容或者内容没有超出元素时,还是元素的高度

    scrollTop:元素中的内容向上卷曲过去的距离

    scrollLeft:元素中的内容向左卷曲过去的距离

    兼容性代码:

    //获取滚动条的滚动距离(上、左)
    
    function  getScroll (){
    
      return {
    
      top:window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,
    
      left:window.pageYOffset||document.documentElement.scrollLeft||document.body.clientLeft||0
    
     };
    
    }
    

    固定导航栏案例

    //这个地方有个注意点,就是设置marginTop的时候,一定要记得加‘px’
    
      window.onscroll = function () {
    
      console.log(getScroll().top);
    
      if(getScroll().top > my$('d1').offsetHeight){
    
      my$('d2').className = 'div2 fixed';
    
      my$('d3').style.marginTop = my$('d2').offsetHeight+'px';
    
     }else{
    
      my$('d2').className = 'div2';
    
      my$('d3').style.marginTop = 0 +'px';
    
     }
    
     }
    
    client系列

    可视区域:能看到的元素的大小

    clientWidth:可视区域的宽,没有边框,有padding

    clientHeight:可视区域的高,没有边框,有padding

    clientLeft:左边框的宽度

    clientTop:上边框的宽度

    因为padding也是内容的一部分,所以padding并不算在这个值里面

    clientX,offsetX,layerX,pageX,screenX,X

    https://www.cnblogs.com/xulei1992/p/5659923.html

    先来个定义

    screenX/Y:鼠标位置相对于屏幕的坐标

    pageX/Y:鼠标位置相对于文档边缘的距离,当滚动条滚动时,对应的值会增加,可以理解为相对于文档的top和left,而不是相对于可是区域的top、left(IE8不支持)

    clientX/Y:鼠标位置相对于文档边缘的距离,当公东条滚动时,对应的值不会增加

    offsetX/Y:鼠标位置相对于当前元素(块或行内块)的距离,google浏览器的边缘包含border,IE浏览器的边缘不包含边框

    啥意思呢?看图说话

    google浏览器中,当鼠标放在border上时,offset的值是正的


    image.png

    在IE浏览器中,当鼠标放在border上时,offset的值是负的


    image.png

    X/Y:与clientX/Y相同,火狐浏览器不支持

    layerX/Y:与pageX/Y相同(不包括IE浏览器),IE11浏览器中和clientX/Y相同(IE8不支持)

    测试代码自存

    <!DOCTYPE html>
    
    <html>
    
    <head>
    
      <title></title>
    
      <script  type="text/javascript"  src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    
      <style>
    
      body {
    
      margin: 0;
    
      padding: 0;
    
     }
    
      .div {
    
      text-align: center;
    
      font-size: 24px;
    
      height: 300px;
    
      width: 1300px;
    
      line-height: 300px;
    
      color: yellow;
    
     }
    
      #d1 {
    
      background-color: #FF3B2F;
    
     }
    
      #d2 {
    
      background-color: #4CDA64;
    
     }
    
      #d3 {
    
      background-color: #007AFF;
    
      border: 50px  solid  #004400;
    
      width: 500px;
    
      display: inline-block;
    
     }
    
      #d3-2{
    
      background-color: #FF2C55;
    
      width: 500px;
    
      border: 10px  solid  #019EE4;
    
      display: inline-block;
    
     }
    
      #d4 {
    
      position: fixed;
    
      background-color: #FFCC00;
    
      height: 340px;
    
      width: 120px;
    
      top: 0;
    
      bottom: 0;
    
      left: 50px;
    
      margin: auto  0;
    
      font-family: "arial";
    
      font-size: 16px;
    
     }
    
      </style>
    
      <script  type="text/javascript">
    
      $(function () {
    
      document.onmousemove = function (e) {
    
      if (e == null) {
    
      e = window.event;
    
     }
    
      var  html = "<span style='color:#000'>screenX:" + e.screenX + "</span><br/>";
    
      html += "<span style='color:#000'>screenY:" + e.screenY + "</span><br/><br/>";
    
      html += "<span style='color:#f00'>clientX:" + e.clientX + "</span><br/>";
    
      html += "<span style='color:#f00'>clientY:" + e.clientY + "</span><br/><br/>";
    
      html += "<span style='color:#f00'>x:" + e.x + "</span><br/>";
    
     html += "<span style='color:#f00'>y:" + e.y + "</span><br/><br/>";
    
      html += "<span style='color:#00f'>layerX:" + e.layerX + "</span><br/>";
    
      html += "<span style='color:#00f'>layerY:" + e.layerY + "</span><br/><br/>";
    
      html += "<span style='color:#00f'>pageX:" + e.pageX + "</span><br/>";
    
      html += "<span style='color:#00f'>pageY:" + e.pageY + "</span><br/><br/>";
    
      html += "<span style='color:#070'>offsetX:" + e.offsetX + "</span><br/>";
    
      html += "<span style='color:#070'>offsetY:" + e.offsetY + "</span><br/>";
    
      $("#d4").html(html);
    
     };
    
     });
    
      </script>
    
    </head>
    
    <body>
    
      <div  id="d1"  class="div">div1 height:300px width:1300px</div>
    
      <div  id="d2"  class="div">div2 height:300px width:1300px</div>
    
      <div  id="d3"  class="div">div3 height:300px width:500px</div>
    
      <div  id="d3-2"  class="div">div3-2 height:300px width:500px <span  style="width:50px;height:50px;background:#000;display: inline-block;border: 5px solid #fff;line-height: 45px;">dddd</span></div>
    
      <div  id="d4"></div>
    
    </body>
    
    </html>
    
    通过document获取元素

    获取body,得到的是一个标签

    document.body

    获取title,得到的是title文本

    document.title

    获取html

    document.documentElement

    获取元素的所有样式属性
    window.getComputedStyle(my$('d1'),null)
    

    这样就能获取到d1元素的所有样式,返回值是一个样式对象,通过.属性即可获得属性值(IE8不支持)

    my$('d1').currentStyle
    

    IE8支持

    兼容性代码

    //获取元素的所有样式属性
    
    function  getStyle (element,attr){
    
      return  window.getComputedStyle? window.getComputedStyle(element,null)[attr]:element.currentStyle[attr];
    
    }
    
    元素隐藏的不同方式

    不占位:

    display:none;

    相关文章

      网友评论

          本文标题:JS-DOM

          本文链接:https://www.haomeiwen.com/subject/afeszftx.html