目录
1 DOM概念
1.1 什么是DOM
首先,什么是DOM?DOM是Document Object Model(文档对象模型)的缩写,是专门操作HTML的API。众所周知,DOM包含核心DOM、XML DOM和HTML DOM,核心DOM能够直接操作所有的结构化文档(html,xml),是中立与平台和语言的接口,它允许程序或脚本动态地访问更新文档的内容、样式以及结构。DOM包含核心DOM、XML DOM和HTML DOM,我们这里讨论HTML DOM,HTML DOM是关于如何获取、添加、修改和删除HTML元素的标准。
W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
DOM(文档对象模型)是一组用来描述脚本怎样与结构化文档进行交互和访问的web标准。他的功能是把浏览器支持的文档(包括HTML XML XHTML)当作一个对象来解析。DOM实际上是一个操作文档里面所包含的内容的一个编程的API,允许开发人员从文档中读取、搜索、修改、增加和删除数据。DOM是与平台和语言无关的,也就是说只要是支持DOM的平台和编程语言,你都可以用来编写文档。
DOM定义了一系列对象、方法和属性,用于访问、操作和创建文档中的内容、结构、样式以及行为。每一个网页元素(一个HTML标签)都对应着一个对象(object,所谓“对象”,用白话说就是“东西”。)。网页上的标签是一层层嵌套的,最外面的一层是<HTML>,文档对象模型也这样一层层嵌套着,但是通常被理解成一棵树的形状。树根是window或document对象,相当于最外层的标签的外围,也就是整个文档。树根之下(这棵树的图通常是倒着画,就好像遗传谱系或者家谱那样。树根就是唯一的共同祖先)是子一级的对象,子对象也有它自己的子对象,除了根对象以外,所有的对象都有自己的父对象,同一对象的子对象之间就是兄弟的关系。如果大家没有见过家谱,应该知道一个公司的组织架构。
DOM实际上是以面向对象方式描述的文档模型。DOM定义了表示和修改文档所需的对象、这些对象的行为和属性以及这些对象之间的关系。可以把DOM认为是页面上数据和结构的一个树形表示,不过页面当然可能并不是以这种树的方式具体实现。通过JavaScript,可以重构整个 HTML 文档。可以添加、移除、改变或重排页面上的项目。
要改变页面的某个东西,JavaScript 就需要获得对 HTML 文档中所有元素进行访问的入口。这个入口连同对 HTML 元素进行添加、移动、改变或移除的方法和属性,都是通过文档对象模型来获得的(DOM)。
1.2 DOM节点
在HTML DOM中HTML文档中所有内容都被视为节点,DOM被视为节点树的HTML。
(1)整个文档视为一个文档节点
(2)每个HTML元素视为元素节点 //节点类型都有对应的数值 这里的是 1
(3)HTML元素中的文本视为文本节点 //文本节点text 所代表的数值为 3
(4)每个HTML属性为属性节点 //属性节点所代表的数值为 2
(5)注释为注释节点 //注释节点 coment 所代表的数值为 8
(6)document //这里代表的数值为 9
(7)DocumentFragment //这里代表的数值为 11
讲到这里属性节点代表的数值,就要提到它的作用 ,这是类似查看数据类型的 typeof 的效果所返回的值,用nodeType来实现。
节点属性还有 nodeName 用来获取元素的标签名,返回的内容均为大写,并且有个只读不能写入的属性。
nodeValue 是元素的内容,需要特别注意的是这个属性只对text文本节点与coment注释节点起作用,并且可读可写入。
hasCildNodes()是判断是否含有子节点属性。
attributes 为节点的属性集合、类数组
例:div.attributes =》 {0:id,1:class,id:id,class:class,length:2}
HTML DOM将HTML视为文档视为树结构,这种结构称为节点树:
下面举个DOM树的图形示例
1.3 DOM树
DOM基本功能:
① 查询某个元素
② 查询某个元素的祖先、兄弟以及后代元素
③ 获取、修改元素的属性
④ 获取、修改元素的内容
⑤ 创建、插入和删除元素
按照不同的类型来分,dom有不同的节点:文档节点、元素节点、属性节点、文本节点、注释节点,别说话,看图:
总的来说,
HTML DOM 定义了用于 HTML 的一系列标准的对象,以及访问和处理 HTML 文档的标准方法。
通过 DOM,可以访问所有的 HTML 元素,连同它们所包含的文本和属性。可以对其中的内容进行修改和删除,同时也可以创建新的元素。
HTML DOM 独立于平台和编程语言。它可被任何编程语言诸如 Java、JavaScript 和 VBScript 使用。
3、JS 和DOM有什么联系吗? js是代码,html是标记语言哦
想要做成动态页面,肯定要用到js了,管你是vue还是ng还是什么的。
DOM的妙处在于:它能够在所有浏览器上提供一种一致的方式,通过代码访问HTML的结构和内容。
1、在浏览器加载一个页面时,浏览器会解析HTML,并创建文档的一个内部模型,其中包含HTML标记的所有元素,自上而下解析,遇到JavaScript浏览器会检查它的正确性,然后执行代码。
2、JavaScript继续执行,使用DOM检查页面、完成修改、从页面接受事件,或者要求浏览器从Web服务器获取其它数据
注:document是一个反映HTML的对象,通过调用document的方法改变DOM的状态,也就是改变HTML页面
3、JavaScript修改了DOM时,浏览器会随着动态更新页面。
DOM就是一张映射表啦,记录着一堆用代码操控document时的规章制度,直白点说,就是js操作html时的API
2.js ,css,html执行顺序
加载的顺序不一样,可以吧html看成是从上往下加载的,在网速较慢的情况下把js代码放在body的底部用户会先看到网页的结构,等js加载完成后才能出现特效.
2.1 正常网页加载的顺序:
1 浏览器一边下载html网页,一边开始解析.
2解析过程中,若发现script标签,暂停解析,网页渲染的控制权交给js引擎.
3 如果scirpt引用了外部脚本,就下载该脚本,否则直接执行.
4.执行完毕,控制权交还给js渲染引擎.恢复往下解析html网页.
2.2 HTML 加载顺序
1.在html中 body部分中的js会在页面加载的时候被执行.
2.在html中head中的js会预先进行加载,反而会在页面需要调用的时候才会执行代码,所以可以将预先不执行的代码放在head中.
3.需调用先执行的时候把js放在head中,在head页面载入的时候,就同时载入了代码,在body中调用的时候就不用载入代码,速度会提高.
4.如果head中的js代码需要传入一个参数,需要body中的参数,那么这时候就会报错,因为此时页面的DOM树还未生成.
5 从js对页面下载性能方向考虑. 由于脚本会阻塞其他资源的下载,如图片和页面渲染,直到脚本全部被下载并执行完毕后,页面的渲染才会继续,因此推荐将所有的script标签放到底部.
<html>
<head>
<!-- 引用外部JS文件 -->
<script src="..........."></script>
<!--引用外部css样式 -->
<link href="............."/>
<style>
..............
</style>
<script>
..............
</script>
</head>
<body>
<script>
..............
</script>
</body>
</html>
- window.onload:等待页面中的所有内容加载完毕之后才会执行。
- $(document).ready():页面中所有 DOM 结构绘制完毕之后就能够执行。
window.onload 与 $(document).ready() / $(function(){})相当于下载 body 内最靠后的<script>代码段
- 下载的顺序是从上向下,渲染的顺序也是从上到下,下载和渲染是同步执行。HTML 需要等<head>中所有的 JS 文件 和 CSS 文件 加载完成后才会开始绘制。
- 用户输入网址,浏览器向服务器发出请求,服务器返回 Html 文件。
==》<html>
- 浏览器开始载入 HTML 代码,进入
==》<head>
,发现标签内有一个 <link> 标签引用外部的 CSS 文件;浏览器又发出 CSS 文件请求,服务器返回这个 CSS 文件。页面获取 CSS 文件后开始渲染页面。
引入外联样式表,属于并行加载。CSS 在加载时 DOM 还在继续加载构建。
- 外联样式表:<head> 标签中,使用 <link> 标签的 href 属性来引用的层叠样式表(css文件)
- 内联样式表:<head> 标签中,使用 <style> 标签 通过 选择器 + 样式文件 编写的。
- 内部样式表:在标签 中的 <style> 属性中添加的 css 样式声明。
上述三种样式表,页面显示的效果的影响程度越来越高。
其中,还包含了许多选择器。
【 ID 选择器指定的样式 】 > 【类选择器指定的样式】 > 【元素类型选择器指定的样式】
- 浏览器继续载入 HTML 中 <body> 部分的代码。
- 浏览器解析到<img>或者<video>标签引用了一张图片或者一个视频时,会向服务器
并行
请求图片或者视频。继续渲染后面的代码。
- 当服务器返回图片文件或者视频文件的时候,浏览器会重新渲染这部分代码。
- 浏览器发现 <script> 标签,便会暂停解析,将控制权交给 JavaScript 引擎(JavaScript 解释器)。
当引用了 JavaScript 的时候,浏览器发送 一 个JavaScript request ,就会一直等待该request 的返回。因为浏览器需要一个稳定的 DOM 树结构,而 JavaScript 中的代码可能直接改变了 DOM 树的结构,甚至 直接使用 location.href 进行跳转,所以浏览器为了防止出现 JavaScript 改变 DOM 树的情况,会阻塞其他的下载和渲染。
- 如果 <script> 标签引用了外部脚本,就下载该脚本(下载执行该脚本),否则就直接执行,执行完毕后将控制权交给 浏览器渲染 引擎。
- 如果JavaScript 中执行了<div>(style.display=“nonde”),执行结束后浏览器渲染会先渲染这部分内容。
- 直到解析到 </html>,解析完成。
- 当 <body> 中的代码全部执行完毕,并且整个页面的 css 样式加载完毕后, css 会重新渲染整个页面的 html 元素。
各个步骤的加载渲染时间,可以通过浏览器的插件进行追踪。例如:Chrome还提供一种很棒的事件跟踪工具,叫做 speed tracer。
总结:加载 html 文档,从上向下解析,<head> 中的 link 是并行加载的,加载完成后开始 <body> 中的渲染,避免闪屏情况的出现,<script> 同步进行加载和解析,出现阻塞加载的情况。
浏览器加载 一个 html 页面,并行进行解析(生成 DOM 树)和渲染。
2.3 JS加载示例
js代码在js外部文件和<script></script>内的区别:
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript"src="test.js" ></script>
<script type="text/javascript">
alert("head中js");
</script>
</head>
<body>
</body>
</html>
其中test.js为外部js文件,代码为:
alert("文件中js");
程序运行结果为先打印"文件中js",再打印"head中js",如果把<script src="test.js">放在后面,则是先输出"head中js",即浏览器是按<script>载入的先后顺序执行的。
一般来说每个脚本定义的全局变量和函数,都可以被后面执行的脚本所调用。变量的调用必须是在前面已经声明, 否则是undefined。而函数的调用可以在函数定义之前,前提是函数调用与定义在同一个<script></script>中,看下面的代码:
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
alert(str);//程序打印出,undefined
Sayhello("小明");//程序打印出,小明你好
function Sayhello(name)
{
alert(name+"你好!");
}
var str="abcd";
</script>
</head>
<body>
</body>
</html>
函数定义可以出现在函数调用的后面,但是如果是分别在两段代码,且函数调用在前面代码中,则会报函数未定义错误。
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
Sayhello("小明");//浏览器报错Sayhello未定义
</script>
<script type="text/javascript">
function Sayhello(name)
{
alert(name+"你好!");
}
var str="abcd";
</script>
<script type="text/javascript">
Sayhello("小红");
alert(str);
</script>
</head>
<body>
</body>
</html>
程序正常打印''小红你好''和''abcd''。
在实际js的编程中,可能会页面<script>标签内的js代码中调用外部js文件中的变量或函数,这个需要js文件的加载在前,而调用在后。下面的代码可以说明:
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript">
alert(num1);
alert(num2)
alert(sum(3,7));
</script>
</head>
<body>
</body>
</html>
test.js中的代码:
var num1=2;
var num2=3;
function sum(a,b)
{
return a+b;
}
程序正常输出,如果把test.js放在后面,调用却在前面,会出现undefined的错误。如果把js文件test.js放在后可以调用前面html页面<script>标签中的变量和函数,也可以调用前面的js文件中定义的变量和函数。
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
var string1="abc";
var string2="def";
function Print(str1,str2)
{
alert(str1+str2) ;
}
</script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
</body>
</html>
上面程序中string1,string2,Print声明或定义在前,在test.js中调用,test.js的代码为:
alert(string1);//输出abc
alert(string2);//输出def
var str1="12";
var str2="34";
Print(str1,str2);//输出1234
后面引用的js文件调用前面js文件中定义的变量和函数,把前面的html改为如下:
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="test02.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
</body>
</html>
test.js中的代码不变,调用前面test02.js中定义变量和函数,test02.js的代码如下:
var string1="abc";
var string2="def";
function Print(str1,str2)
{
alert(str1+str2) ;
}
程序运行结果与前面一样,上面程序交换test.js和test02.js的先后会出现undefined的错误。这充分说明js外部文件和页面内<script>标签里的js代码一样,让先后顺序加载执行的。
下面来看看<script>加入html的不同位置执行的顺序:在<head>和<body>中以及与页面元素加载的先后关系
下面的程序对比<head>和<body>中js的执行顺序:
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
alert("我在head中");
</script>
</head>
<body>
<script type="text/javascript">
alert("我在body中");
</script>
</body>
</html>
上面程序先弹出"我在head中"后body中,与页面加载的顺序一致。放入<body>中的js随页面元素加载时执行。可以把js放在</html>的后面,在页面加载完成后执行,相当于onload事件中的代码。
综合上面所述情况可以归结为一点,即JavaScript代码是按页面加载的先后顺序执行的。(注上述代码在不同浏览器中执行的结果会有一些小差异)。