DOM

232 阅读9分钟

获取元素的方法

1. getElementById -> Dom对象

2. getElementsByTagName -> 类数组

3. getElementsByName -> 类数组

4. getElementsByClassName -> 类数组

offsetWidth = width(元素宽) + padding + border

offsetHeight = height + padding + border

clientWidth = width + padding

clientHeight = height + padding

offsetTop 距最近的已定位的祖先元素顶部的距离

offsetLeft 距最近已经定位的祖先元素的左边的距离

类数组如果没有获取到元素的话 返回[]

使用JS写CSS样式 都是字符串的形式

节点

节点类型

Node.ELEMENT_NODE 元素节点(1)

Node.ATTRIBUTE_NODE 属性节点(2)

Node.TEXT_NODE 文本节点(3)

Node.COMMENT.NODE 注释节点(8)

document.getElementsByTagName()函数获取到的为类数组

特征/方法 类型返回值 说明
nodeName String 节点名字(大写标签名) 元素节点返回TagName 文本节点返回#text 属性节点返回属性名
nodeValue String 节点的值:元素节点属性为null,文本节点属性为节点中的字符串,属性节点返回属性值
firstChild Node 指向在childNodes列表中的第一个子节点
lastChild Node 最后一个子节点
nodeTyoe Number 节点的类型常量值之一
nextSibling Node 指向后一个兄弟节点;如果这个节点就是最后一个兄弟节点,那么该值为null
previousSibling Node 指向前一个兄弟节点;如果这一节点就是第一个兄弟节点,那么该值为null
appendChild(node) Node 将node添加到childNodes的末尾
removeChild(node) Node 从childNodes中删除node
replaceChild(newnode,oldnode) Node 将childNodes中的oldnode替换成newnode
insertBefore(newnode,refnode) Node 在childNodes中的refnode之前插入newnode

nodeName:文本节点名称#text

空格回车算为文本节点

查找结点

nextSibling与nextElementSibling

//nextSibling 找到下一个节点 标准浏览器 会找到(回车 空格) IE浏览器下可以直接找到元素节点
//nextElementSibling 标准浏览器找到元素节点 IE不支持
//拿到元素的下一个节点,并判断节点类型是否为元素节点 如果不是继续查找下一个节点并返回
function next(elem) {
    do{
        elem = elem.nextSibling;
    }while(elem && elem.nodeType != 1)
    return elem;
}

firshChild

//查找第一个子节点
function first (elem) {
    elem = elem.firstChild ;
    if(elem.nodeType != 1){
        elem = next(elem);//next()上 next()函数
    }
    
}

nextElementSibling 标准浏览器找到元素节点 ie不支持

previousSibling 前一个节点 previousElementSibling

nodeValue 节点的值 元素节点的值为null

nodeType 返回节点类型值

children

<body>
   <ul>
   <li>111</li>
   <li>222</li>
   <li>333</li>
   <li>444</li>
   </ul>
    <script>
    //节点 
    var oUl = document.getElementsByTagName('ul')[0];
    console.log(oUl);
    //children 查找所有子节点 返回的是类数组
    console.log(oUl.children);
    console.log(oUl.innerHTML);
    var oH1 = document.createElement('h1');
    oH1.innerHTML = 'hello world';
    oUl.appendChild(oH1);
    </script>
</body>

创建节点

creatElement 创建节点

//创建一个<p>节点
var oP = document.createElement('p');

document.creaetElement(); appendChild 插入到末尾

<body>
    <div>
    <h1></h1>
    <h2></h2>
    <a href="#"></a>
    </div>
    <script>
        var oDiv = document.getElementsByTagName('div')[0];
        //创建节点
        var oP = document.createElement('p');
        //将<p>插入到<div>中所有节点的 尾部
        oDiv.appendChild(oP);
        var oA = document.getElementsByTagName('a')[0];
        //将<a>移除
        oDiv.removeChild(oA);
        var oH1 = document.getElementsByTagName('h1')[0];
        var oSpan =document.createElement('span');
        //在<div>中<h1>之前添加一个<span>标签
        oDiv.insertBefore(oSpan,oH1);
         //将<h2>替换为<span>
        var oH2 = document.getElementsByTagName('h2')[0];
        oDiv.replaceChild(oSpan,oH2);
    </script>
</body>

removeChild 删除节点

insertBefore (new,old) 插入到old元素之前

replaceChild (new,old) 替换

创建文本节点,传参数即是文本内容

<body>
 <script>
    //创建一个元素节点,传入标签名
    var p = document.createElement("p");
    var txt = document.createTextNode("创建文本节点,传参数即是文本内容");
    //将txt所引用的文本节点插入p到p的最后面(在这里p是空的)
    p.appendChild(txt);
    //直到现在,页面不会出现任何内容,必须将创建的节点插入到文档中
    document.body.appendChild(p);//p将出现在最后
    </script>
   

</body>

节点属性

1. setAttribute 设置属性

2. getAttribute 获取属性

3. removeAttribute 删除属性

<body>
    <p>1111</p>
    <script>
    var oP = document.getElementsByTagName('p')[0];
    //为<p>添加了一个 index属性 值为 1
    oP.setAttribute('index',1);
    //getAttribute()取出属性值
    console.log(oP.getAttribute('index'));
    //setAttribute()添加的属性可以在标签中展示
    //对象.属性 赋值后 在标签中无法显示
    oP.tag = 1;
    console.log("tag = ",oP.tag);//tag = 1
    //删除index属性
    oP.removeAttribute('index');
    </script>
</body>

函数下有一个原型 prototype

通过原型添加的属性和方法可以被实例化对象所共有

判断是数组还是对象

var arr = [];
var obj = {};
console.log(typeof arr);//object
console.log(typeof obj);//object

显然,typeof() 无法判断是否是数组与对象

1.obj.constructor =>Objct Array

var arr = new Array();
var obj = new Object();
console.log(arr.constructor);//Array
console.log(obj.constructor);//Object

2.arr instanceof Array 判断 arr 是否为Array 的 一个实例化对象

var arr = new Array();
var obj = new Object();
console.log(arr instanceof Array);//ture
console.log(obj instanceof Array);//false

事件委托->事件冒泡

动态添加的元素 无法在已进入页面绑定事件 需要把事件绑定在已存在的父元素上

this

  1. 函数中this是window

  2. 定时器this是window

  3. 对象this是当前对象

  4. 构造函数this是实例化对象

  5. 事件绑定this是绑定事件的Dom对象

var a = 1;
function f1(){
    console.log(this);
}
f1();//window

setTimeout(function() {
    console.log(this);
},1000)//window

var obj = {
    name:'Bob',
    code:function(){
        console.log(this);
    }
}
obj.code();//obj

function Person(_name) {
    this.name = _name;
    this.code = function(){
        console.log(this);
    }
}
var person = new Person();
person.code();//Person
<body>
 <div>123</div>
 <script>
    oDiv = document.getElementsByTagName('div')[0];
    oDiv.onclick = function(){
        setTimeout(function(){
            console.log(this)//Window
        },1000)
        console.log(this);//<div>
    }
 </script>
</body>

call()方法 改变指针 第一个参数 要改变指针的对象 后面的参数 是方法需要的参数

apply()方法 改变指针 第一个参数 要改变指针的对象 call与apply 传入参数方式不一样 , []

apply 两个参数 对象,数组

call()和apply 会自动调用方法 bind需要手动调用

call与apply的区别: 改变this指针并且自动调用方法 bind只改变了this指针

call 与bind的区别:call自动调用 bind手动调用 其他相同

<body>
    <div>123</div>
    <script>
        oDiv = document.getElementsByTagName('div')[0];
        function f1(x,y){
           console.log(this,x,y);
        }
        var obj = {
            name :'Bob',
            age :'18'
        }
        f1.call(oDiv,2,3);//<div> 2 3
        f1.apply(obj,[2,3]);//Object 2 3
        f1.bind(oDiv,3,4)();//<div> 3 4
    </script>
</body>

闭包

闭包

  1. 外部函数里面有一个内部函数(函数套函数)
  2. 内部函数会使用外部函数里的局部变量
function fun1() {
    var a = 1;
    return function() {
        console.log(a)
    }
}
var aa = fun1();
console.log(aa);
aa();

优点:

  1. 闭包里的变量 不会被垃圾回收机制清理 一直在内存里
  2. 可以拿到索引值

缺点: 造成内存泄漏

函数的立即调用

例一

var name = "The window";
    var object = {
    name :"My Object",
        getNameFunc :function(){
            return function(){ //->window
                return this.name;
            }
        }
    }
    alert(object.getNameFunc()());//The window
    var name = "The window";//window.name
    var object = {
        name :"My Object",
        getNameFunc :function(){
            //this->object
            var that = this;
            return function(){
                return that.name;
            }
        }
    }
    alert(object.getNameFunc()());// My Object

例二

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>
var oLi = document.querySelectorAll('li');
  for(var i = 0;i< oLi.length;i++){
      (function(index){
          oLi[index].onclick = function(){
              console.log(index)
          }
      })(i)
  }

类(构造方法or构造函数):表示具有相同的属性方法的集合 类名的首字母要大写

声明类的时候 属性写在构造函数中 方法写在原型(prototype)中

原型中的方法被实例化对象所共用

function Person(_name,_age,_weight) {
    this.name = _name,
    this.age = _age,
    this.weight = _weight,
    this.code = function(){
        console.log('hello')
    }
}
//实例化一个对象
var people1 = new Person('John',19,'60kg');
console.log(people1.name);//John
console.log(people1.age);//19
console.log(people1.weight);//60kg
people.code();//hello
//没有传入参数为undefined
var people2 = new Person('Bob',20)
console.log(people2);//weight: undefined

原型:函数下有一个原型 prototype

通过原型添加的属性和方法可以被实例化对象所共享

prototype 下有一个constructor 代表的是构造函数

通过原型添加的属性

function Person(_name,_age,_weight) {
    this.name = _name,
    this.age = _age,
    this.weight = _weight,
    this.code = function(){
        console.log('hello')
    }
}
Person.prototype.height = '175';

事件

事件冒泡与事件捕获

**点击事件

oDiv.onclick = function(event) {
    //this
    evetn = window.event ||event//兼容IE浏览器的方式
    //event.clientX
    //event.clientY
    event.preventDefault();//阻止默认事件
    e.targe//事件源 触发当前事件的源头
    return false //组织默认事件
}

事件冒泡:从里向外(触发了子元素的事件后 就会冒泡到父元素的事件)

事件捕获:从外向里

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1{
            width:200px;
            height:200px;
            background:red;
        }
        #div2{
            width:100px;
            height:100px;
            background:blue;
        }
    </style>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
    <script>
        var oDiv1 = document.getElementById('div1');
        var oDiv2 = document.getElementById('div2');
        oDiv1.onclick = function() {
            console.log('div1')
        }
           //事件冒泡  从里向外传播
        oDiv2.onclick = function() {
            console.log('div2');
        }
       
       
    </script>
</body>

给予同一元素相同事件时,执行后一个事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #div1{
            width:200px;
            height:200px;
            background:red;
        }
    </style>
</head>
<body>
    <div id="div1" > </div>
    <script>
        var oDiv1 = document.getElementById('div1');
        oDiv1.onclick = function() {
            console.log('hello')
        }
        oDiv1.onclick = function() {
            console.log('world');
        }
       //显示world
       
    </script>
</body>
</html>

addEventListener(事件,方法,布尔值):添加事件监听 可以给元素绑定多个相同事件

false 事件冒泡

<style>
    #div1{
        width:200px;
        height:200px;
        background:red;
    }
    #div2{
        width:100px;
        height:100px;
        background:blue;
    }
</style>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
<script>
    var oDiv1 = document.getElementById('div1');
    var oDiv2 = document.getElementById('div2');

   oDiv1.addEventListener('click',function(){
       console.log('div1')        
   },false)
   oDiv2.addEventListener('click',function(){
       console.log('div2')
   },false)
</script>
</body>
</html>

ture 事件捕获

oDiv1.addEventListener('click',function(){
   console.log('div1')        
},true)
oDiv2.addEventListener('click',function(){
   console.log('div2')
},true)

即有冒泡又有捕获, 先捕获后冒泡

var oDiv1 = document.getElementById('div1');
var oDiv2 = document.getElementById('div2');
oDiv1.addEventListener('click',function(){
   console.log('捕获:','div1')        
},true)
oDiv2.addEventListener('click',function(){
   console.log('捕获:','div2')
},true)
oDiv1.addEventListener('click',function(){
   console.log('冒泡:',''div1')        
},false)
oDiv2.addEventListener('click',function(){
   console.log('冒泡:',''div2')
},false)//捕获: div1 捕获: div2 冒泡: div2 冒泡: div1

阻止事件冒泡

var oDiv1 = document.getElementById('div1');
var oDiv2 = document.getElementById('div2');
oDiv1.onclick = function(e) {
    console.log('div1');
}
oDiv2.onclick = function(e) {
    //阻止事件冒泡
    e.stopPropagation();
    console.log('div2')
}

事件委托

动态添加的元素,无法在一进入页面时绑定事件,需要把事件绑定在已存在的父元素上

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        li{
            background:red;
        }
        ul{
            background:#000;
        }
    </style>
</head>
<body>
    <button>添加</button>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    <script>
        var aLi = document.getElementsByTagName('li');
        var oUl = document.getElementsByTagName('ul')[0];
        var oBtn = document.getElementsByTagName('button')[0];
        oBtn.onclick = function() {
            var oLi = document.createElement('li')
            oLi.innerHTML = Math.random();
            //给ul下的li追加元素li
            oUl.appendChild(oLi);
            }
        oUl.onclick = function(e){
        //判断点击的事件源是否为li
            if(e.target.tagName == 'LI'){
            //输出li内容
                console.log(e.target.innerHTML)
            }
        }
    </script>
</body>
</html>