08-JS基础-DOM相关

  • 简介
    Document Object Model 文档对象模型,通过DOM可以来任意来修改网页中各个内容。
    文档指的是网页,一个网页就是一个文档。
    对象指将网页中的每一个节点都转换为对象。
    模型用来表示节点和节点之间的关系,方便操作页面。
  • 节点(Node)
    节点是构成网页的最基本的单元,网页中的每一个部分都可以称为是一个节点。
    虽然都是节点,但是节点的类型却是不同的,常用的节点:
    - 文档节点 (Document),代表整个网页
    - 元素节点(Element),代表网页中的标签
    - 属性节点(Attribute),代表标签中的属性
    - 文本节点(Text),代表网页中的文本内容
DOM操作

在网页中浏览器已经为我们提供了document对象,它代表的是整个网页,它是window对象的属性,可以在页面中直接使用。

document查询方法:
1)根据元素的 id 属性查询一个元素节点对象:
  document.getElementById("id属性值");
2)根据元素的name属性值查询一组元素节点对象:
  document.getElementsByName("name属性值");
3)根据标签名来查询一组元素节点对象:
  document.getElementsByTagName("标签名");

元素的属性:

读取元素的属性:
语法:元素.属性名

修改元素的属性:
语法:元素.属性名 = 属性值

innerHTML
使用该属性可以获取或设置元素内部的HTML代码

city. innerHTML += "<li>广州</li>";
  • 文档的加载
    浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。
    如果将js代码编写到页面的上边,当代码执行时,页面中的DOM对象还没有加载,此时将会无法正常获取到DOM对象,导致DOM操作失败。
    解决方式一:
    可以将js代码编写到body的下边
<body>
    <button id="btn">按钮</button>
    <script>
        var btn = document.getElementById("btn");
        btn.onclick = function(){
                    
        };
    </script>
</body>

解决方式二:
将js代码编写到window.onload = function(){}中,
window.onload 对应的回调函数会在整个页面加载完毕以后才执行。

<script>
    window.onload = function(){
        var btn = document.getElementById("btn");
        btn.onclick = function(){
                    
        };
    };
</script>
  • DOM查询
  1. 通过具体的元素节点来查询

通过标签名查询当前元素的指定后代元素
元素.getElementsByTagName()

获取当前元素的所有子节点, 会获取到空白的文本子节点,根据DOM标准,标签间空白也会当成文本子节点。
元素.childNodes

获取当前元素的所有子元素
元素.children

获取当前元素的第一个子节点
元素.firstChild

获取当前元素的最后一个子节点
元素.lastChild

获取当前元素的父元素
元素.parentNode

获取当前元素的前一个兄弟节点
元素.previousSibling

获取当前元素的后一个兄弟节点
元素.nextSibling

  1. innerHTML和innerText
    这两个属性并没有在DOM标准定义,但是大部分浏览器都支持这两个属性。
    两个属性作用类似,都可以获取到标签内部的内容,
    不同是innerHTML会获取到html标签,而innerText会自动去除标签。
    如果使用这两个属性来设置标签内部的内容时,没有任何区别的。

读取标签内部的文本内容
元素.firstChild.nodeValue

  • document对象的其他的属性和方法

document.all
获取页面中的所有元素,相当于document.getElementsByTagName("*");

document.documentElement
获取页面中html根元素

document.body
获取页面中的body元素,body的引用

document.getElementsByClassName()
根据元素的class属性值查询一组元素节点对象(这个方法不支持IE8及以下的浏览器)

document.querySelector()
根据CSS选择器去页面中查询一个元素
如果匹配到的元素有多个,则它会返回查询到的第一个元素

document.querySelectorAll()
根据CSS选择器去页面中查询一组元素
会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个

  • DOM增删改

根据标签名创建一个元素节点对象
document.createElement()

根据文本内容创建一个文本节点对象
document.createTextNode()

向父节点中添加指定的子节点
父节点.appendChild(子节点)

// 向父节点city中添加子节点li
//方式一
var li = document.createElement("li");
var text = document.createTextNode("广州");
li.appendChild(text);
city.appendChild(li);

// 方式二
city. innerHTML += "<li>广州</li>";

// 方式三(推荐)
var li = document.createElement("li");
li.innerHTML = "广州";
city.appendChild(li);

将一个新的节点插入到旧节点的前边
父节点.insertBefore(新节点,旧节点)

使用一个新的节点去替换旧节点
父节点.replaceChild(新节点,旧节点)

删除指定的子节点
父节点.removeChild(子节点)
推荐方式:子节点.parentNode.removeChild(子节点)

  • DOM对CSS的操作
  1. 读取和修改内联样式
    使用style属性来操作元素的内联样式
  • 读取内联样式:
    语法:元素.style.样式名
元素.style.width
元素.style.height

注意:如果样式名中带有-,则需要将样式名修改为驼峰命名法
将-去掉,然后-后的字母改大写, 比如:background-color --> backgroundColor , border-width ---> borderWidth

  • 修改内联样式:
    语法:元素.style.样式名 = 样式值

通过style修改的样式都是内联样式,由于内联样式的优先级比较高,所以我们通过JS来修改的样式,往往会立即生效,但是如果样式中设置了!important,则内联样式将不会生效。

  • 读取元素的当前样式
    - 正常浏览器
    使用getComputedStyle()
    这个方法是window对象的方法,可以返回一个对象,这个对象中保存着当前元素生效样式。
    参数:
    要获取样式的元素
    可以传递一个伪元素,一般传null
// 获取元素的宽度
getComputedStyle(box , null)["width"];

通过该方法读取到样式都是只读的不能修改

// IE8 使用currentStyle
// 元素.currentStyle.样式名
box.currentStyle["width"]
  • 其他的样式相关的属性
    以下样式都是只读的

clientHeight
元素的可见高度,指元素的内容区和内边距的高度

clientWidth
元素的可见宽度,指元素的内容区和内边距的宽度

offsetHeight
整个元素的高度,包括内容区、内边距、边框

offfsetWidth
整个元素的宽度,包括内容区、内边距、边框

offsetParent
当前元素的定位父元素
离他最近的开启了定位的祖先元素,如果所有的元素都没有开启定位,则返回body

offsetLeft、offsetTop
当前元素和定位父元素之间的偏移量
offsetLeft 水平偏移量
offsetTop 垂直偏移量

scrollHeight、scrollWidth
获取元素滚动区域的高度和宽度

scrollTop、scrollLeft
获取元素垂直和水平滚动条滚动的距离
判断滚动条是否滚动到底
垂直滚动条: scrollHeight - scrollTop = clientHeight
水平滚动条: scrollWidth - scrollLeft = clientWidth

DOM其它操作
  • DOM操作CSS
    通过JS修改元素的样式:

语法:元素.style.样式名 = 样式值

注:如果CSS的样式名中含有-,这种名称在JS中是不合法的比如background-color,需要将这种样式名修改为驼峰命名法backgroundColor。
我们通过style属性设置的样式都是内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即显示。
但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加 !important。

读取元素的样式:

语法:元素.style.样式名

注:通过style属性设置和读取的都是内联样式,无法读取样式表中的样式。

window.onload = function(){             
    /*
    * 点击按钮以后,修改box1的大小
    */
    //获取box1
    var box1 = document.getElementById("box1");
    var btn01 = document.getElementById("btn01");
    btn01.onclick = function(){
                    
        box1.style.width = "300px";
        box1.style.height = "300px";
        box1.style.backgroundColor = "yellow";
    };
                
    //点击按钮2以后,读取元素的样式
    var btn02 = document.getElementById("btn02");
    btn02.onclick = function(){
    
        alert(box1.style.width);   
        getStyle(box1 , "width");
    };

    /*
    * 定义一个函数,用来获取指定元素的当前的样式
    * 参数:
    *       obj 要获取样式的元素
    *       name 要获取的样式名
    */
    function getStyle(obj , name){
                
        if(window.getComputedStyle){
            //正常浏览器的方式,具有getComputedStyle()方法
            return getComputedStyle(obj , null)[name];
        }else{
            //IE8的方式,没有getComputedStyle()方法
            return obj.currentStyle[name];
        }
        //return window.getComputedStyle?getComputedStyle(obj , null)[name]:obj.currentStyle[name];
    }
};
  • 获取其它css操作的属性:
/*
* clientWidth
* clientHeight
* 这两个属性可以获取元素的可见宽度和高度
* 这些属性都是不带px的,返回都是一个数字,可以直接进行计算
* 会获取元素宽度和高度,包括内容区和内边距
* 这些属性都是只读的,不能修改
*/
box1.clientWidth;
box1.clientHeight;

/*
* offsetWidth
* offsetHeight
* 获取元素的整个的宽度和高度,包括内容区、内边距和边框
*/
box1.offsetWidth;
                    
/*
* offsetParent
* 可以用来获取当前元素的定位父元素,会获取到离当前元素最近的开启了定位的祖先元素
* 如果所有的祖先元素都没有开启定位,则返回body
*/
var op = box1.offsetParent;

/*
* offsetLeft
* 当前元素相对于其定位父元素的水平偏移量
* offsetTop
* 当前元素相对于其定位父元素的垂直偏移量
*/
box1.offsetLeft;
                    
/*
* scrollWidth
* scrollHeight
* 可以获取元素整个滚动区域的宽度和高度
*/
box4.clientHeight;
box4.scrollWidth;
                    
/*
* scrollLeft
* 可以获取水平滚动条滚动的距离
* scrollTop
* 可以获取垂直滚动条滚动的距离
*/
box4.scrollLeft;
box4.scrollTop;                 
//当满足scrollHeight - scrollTop == clientHeight,说明垂直滚动条滚动到底了
//当满足scrollWidth - scrollLeft == clientWidth,说明水平滚动条滚动到底
事件(Event)

事件指的是用户和浏览器之间的交互行为。比如:点击按钮、关闭窗口、鼠标移动 ... ...
可以为事件来绑定回调函数来响应事件。
绑定事件的方式:
1.可以在标签的事件属性中设置相应的JS代码

<button onclick = "js代码......">按钮</button>

2.可以通过为对象的指定事件属性设置回调函数的形式来处理事件

<button id="btn">按钮</button>
<script>
    var btn = document.getElementById("btn");
    btn.onclick = function(){
                        
    };
</script>
  • 事件对象
    当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标、键盘哪个按键被按下、鼠标滚轮滚动的方向等。
    可以在响应函数中定义一个形参,来使用事件对象,但是在IE8以下浏览器中事件对象没有做为实参传递,而是作为window对象的属性保存。
元素.事件 = function(event){
    event = event || window.event;
};
            
元素.事件 = function(e){
    e = e || event;
};
// 当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标
window.onload = function(){
    //获取两个div
    var areaDiv = document.getElementById("areaDiv");
    var showMsg = document.getElementById("showMsg");
    /*
     * onmousemove
     * 该事件将会在鼠标在元素中移动时被触发
     *
     */
     areaDiv.onmousemove = function(event){
         // IE8以下浏览器中事件对象作为window对象的属性保存。
         // 解决事件对象的兼容性问题。
         event = event || window.event;
        /*
         * clientX可以获取鼠标指针的水平坐标
         * cilentY可以获取鼠标指针的垂直坐标
         */
        var x = event.clientX;
        var y = event.clientY;
        //在showMsg中显示鼠标的坐标
        showMsg.innerHTML = "x = "+x + " , y = "+y;
     };
};
  • 事件的冒泡(Bubble)
    事件的冒泡指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发。
    事件的冒泡大部分情况下都是有益的,如果需要取消冒泡,则需要使用事件对象来取消。
    可以将事件对象的cancelBubble设置为true,即可取消冒泡
元素.事件 = function(event){
    event = event || window.event;
    event.cancelBubble = true;
};
  • 事件的委派
    将事件统一绑定给元素共同的祖先元素,当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理。
    事件的委派利用冒泡,减少了事件绑定的次数,提高程序性能。

  • 事件的绑定
    使用 对象.事件 = 函数 的形式绑定响应函数,只能同时为一个元素的一个事件绑定一个响应函数。如果绑定多个,先绑定的会被覆盖。

  1. addEventListener()
    通过addEventListener()方法也可以为元素绑定响应函数,可以同时为一个元素的相同事件同时绑定多个响应函数,当事件被触发时,响应函数将会按照函数的绑定顺序执行。
    注:不支持IE8及以下的浏览器

参数:
1.事件的字符串,不要on
2.回调函数,当事件触发时该函数会被调用
3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false

var btn2 = document.getElementById("btn2");
btn2.addEventListener("click",function(){
    alert(1);
},false);

btn2.addEventListener("click",function(){
    alert(2);
},false);
  1. attachEvent()
    在IE8中可以使用attachEvent()来绑定事件,可以同时为一个事件绑定多个处理函数,但是它是后绑定先执行,执行顺序和addEventListener()相反。

参数:
1.事件的字符串,要on
2.回调函数

btn2.attachEvent("onclick",function(){
    alert(1);
});
                
btn2.attachEvent("onclick",function(){
    alert(2);
});

注:addEventListener()中的this,是绑定事件的对象
  attachEvent()中的this,是window

//定义一个函数,用来为指定元素绑定响应函数
/*
 * 参数:
 *  obj 要绑定事件的对象
 *  eventStr 事件的字符串(不要on)
 *  callback 回调函数
 */
 function bind(obj , eventStr , callback){
    if(obj.addEventListener){
        //大部分浏览器兼容的方式
        obj.addEventListener(eventStr , callback , false);
    }else{
        /*
         * this是谁由调用方式决定
         * callback.call(obj)
         */
        //IE8及以下
        obj.attachEvent("on" + eventStr , function(){
            //在匿名函数中调用回调函数
            callback.call(obj);
        });
    }
}
  • 事件的传播
    事件传播分成了三个阶段
  1. 捕获阶段
    在捕获阶段时从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件;
  2. 目标阶段
    事件捕获到目标元素,捕获结束开始在目标元素上触发事件;
  3. 冒泡阶段
    事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件;
    如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true。
    一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false。
    注:IE8及以下的浏览器中没有捕获阶段
  • 拖拽
    拖拽的流程
    1. 当鼠标在被拖拽元素上按下时,开始拖拽   onmousedown
    2. 当鼠标移动时被拖拽元素跟随鼠标移动    onmousemove
    3. 当鼠标松开时,被拖拽元素固定在当前位置   onmouseup
var box = document.getElementById("box");
//为box绑定一个鼠标按下事件
box.onmousedown = function(event){
    // 设置box捕获所有鼠标按下的事件
    // setCapture() 只有IE支持,但是在火狐中调用时不会报错,而如果使用chrome调用,会报错
    box.setCapture && box.setCapture();

    event = event || window.event;
    //div的偏移量 鼠标.clentX - 元素.offsetLeft
    //div的偏移量 鼠标.clentY - 元素.offsetTop
    var ol = event.clientX - box1.offsetLeft;
    var ot = event.clientY - box1.offsetTop;
                    
    //为document绑定一个onmousemove事件
    document.onmousemove = function(event){
        event = event || window.event;
        //获取鼠标的坐标
        var left = event.clientX - ol;
        var top = event.clientY - ot;
        //修改box1的位置
        box1.style.left = left+"px";
        box1.style.top = top+"px";
    };
                    
    //为document绑定一个鼠标松开事件
    document.onmouseup = function(){
        //取消document的onmousemove事件
        document.onmousemove = null;
        //取消document的onmouseup事件
        document.onmouseup = null;
        //当鼠标松开时,取消对事件的捕获
        obj.releaseCapture && obj.releaseCapture();
    };
    return false;
};

当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,如果不希望发生这个行为,则可以通过return false来取消默认行为。但是这招对IE8不起作用

  • 滚轮事件
    onmousewheel 鼠标滚轮滚动事件,会在滚轮滚动时触发,但是火狐不支持该属性。在火狐中需要使用 DOMMouseScroll 来绑定滚动事件,该事件需要通过addEventListener()函数来绑定。
    使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false, 需要使用event来取消默认行为event.preventDefault(); , 但是IE8不支持event.preventDefault();
window.onload = function(){
    var box1 = document.getElementById("box1");
    //为box绑定一个鼠标滚轮滚动的事件
    box.onmousewheel = function(event){
        event = event || window.event;
        //event.wheelDelta 可以获取鼠标滚轮滚动的方向,wheelDelta这个值不看大小,只看正负
        //alert(event.wheelDelta);
        //wheelDelta这个属性火狐中不支持,在火狐中使用event.detail来获取滚动的方向                   
        /*
         * 当鼠标滚轮向下滚动时,box变长
         *  当滚轮向上滚动时,box变短
         */
        //判断鼠标滚轮滚动的方向
        if(event.wheelDelta > 0 || event.detail < 0){
        //向上滚,box变短
            box.style.height = box1.clientHeight - 10 + "px";
        }else{
            //向下滚,box变长
            box.style.height = box1.clientHeight + 10 + "px";
         }

          event.preventDefault && event.preventDefault();

          return false;                 
     };
    //为火狐绑定滚轮事件
    bind(box1,"DOMMouseScroll",box1.onmousewheel);
};
            
function bind(obj , eventStr , callback){
    if(obj.addEventListener){
        //大部分浏览器兼容的方式
        obj.addEventListener(eventStr , callback , false);
    }else{
        //IE8及以下
        obj.attachEvent("on"+eventStr , function(){
            //在匿名函数中调用回调函数
            callback.call(obj);
        });
    }
}
  • 键盘事件
    onkeydown 按键被按下
    对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发。当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常的快,这种设计是为了防止误操作的发生。
    onkeyup 按键被松开
    键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document。

可以通过keyCode来获取按键的编码, 通过它可以判断哪个按键被按下。
除了keyCode,事件对象中还提供了几个属性:altKey、ctrlKey、shiftKey 这三个用来判断alt ctrl 和 shift是否被按下,按下则返回true,否则返回false。

document.onkeydown = function(event){
    event = event || window.event;
    //console.log(event.keyCode);
                    
    //判断y和ctrl是否同时被按下
    if(event.keyCode === 89 && event.ctrlKey){
        console.log("ctrl和y都被按下了");
    }
};
/*document.onkeyup = function(){
    console.log("按键松开了");
};*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容