对于前端来说,HTML 都是最基础的内容。
今天,我们来了解一下 HTML 和网页有什么关系,以及与 DOM 有什么不同。通过本讲内容,你将掌握浏览器是怎么处理 HTML 内容的,以及在这个过程中我们可以进行怎样的处理来提升网页的性能,从而提升用户的体验。
不知你是否有过这样的体验:当打开某个浏览器的时候,发现一直在转圈,或者等了好长时间才打开页面……
此时的你,会选择关掉页面还是耐心等待呢?
这一现象,除了网络不稳定、网速过慢等原因,大多数都是由于页面设计不合理导致加载时间过长导致的。
我们都知道,页面是用 HTML/CSS/JavaScript 来编写的。
HTML由一系列的元素组成,通常称为HTML元素。HTML 元素通常被用来定义一个网页结构,基本上所有网页都是这样的 HTML 结构:
<html>
<head></head>
<body></body>
</html>其中:
HTML 中的元素特别多,其中还包括可用于 Web Components 的自定义元素。
前面我们提到页面 HTML 结构不合理可能会导致页面响应慢,这个过程很多时候体现在<script>和<style>元素的设计上,它们会影响页面加载过程中对 Javascript 和 CSS 代码的处理。
因此,如果想要提升页面的加载速度,就需要了解浏览器页面的加载过程是怎样的,从根本上来解决问题。
浏览器在加载页面的时候会用到 GUI 渲染线程和 JavaScript 引擎线程(更详细的浏览器加载和渲染机制将在第 7 讲中介绍)。其中,GUI 渲染线程负责渲染浏览器界面 HTML 元素,JavaScript 引擎线程主要负责处理 JavaScript 脚本程序。
由于 JavaScript 在执行过程中还可能会改动界面结构和样式,因此它们之间被设计为互斥的关系。也就是说,当 JavaScript 引擎执行时,GUI 线程会被挂起。
以网易云课堂官网为例,我们来看看网页加载流程。
(1)当我们打开官网的时候,浏览器会从服务器中获取到 HTML 内容。
(2)浏览器获取到 HTML 内容后,就开始从上到下解析 HTML 的元素。
(3)<head>元素内容会先被解析,此时浏览器还没开始渲染页面。
我们看到<head>元素里有用于描述页面元数据的<meta>元素,还有一些<link>元素涉及外部资源(如图片、CSS 样式等),此时浏览器会去获取这些外部资源。除此之外,我们还能看到<head>元素中还包含着不少的<script>元素,这些<script>元素通过src属性指向外部资源。
(4)当浏览器解析到这里时(步骤 3),会暂停解析并下载 JavaScript 脚本。
(5)当 JavaScript 脚本下载完成后,浏览器的控制权转交给 JavaScript 引擎。当脚本执行完成后,控制权会交回给渲染引擎,渲染引擎继续往下解析 HTML 页面。
(6)此时<body>元素内容开始被解析,浏览器开始渲染页面。
在这个过程中,我们看到<head>中放置的<script>元素会阻塞页面的渲染过程:把 JavaScript 放在<head>里,意味着必须把所有 JavaScript 代码都下载、解析和解释完成后,才能开始渲染页面。
到这里,我们就明白了:如果外部脚本加载时间很长(比如一直无法完成下载),就会造成网页长时间失去响应,浏览器就会呈现“假死”状态,用户体验会变得很糟糕。
因此,对于对性能要求较高、需要快速将内容呈现给用户的网页,常常会将 JavaScript 脚本放在<body>的最后面。这样可以避免资源阻塞,页面得以迅速展示。我们还可以使用defer/async/preload等属性来标记<script>标签,来控制 JavaScript 的加载顺序。
百度首页
对于百度这样的搜索引擎来说,必须要在最短的时间内提供到可用的服务给用户,其中就包括搜索框的显示及可交互,除此之外的内容优先级会相对较低。
浏览器在渲染页面的过程需要解析 HTML、CSS 以得到 DOM 树和 CSS 规则树,它们结合后才生成最终的渲染树并渲染。因此,我们还常常将 CSS 放在<head>里,可用来避免浏览器渲染的重复计算。
我们知道<p>是 HTML 元素,但又常常将<p>这样一个元素称为 DOM 节点,那么 HTML 和 DOM 到底有什么不一样呢?
根据 MDN 官方描述:文档对象模型(DOM)是 HTML 和 XML 文档的编程接口。
也就是说,DOM 是用来操作和描述 HTML 文档的接口。如果说浏览器用 HTML 来描述网页的结构并渲染,那么使用 DOM 则可以获取网页的结构并进行操作。一般来说,我们使用 JavaScript 来操作 DOM 接口,从而实现页面的动态变化,以及用户的交互操作。
在开发过程中,常常用对象的方式来描述某一类事物,用特定的结构集合来描述某些事物的集合。DOM 也一样,它将 HTML 文档解析成一个由 DOM 节点以及包含属性和方法的相关对象组成的结构集合。
我们常见的 HTML 元素,在浏览器中会被解析成节点。比如下面这样的 HTML 内容:
<html>
<head>
<title>标题</title>
</head>
<body>
<a href='xx.com'>我的超链接</a>
<h1>页面第一标题</h1>
</body>
</html>打开控制台 Elements 面板,可以看到这样的 HTML 结构,如下图所示:
在浏览器中,上面的 HTML 会被解析成这样的 DOM 树,如下图所示:
我们都知道,对于树状结构来说,常常使用parent/child/sibling等方式来描述各个节点之间的关系,对于 DOM 树也不例外。
举个例子,我们常常会对页面功能进行抽象,并封装成组件。但不管怎么进行整理,页面最终依然是基于 DOM 的树状结构,因此组件也是呈树状结构,组件间的关系也同样可以使用parent/child/sibling这样的方式来描述。同时,现在大多数应用程序同样以root为根节点展开,我们进行状态管理、数据管理也常常会呈现出树状结构。
我们知道,浏览器中各个元素从页面中接收事件的顺序包括事件捕获阶段、目标阶段、事件冒泡阶段。其中,基于事件冒泡机制,我们可以实现将子元素的事件委托给父级元素来进行处理,这便是事件委托。
如果我们在每个元素上都进行监听的话,则需要绑定三个事件;(假设页面上有a,b,c三个兄弟节点)
function clickEventFunction(e) {
console.log(e.target === this); // logs `true`
// 这里可以用 this 获取当前元素
}
// 元素a,b,c绑定
element2.addEventListener("click", clickEventFunction, false);
element5.addEventListener("click", clickEventFunction, false);
element8.addEventListener("click", clickEventFunction, false);使用事件委托,可以通过将事件添加到它们的父节点,而将事件委托给父节点来触发处理函数:
function clickEventFunction(event) {
console.log(e.target === this); // logs `false`
// 获取被点击的元素
const eventTarget = event.target;
// 检查源元素`event.target`是否符合预期
// 此处控制广告面板的展示内容
}
// 元素1绑定
element1.addEventListener("click", clickEventFunction, false);这样能解决什么问题呢?
常见的使用方式主要是上述这种列表结构,每个选项都可以进行编辑、删除、添加标签等功能,而把事件委托给父元素,不管我们新增、删除、更新选项,都不需要手动去绑定和移除事件。
如果在列表数量内容较大的时候,对成千上万节点进行事件监听,也是不小的性能消耗。使用事件委托的方式,我们可以大量减少浏览器对元素的监听,也是在前端性能优化中比较简单和基础的一个做法。
注意:
我们了解了 HTML 的作用,以及它是如何影响浏览器中页面的加载过程的,同时还介绍了使用 DOM 接口来控制 HTML 的展示和功能逻辑。我们了解了DOM解析事件委托等相关概念。
我们在浏览一个网页的时候,通常会遇到比较长的网页,一直向下拉滚动条一直向下,而在最底部的位置通常会有一个一键返回到顶部
或者返回到哪里的按钮,这个按钮就是利用的 锚点链接 功能。
就两个值:第一个就是锚点下在哪里?第二个就是点在哪里?
<body>
<!-- 2、跳转的目标位置:点-->
<a id="test">这里是顶部</a>
<!-- 1、跳转的按钮:锚-->
<a href="#test">回到顶部</a>
</body>源代码:↓
备注:如果手机上看格式错乱,建议粘贴到电脑版编辑器里观看。
作网页时,经常需要设置网页的基本信息,如网页的标题、作者等。为此,HTML提供了一系列设置网页信息的标签,这些标签通常都写在
<head>标签内,也被称为HTML.文档头部相关标签。下面将介绍常用的HTML文档头部标签中的<title>和<meta>标签。
(1)<title>标签
<title>标签用于设置HTML页面的标题,也就是为网页取一个名称。在网页结构中,<title>标签必须位于<head>标签内。一个HTML.文档只能含有一个<title>标签,<title></title>标签之间的内容将显示在浏览器窗口的标题栏中。例如,将某个页面标题设置为“轻松学习HTML.5”,示例代码如下:
<title>轻松学习HIML.5</title>上述代码对应的页面效果如下图:
(2)<meta>标签
<meta>标签用于定义页面的元信息(元信息不会显示在最终的页面效果中),可重复出现在标签中。在HTML中,<meta>标签是一个单标签,本身不包含任何内容,仅表示网页的相关信息。通过标签的属性,可以定义页面的相关参数。
例如,为搜索引擎提供网页的关键字、作者姓名、内容描述,以及定义网页的刷新时间等。下面介绍<meta/>标签常用的几组设置,具体如下。
<meta name-”名称”content-”值”>:在<meta>标签中使用 name 属性和 content 属性可以为搜索引擎提供信息。其中,name属性提供搜索内容名称,content属性提供对应的搜索内容值,这些属性的具体应用如下。
设置网页关键字,如某图像网站的关键字设置,示例代码如下:
<meta name=“keywoxds”content=“千图网,免费素材下载,千图网免费素材图库,矢量图,矢量图库,图像素材,网页素材,
免费素材,PS素材,网站素材,设计模板,设计素材,网页模板免费下载,千图,素材中国,素材,免费设计,图像”/>在上述示例代码中,nare属性的属性值为"keywonds”,该属性值用于定义搜索内容名称为网页关键字;content 属性的属性值用于定义关键字的具体内容,多个关键字内容之间可以用“,”分隔。
设置网页描述,如某图像网站的描述信息设置,示例代码如下:
<meta name=”description”content=”专注免费设计素材下裁的网站!提供矢量图素材,矢量青景图像,矢量图库,还有
psd素材,PS素材,设计模板,设计素材,PPT素材,以及网页素材,网站素材,网页图标免费下载”/>在上述示例代码中,name属性的属性值为“deseription”,该属性值用于定义搜索内容名称为网页描述;comtent 属性的属性值用于定义描述的具体内容。网页描述的文字不必过多,能够描述清晰即可。
设置网页作者,如可以为网站增加作者信息,示例代码如下:
<meta name-"author" content="网络部"/>在上述示例代码中,name属性的属性值为”author”,该属性值用于定义搜索内容名称为网页作者;content属性的属性值用于定义具体的作者信息。
<meta http-equiv=”名称”content=”值”>在<meta/>标签中,http-equiv 属性和content 属性可以设置服务器发送给浏览器的HTTP头部信息,为浏览器显示该页面提供相关的参数标准。其中,http-equiv属性提供参数类型,content属性提供对应的参数值,这些属性的具体应用如下。设置字符集,如某图像官网字符集的设置,示例代码如下:
<meta http-equiva"Content-Type" content="text/html; charset=gbk"/>在上述示例代码中,hitp-epuiv属性的属性值为“Content-Type”.content属性的属性值为“test/html”和“charset=gbk”,两个属性值之间用“:”隔开。其中,“text/html”用于说明当前文档类型为HIML“charset=gbk”用于说明文档字符集为GBK(中文编码)。
目前最常用的国际化字符集编码格式是UTF-8,常用的中文字符集编码格式主要是GBK和GB2312。当用户使用的字符集编码格式与当前浏览器不匹配时,网页内容就会出现乱码。新版本的HTML.5简化了字符集的写法,示例代码如下:
<meta charset="utf-g">设置页面自动刷新与跳转,如定义某个页面10秒后跳转至百度首页,示例代码如下:
<meta http-equiv""refresh" content="10; url- httpa://sww.baidu.com/"/>在上述示例代码中,http-equiv属性的属性值为“refresh”,content属性的属性值为数值和URL。两个属性值之间用“:”隔开,分别用于指定跳转时间和目标页面的URL。跳转时间默认以秒为单位。
*请认真填写需求信息,我们会在24小时内与您取得联系。