Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
popring committed Sep 23, 2024
1 parent c677c0a commit 3e09f2d
Showing 1 changed file with 5 additions and 94 deletions.
99 changes: 5 additions & 94 deletions source/_posts/首屏骨架屏减少白屏.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ tags:
categories: 性能优化
---


## 背景

用户从输入 `url` 到打开页面,经历的步骤可以参考[这里](https://popring.github.io/2021/03/06/%E7%AE%80%E5%8D%95%E8%81%8A/%E4%BB%8E%E8%BE%93%E5%85%A5url%E5%88%B0%E9%A1%B5%E9%9D%A2%E6%98%BE%E7%A4%BA%E7%BB%8F%E8%BF%87%E4%BA%86%E4%BB%80%E4%B9%88/)。现代前端应用程序通常使用 `React``Vue``Angular``Solid` 等框架进行开发,这些框架统一管理工程化内容。

这也导致了一个问题:通过这些框架开发的单页面应用(SPA)通常只包含一个 `<div id="app"></div>`,而其余内容都是在后续脚本运行时动态渲染。这使得用户加载的 HTML 页面往往呈现为白屏,只有等到脚本解析执行后,内容才会呈现。因此,服务端渲染(SSR)应运而生,它在服务器端就将内容渲染好并返回给前端,虽然这需要整体改造项目,成本较高。另一种方案是使用首屏骨架图渲染,以减少白屏现象。

<!-- more -->


## 原理

骨架屏的原理是直接将骨架图嵌入 HTML 中,实际内容加载完毕后将骨架图替换为真实内容。
Expand All @@ -22,100 +26,7 @@ categories: 性能优化
3. **自动生成骨架屏**
- `page-skeleton-webpack-plugin`:不再维护,不推荐。
- 使用 Chrome 插件生成骨架屏,比如 `@killblanks/skeleton-ext`,效果不错,但样式需要微调。
- 自定义实现,原理简单,将页面的文字和图片替换为骨架图形式。以下是使用代码生成骨架图的示例,可以直接复制到浏览器中执行,预览效果。

```js
// 递归生成骨架图
function processElement(el, skeletonOverlay, bodyRect) {
const children = el.children;

if (children.length > 0) {
for (let i = 0; i < children.length; i++) {
processElement(children[i], skeletonOverlay, bodyRect);
}
} else {
const rect = el.getBoundingClientRect();
if (rect.width > 0 && rect.height > 0) {
const skeletonElement = document.createElement('div');
skeletonElement.className = 'skeleton-box';
skeletonElement.style.position = 'absolute';
skeletonElement.style.top = rect.top - bodyRect.top + 'px';
skeletonElement.style.left = rect.left - bodyRect.left + 'px';
skeletonElement.style.width = rect.width + 'px';
skeletonElement.style.height = rect.height + 'px';
skeletonOverlay.appendChild(skeletonElement);
}
}
}

// 覆盖页面并生成骨架图
function generateSkeleton() {
if (document.getElementById('skeleton-overlay')) return;

const skeletonOverlay = document.createElement('div');
skeletonOverlay.id = 'skeleton-overlay';
skeletonOverlay.style.position = 'fixed';
skeletonOverlay.style.top = 0;
skeletonOverlay.style.left = 0;
skeletonOverlay.style.width = '100%';
skeletonOverlay.style.height = '100%';
skeletonOverlay.style.zIndex = 9999;
skeletonOverlay.style.backgroundColor = 'rgba(255, 255, 255, 1)';

const bodyRect = document.body.getBoundingClientRect();

document
.querySelectorAll('div, p, h1, h2, h3, h4, h5, h6, a, img, span, em')
.forEach((el) => {
processElement(el, skeletonOverlay, bodyRect);
});

insertSkeletonStyles(skeletonOverlay);
document.body.appendChild(skeletonOverlay);
}

// 骨架图样式函数
function insertSkeletonStyles(skeletonOverlay) {
const skeletonStyles = `
.skeleton-box {
background-color: #f0f0f0;
animation: skeleton-loading 1.5s infinite;
border-radius: 4px;
}
@keyframes skeleton-loading {
0% {
background-color: #f0f0f0;
}
50% {
background-color: #e0e0e0;
}
100% {
background-color: #f0f0f0;
}
}
`;

const styleSheet = document.createElement('style');
styleSheet.type = 'text/css';
styleSheet.innerText = skeletonStyles;
skeletonOverlay.appendChild(styleSheet);
}

// 切换骨架图的显示和隐藏
function toggleSkeleton() {
const skeletonOverlay = document.getElementById('skeleton-overlay');
if (skeletonOverlay) {
skeletonOverlay.style.display =
skeletonOverlay.style.display === 'none' ? 'block' : 'none';
} else {
generateSkeleton();
}
}

// 将核心函数绑定到 window 对象上
window.generateSkeleton = generateSkeleton;
window.toggleSkeleton = toggleSkeleton;
```
- 自定义实现,原理简单,将页面的文字和图片替换为骨架图形式。[参考源码](https://github.com/popring/vite-skeleton/blob/main/tempermonkey/genSkeleton.js)。如果你恰巧有 `油猴` 插件,也可以直接安装脚本使用[点击直达](https://greasyfork.org/zh-CN/scripts/509875-skeletonscript)

## 注入代码 1 - 注入进 `#app`

Expand Down

0 comments on commit 3e09f2d

Please sign in to comment.