抛出"问题"
我们先来阐述阐述问题,今儿在写一个有关于新手指引的公用组件,类似于这样的形式:
我相信大家首先想到的思路就是在
useEffect
中通过
getBoundingClientRect()
获得对应传入元素(
id
)的位置,然后通过定位增加一个类似的弹窗效果。
当我天真的以为这样就可以实现它的时,我碰到了一个"无从下手"解决的问题。
useEffect
中获取
getBoundingClientRect()
的值是随机的?
随机的???作为一个基本的程序员,随机的代码执行结果,这我怎么能够接受呢!
我们来看看简化后的代码:
"问题"代码
// 代码已经是很简化的版本了 仅仅保留了核心的内容
import React, { useEffect } from 'react'
import './_index.scss'
const GuideBeta = () => {
useEffect(() => {
console.log(document.getElementById('step1'))
console.log(document.getElementById('step1')?.getBoundingClientRect())
}, [])
return (
<div className='beta'>
<div id='step1'>
<div>第一个指引</div>
<div id='step2'>
<div>第二个指引</div>
export { GuideBeta }
复制代码
上面代码其实很简单,渲染两个
id
为
step1
和
step2
的元素,然后在
useEffect()
之中去打印获取
id
为
step1
的元素。
差不多页面渲染出来就是这个样子:
输出结果
这个是正常的输出结果:
当时当我们尝试多刷新几次页面来看看打印结果:
也许你会奇怪是不是我代码写的有问题,这里先卖个小关子
两次不同的打印结果,产生的原因和业务代码没有任何关系
。
要搞清楚这个问题,我们需要从一些基础的理论知识来层层递进。
血与泪的教训,我
checked
了我的代码整整一早上...
浏览器加载机制
关于浏览器加载机制其实我相信大家已经老生常谈了,这里我结合上边两次不同打印的原理来稍微聊聊对应的机制:
js
执行浏览器会被
js
引擎"霸占",从而导致渲染进程无法执行阻塞
DomTree
的渲染的,那么
Css
呢?
css
加载是否会阻塞
Dom Tree
的渲染呢?
让我们带着这个问题来谈谈
css
是否会阻塞
Dom Tree
的构建。
css
加载是否会阻塞
Dom Tree
的渲染和解析
验证
css
加载和
Dom Tree
的关系
我们尝试先来看看这端代码:
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#h1 {
color: blue;
</style>
<script>
setTimeout(() => {
const h1 = document.getElementById('h1')
console.log(h1)
}, 0)
</script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<h1 id="h1">
大大的标题
</body>
</html>
复制代码
代码其实很简单,就是在
js
脚本中定时器中获取
h1
标签。之后引入了
bootstrap
样式库。
注意:我们需要将浏览器中"网络"限制为
SLOW 3G
进行测试。
通过上边的表现,我们可以看到当页面加载中。
js
脚本中的
setTimeout
已经成功的在控制台打印出来了
h1
标签对应的元素。
也就是说
css
还未加载完成,我们就已经可以获取到对应的
Dom
,
所以
css
加载并不会阻塞
Dom Tree
的构建。
但是同时注意到,当
css
文件加载完成后页面才会渲染出来蓝色的
大大的标题
,也就是说
当
css
文件加载完成后,页面才会进行渲染。
此时我们可以得知
css
的加载是会阻塞
Render Tree
的渲染的,你可以暂时理解成
Render Tree
为
Dom Tree
,之后我们会在后边详细讲解。
css
对于
Dom Tree
结论
我们来谈谈关于
css
加载的结论:
-
css
加载并不会阻塞
Dom Tree
的构建,因为
css
还未加载完时我们已经可以获取到对应的
h1
标签了。
-
css
加载会阻塞
Dom Tree
的渲染,只有当
css
加载完成后页面才会渲染出蓝色的
大大的标题
。
css
加载对于
js
的影响
那么
css
加载对于
js
的是否有影响呢?废话不多说我们来看代码:
css
加载对于
js
验证
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
const now = window.now = Date.now()
console.log('css加载之前', now)
</script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script>
const scriptExec = Date.now() - window.now + 'ms'
console.log('css加载完成')
console.log('间隔:' + scriptExec)
</script>
</head>
<h1 id="h1">
大大的标题
</body>