一篇文章搞懂DOM

学习JavaScript肯定是会遇到DOM操作,那么什么是DOM?它又是干嘛用的?这篇文章为你揭晓答案。

DOM是document object model的缩写,简称文档对象模型。

简单的说DOM是一套对文档的内容进行抽象和概念化的方法。我们可以把HTML文档模型化,当作对象来处理。

基本概念:

文档(document): HTML或XML文件。

节点(node):HTML文档中的所有内容都可以称之为节点,常见的节点有 元素节点 属性节点 文本节点 注释节点。

元素(element): HTML文档中的标签可以称为元素。

我们可以把一个HTML文档看做一个树形结构的对象,每一个标签会形成一个分支,这样就很容易理解了,如下图所示(图片来自w3school)。

知道了什么是DOM,肯定要问DOM有什么用?

DOM把HTML文档抽象成一个对象,肯定是为了方便使用JavaScript对HTML文档进行操作。DOM的作用就是为了对页面的结构内容进行操作,增加页面的动态特性。

好了,知道了DOM是干嘛用的,那么下面我们就学习如何进行DOM操作。

DOM操作主要分四个部分:

1、获取HTML节点及修改节点的属性

2、修改节点的样式

3、给节点绑定事件

4、节点操作

现在我们进行一一介绍

获取HTML节点与修改节点属性(包含表单元素)

DOM提供了三个获取节点的方法

方法一:

getElementById()   //根据id属性获取一个DOM对象,区分大小写,符合代码规范

通过id寻找一个元素(找到的是一个元素对象) 该方法只能被document对象调用(同一个文档中id不能重复)。

<div id="box"></div>

var box = document.getElementById(“box”);

方法二:

getElementsByTagName()    //根据标签返回多个DOM对象

通过标签名寻找一类元素(找到的是由元素对象组成的伪数组) 即可以被document调用,又可以被元素对象调用,被元素对象调用时表示在该元素对象内部执行查找。

通常针对多个标签,而且常会要用到for循环。

<div class="cl" id=“cl”>

    <div class="cl2"></div>

    <div class="cl2"></div>

</div>

<div class="cl"></div>

<div class="cl"></div>

var divs = document.getElementsByTagName("div");// 获取页面上所有div,divs是一个伪数组

var cl = document.getElementById("cl");// 获取id为cl的元素

var cl2s = cl.getElementsByTagName("div");// 获取cl元素下面所有的div标签,cl2s是一个伪数组

方法三:

getElementsByClassName()

通过类名寻找一类元素。

<div class="cl" id=“cl”>

    <p class="cl"></div>

    <span class="cl"></div>

</div>

<a class="cl"></a>

var cls = document.getElementsByClassName("cl");//获取到的是一个伪数组,里面装的是div p span a这四个元素对象

获得到了节点元素后我们就可以对节点元素的属性进行修改了。

DOM也提供了两个方法供我们获取和修改元素的属性值。

getAttribute()

getAttribute是一个函数,用于获取节点属性。它只有一个参数,即所需要查询的属性的名字。getAttribute不属于document对象,所有不能通过document对象调用,只能通过元素节点对象调用。

<div id="box" title=hello></div>

var box = document.getElementById(“box”);

console.log(box.getAttribute(“title”));

通过这个方法我们可以获取元素box的title属性值为hello。

setAttribute()

setAttribute也是一个函数,用于修改节点属性。与getAttribute用法类似,不同的地方在于它有两个参数,第一个为属性名,第二个参数为设定的属性值。

<div id="box" title=hello></div>

var box = document.getElementById(“box”);

console.log(box.setAttribute(“title”,”world”));

此时,box节点的title属性值已经变为world。

是不是感觉so easy.

其实还有更为简便的方法来修改属性值,直接使用点语法就可以了。

获取属性值

var 变量=box.title;

修改属性值

box.属性名 = “属性值”;

是不是感觉更简单呢。

在此我只举例了title属性,当然元素的属性还有很多,比如img标签的src属性,我们可以更改src属性来切换图片。还可以设置表单元素的属性

type可以设置input元素的类型;

value可以设置input元素的值;

checked可以设置input元素是否选中;

selected 可以设置下拉列表select中的option是否被选中;

disabled 可以设置input元素是否被禁用。

好了,属性的操作就到此为止。

获取节点与控制样式

关于节点的获取,上面只用到了三个方法,但是实际的项目HTML文档往往是很复杂的,

文档中所有的节点之间都存在这样或那样的关系。节点间的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。在 HTML 中,可以将<body>元素看成是<html>元素的子元素;相应地,也就可以将<html>元素看成是<body>元素的父元素。而<head>元素,则可以看成是<body>元素的同胞元素,因为它们都是同一个父元素<html>的直接子元素。

首先我们来认识一下文档的层级结构,都有那些关系。

childNodes //子节点

children //子元素 虽然不是早期DOM标准中的方法,但是所有浏览器都支持

nextSibling //下一个兄弟节点

nextElementSibling //下一个兄弟元素 有兼容性问题

previousSibling//上一个兄弟节点

previousElementSibling //上一个兄弟元素 有兼容性问题

firstChild //第一个节点

firstElementChild //第一个子元素 有兼容性问题

lastChild //最后一个子节点

lastElementChild //最后一个子元素 有兼容性问题

parentNode //父节点 (一定是元素节点,所以无需处理)

所有获取节点相关属性都没有兼容性问题

注意:节点和元素不是同一个概念,文章开头说过,在此提醒一下。

获取子节点&子元素

  • childNodes: 获取指定元素的子节点,包括文本节点、元素节点等
  • children: 获取知道元素的子元素,只会获取元素节点。<ul id="list">
    <li><a href="javascript:void(0)">首页</a></li>

    <li><a href="javascript:void(0)">播客</a></li>

    <li><a href="javascript:void(0)">博客</a></li>

    <li><a href="javascript:void(0)">相册</a></li>

    <li><a href="javascript:void(0)">关于</a></li>

    <li><a href="javascript:void(0)">帮助</a></li>

</ul><script>
var ul = document.getElementById("list");

var lis = ul.getElementsByTagName("li");

//不关心层级 只找指定标签

//缺点: 如果内部还有li 也会找到

var nodes = ul.childNodes;

//子节点 只找子级

//缺点: 除了我们想要的元素节点 还会获取到其他节点

var children = ul.children;//子元素

</script>

childNodes是DOM标准中规定的方法 获取节点的方式所有浏览器都支持
children不是DOM标准中规定的方法 因为很常用所有浏览器也都支持

在实际应用中,基本都是用children。

获取下一个兄弟节点

nextSibling:下一个兄弟节点

<input type="text" id="txtName">

<span></span>

<input type="text" id="txtPwd"><span></span>

<input type="button" id="btn" value="注册">

 <script>

var txt = document.getElementById("txtName");

var next = txt.nextSibling;// 获取到的是换行,空文本节点

var pwd = document.getElementById("txtPwd");

var next = pwd.nextSibling;// 获取到的是span元素,因为两个标签间没有其他节点

 </script>

获取下一个兄弟元素

nextElementSibling: 下一个兄弟元素

<input type="text" id="txtName">

<span></span>

 <script>

var txt = document.getElementById("txtName");

var next = txt.nextElementSibling;// 可以获取到span元素,只获取下一个兄弟元素,忽略非元素类型的节点

 </script>

获取父节点

parentNode: 获取元素的父节点,父节点肯定是一个元素

<div id = "box">
    <img src="1.jpg" id="img"/>
</div>
<script>
var img = document.getElementById("img");
var parent = img.parentNode; //获取到的就是id为box的div元素
 </script>

节点的获取我就先介绍到这里,关于兼容性的问题我会再做补充。

下面看一下如何进行节点的样式操作。

获取样式

  • 通过style只能获取行内样式
  • 获取的样式如果有单位,获取到的样式中也会带单位,类型是一个字符串

设置样式

1、通过style设置样式

  • 通过style设置的是行内样式
  • 如果样式需要单位,设置时也需要把单位带上
div{

    width:100px;

    height:100px;

}

<div id="box"></div>

var box = document.getElementById("box");

consloe.log(box.style.width);// 打印的是空字符串,因为只能获取行内样式

box.style.width = "300px";// 设置的是行内样式,而且这里必须带单位

console.log(box.style.width);// 打印的是“300px“/

2、通过类名设置样式

.b{

    width:100px;

    height:100px;

    background-color:red;

}

<div id="box"></div>

var box = document.getElementById("box");

// 通过类名设置样式 两种方式

box.className = "b";

box.setAttribute("class","b");

下面介绍事件绑定

绑定事件

事件三要素: 事件源 事件 事件处理程序

事件源.事件 = function(){

    // 事件处理程序

}

<img src="pic.jpg" id="img"/>

var img = document.getElementById("img");

img.onclick = function(){

   ...

}

img是事件源 事件是点击onclick 事件处理程序是函数体中的内容

下面为常用事件总结


属性


描述


Onblur


元素失去焦点。


Onchange


域的内容被改变。


Onclick


当用户点击某个对象时调用的事件句柄。


ondblclick


当用户双击某个对象时调用的事件句柄。


Onfocus


元素获得焦点。


onkeydown


某个键盘按键被按下。


onkeypress


某个键盘按键被按下并松开。


Onkeyup


某个键盘按键被松开。


Onload


一张页面或一幅图像完成加载。


onmousedown


鼠标按钮被按下。


onmousemove


鼠标被移动。


onmouseout


鼠标从某元素移开。


onmouseover


鼠标移到某元素之上。


onmouseup


鼠标按键被松开。


Onreset


重置按钮被点击。


Onresize


窗口或框架被重新调整大小。


Onunload


用户退出页面。

 

节点操作

节点操作就5种形式,克隆节点、添加节点、插入节点、移除节点和创建节点。

克隆节点 - cloneNode()

element.cloneNode(): 复制element节点

参数:布尔值,

true代表深层克隆,把当前节点和内部所有节点都复制一份

false代表浅层克隆,只复制当前节点

<div id="father">

    <div id="son"><div/>

</div>

var father = document.getElementById("father");

var son = document.getElementById("son");

var clone = son.cloneNode(true);// 把son这个div复制一份 复制出来的clone和son没有任何关系了

添加节点 - appendChild()

father.appendChild(son):将son节点追加到father内部的最后位置

<div id="father">
    <div id="son"><div/>
</div>
<div id="demo"></div>

var father = document.getElementById("father");
var demo = document.getElementById("demo");
var clone = demo.cloneNode(true);// 将demo克隆一份

father.appendChild(clone);// 将克隆出来的clone追加到father中

// 此时页面结构应该为

<div id="father">

    <div id="son"><div/>

    <div id="demo"></div>

</div>

<div id="demo"></div>

//追加克隆节点对原节点不会产生影响

//如果代码如下 则会将demo节点直接移动到father节点下

father.appendChild(demo);// demo是页面上存在的节点

// 此时页面结构应该为

<div id="father">

<div id="son"><div/>

<div id="demo"></div>

</div>

插入节点 - insertBefore()

father.inserBefore(son1,son2): 将son1插入到father节点下的son2前面

<div id="father">

    <div id="son"><div/>

</div>

<div id="demo"></div>

var father = document.getElementById("father");

var son = document.getElementById("son");

var demo = document.getElementById("demo");

father.inserBefore(son,demo);//会直接将demo节点移动到father下的son前面       

插入克隆出来的节点也不会对原节点产生影响

移除节点 - removeChild()

father.removeChild(son): 将father下的son节点移除

<div id="father">

    <div id="son"><div/>

</div>

var father = document.getElementById("father");

var son = document.getElementById("son");

father.removeChild(son);// 直接将son节点删除

创建节点

document.write()

特点:只能被document调用,而且会覆盖页面上原有内容

document.write("<a href="http://www.baidu.com">百度</a>")

// 可以在页面上创建一个a标签,而且会覆盖页面上原有的所有内容

innerHtml()

特点:往页面添加html标签,可以限定范围

<div id="box"></div>

var box = document.getElementById("box");

box.innerHtml = "<a href="http://www.baidu.com">百度</a>";

// 追加后的结构为

<div id="box">

    <a href="http://www.baidu.com">百度</a>

</div>

createElement()

特点:动态创建标签,添加到页面需要配合appendChild使用。

<div id="box"></div>

var box = document.getElementById("box");
var input = document.createElement("input");

input.type = "text";
box.appendChild(input);

DOM的基本操作就到此为止了,如果对你有所帮助就给本文点个赞吧O(∩_∩)O

时间: 2024-08-29 04:10:56

一篇文章搞懂DOM的相关文章

一篇文章搞懂python2、3编码

说在前边: 编码问题一直困扰着每一个程序员的编程之路,如果不将它彻底搞清楚,那么你的的这条路一定会走的格外艰辛,尤其是针对使用python的程序员来说,这一问题更加显著, 因为python有两个版本,这两个版本编码格式却完全不同,但我们却经常需要兼顾这两个版本,所以出现各种问题的几率就大了很多. 所以在这里我试图用一篇文章来彻底梳理整个python语言的编码问题,尽量降低以后在这方面举到问题的可能性. ps 此文一定程度上参考和引用了alex的博客:“https://www.cnblogs.co

一篇文章搞懂DataSet、DataFrame、RDD-《每日五分钟搞定大数据》

1. 三者共性: 1.RDD.DataFrame.Dataset全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利 2.三者都有惰性机制,执行trainform操作时不会立即执行,遇到Action才会执行 3.三者都会根据spark的内存情况自动缓存运算,这样即使数据量很大,也不用担心会内存溢出 4.三者都有partition的概念,如 var predata=data.repartition(24).mapPartitions{       PartLine => {     

【朝花夕拾】一篇文章搞懂Android跨进程通信

前言 只要是面试中高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Android开发高级工程师必须要跨过的一道坎.如果您还对这方面的知识还做不到如数家珍,那就和我一起来攻克它吧! 本文主要包含了如下内容: 其行文脉络大致如下,希望能加深读者对这方面内容的记忆:(1)Android基于Linux系统,所以先说系统进程相关知识和Linux IPC.(2)总结Android的IPC

一篇文章搞懂Android组件化

网上组件化的文章很多,我本人学习组建化的过程也借鉴了网上先辈们的文章.但大多数文章都从底层的细枝末节开始讲述,由下而上给人一种这门技术“博大精深”望而生畏的感觉.而我写这篇文章的初衷就是由上而下,希望别人在阅读的过程中能够觉得“组件化原来也就是这几个东西”的感觉. 首先我们来看一下组件化项目和传统项目的区别 在传统的项目里 我们通常情况下会有一个commonLib的Libary模块和一个app的application模块,业务中的逻辑都写在app中各个功能模块放到不同的包下.这样做有以下几个主要

一篇文章搞懂Nginx是什么,能干什么

Nginx的产生 没有听过Nginx?那么一定听过它的"同行"Apache吧!Nginx同Apache一样都是一种WEB服务器.基于REST架构风格,以统一资源描述符(Uniform Resources Identifier)URI或者统一资源定位符(Uniform Resources Locator)URL作为沟通依据,通过HTTP协议提供各种网络服务. 然而,这些服务器在设计之初受到当时环境的局限,例如当时的用户规模,网络带宽,产品特点等局限并且各自的定位和发展都不尽相同.这也使得

一篇文章搞懂装饰器所有用法

如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 它放在一个函数开始定义的地方,它就像一顶帽子一样戴在这个函数的头上.和这个函数绑定在一起.在我们调用这个函数的时候,第一件事并不是执行这个函数,而是将这个函数做为参数传入它头顶上这顶帽子,这顶帽子我们称之为装饰函数 或 装饰器. 你要问我装饰器可以实现什么功能?我只能说你的脑洞有多大,装饰器就有多强大. 装饰器的使用方法很固定: 先定义一个装饰函数(帽子)(也可以用类.偏函数实现) 再

一篇文章搞懂android存储目录结构

前言 前两天因为开发一个app更新的功能,我将从服务器下载的apk文件放在了内部存储目录(测试手机为小米,路径为:data/user/0/packagename/files)下面,然后安装的时候一直安装不了,提示解析包出错.后来查询发现,安装apk是调用了PackageInstaller,没有相关权限,这个无法获取内部路径,所以会安装不了.借机也复习了一遍Android下面存储相关的知识点,特来总结一番. 存储分类 对于Android存储目录,我总结成一张思维导图,如果有需要原图的,请在我的公众

一篇文章搞懂移位运算

前提知识: 1. 计算机中对于有符号数的表示有三种方式,原码,补码,反码. 2. 在Java中,二进制数最高位是符号位,0表示正数,1表示负数: 3. 正数的表示,例如byte/int 数3,  二进制就是 0000 0011,负数的表示稍微麻烦一点(负数在计算机中是以补码的形式存储的) -5 的二进制: 1. -5的绝对值二进制表示  0000 0101 2. 然后求这个数的反码  1111 1010 3. 将反码加1 变成  1111 1011 , 这个就是-5的二进制表示(补码) 移位运算

一篇文章搞懂到底什么是渲染流水线

本文实际上是<Unity Shader入门精要>一书的读书笔记,书中关于渲染流水线的讲解清楚易懂,非常适合作为Shader学习的入门书籍.自知好记性不如烂笔头,遂将相关内容再结合自己的一些理解写作这篇博客记录下来. 我们将图像绘制的流程称为渲染流水线,是由CPU和GPU协作完成的.一般一个渲染流程可以分成3个概念阶段,分别是:应用阶段(Application Stage),几何阶段(Geometry Stage),光栅化阶段(Rasterizer Stage). 应用阶段 应用阶段是在CPU中