Code前端首页关于Code前端联系我们

基于饿了么基础屏方案,使用Chrome扩展自动生成网页骨架屏

terry 2年前 (2023-09-08) 阅读数 189 #Vue

前言

之前写移动项目时,我使用了骨架屏来解决渲染首屏时空白太短的问题。我已经掌握了Eleme方法page-skeleton-webpack-plugin

但是page-skeleton-webpack-plugin需要一个依赖puppeteer,这会导致整个项目在开发中很笨重并且并不是所有页面都需要使用屏幕骨架。后来我找到了解决办法,决定用谷歌插件代替puppeteer

Chrome扩展生成网站骨架

下载谷歌插件

image.pngimage.png

最新版本下载地址未经谷歌官方核实。 PS:如何安装谷歌插件?自己Google一下吧

渲染

基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏

基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏
基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏

使用方法

插件模块参数

与饿了么骨架文档保持一致,如下图

基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏基于饿了么骨架屏方案,使用Chrome扩展程序自动生成网页骨架屏

骨架屏原理

饿了么骷髅屏的原理,可以看这篇文章详细了解

其实想法很简单。我们可以根据已有的dom结构重写指定的颜色,大致就达到了。不过这套方案有两个难点

  • 如何识别容器和块
  • 多余的CSS样式和房屋结构的多余处理

容器和方块

由于并非所有 DOM 节点都覆盖指定的背景颜色,有些 DOM 是 作为容器,让我们看看 饿了么 是如何处理的


		// 将所有拥有 textChildNode 子元素的元素的文字颜色设置成背景色,这样就不会在显示文字了。
		if (ele.childNodes && Array.from(ele.childNodes).some((n) => n.nodeType === Node.TEXT_NODE)) {
			transparent(ele)
		}
		if (checkHasTextDecoration(styles)) {
			ele.style.textDecorationColor = TRANSPARENT
		}
		// 隐藏所有 svg 元素
		if (ele.tagName === 'svg') {
			return svgs.push(ele)
		}
		// ! 针对于容器中如果有background或者img的 如果有需要当做块处理 否则就以容器为处理
		if (EXT_REG.test(styles.background) || EXT_REG.test(styles.backgroundImage)) {
			return hasImageBackEles.push(ele)
		}
		// export const GRADIENT_REG = /gradient/
		// CSS linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片
		if (GRADIENT_REG.test(styles.background) || GRADIENT_REG.test(styles.backgroundImage)) {
			return gradientBackEles.push(ele)
		}
		if (ele.tagName === 'IMG' || isBase64Img(ele)) {
			return imgs.push(ele)
		}
		if (
			ele.nodeType === Node.ELEMENT_NODE &&
			(ele.tagName === 'BUTTON' || (ele.tagName === 'A' && ele.getAttribute('role') === 'button'))
		) {
			return buttons.push(ele)
		}
		if (
			ele.childNodes &&
			ele.childNodes.length === 1 &&
			ele.childNodes[0].nodeType === Node.TEXT_NODE &&
			/\S/.test(ele.childNodes[0].textContent)
		) {
			return texts.push(ele)
		}
	})(rootElement)

	// ! dom节点 引用类型  这里统一收集对应类型的dom 然后集中用对应的handler处理
	console.log('button数组', buttons)
	console.log('hasImageBackEles', hasImageBackEles)
	console.log(pseudos, gradientBackEles, grayBlocks)
	svgs.forEach((e) => handler.svg(e, svg, cssUnit, decimal))
	texts.forEach((e) => handler.text(e, text, cssUnit, decimal))
	buttons.forEach((e) => handler.button(e, button))
	console.log('imgs数组', imgs)

	hasImageBackEles.forEach((e) => handler.background(e, image))
	imgs.forEach((e) => handler.image(e, image))
	pseudos.forEach((e) => handler.pseudos(e, pseudo))
	gradientBackEles.forEach((e) => handler.background(e, image))
	grayBlocks.forEach((e) => handler.grayBlock(e, button))
 
解决

的办法很简单,就看房子有没有background、backgroundImage、linear-gradient,或者有没有容器

多余的CSS样式和房屋结构的多余处理

饿了么这个方案处理了多余的节点和样式,但是效果不是很明显。让我们换个角度思考一下。其实我们已经知道节点是一个容器,节点是,那么就需要剔除容器这样的节点,因为页面上实际显示的是对应的骨架屏块,而对于特定位置,您可以通过 getBoundingClientRect API 使用绝对位置来获取 整理到语雀上

我的入门学习笔记?

最近写了笔记整理到语雀上,方便童鞋们阅读

  • 我的入门学习笔记?

总结

  • 文章如有错误,欢迎在评论区指正。如果这篇文章对您有帮助,请点赞关注吗?
  • 本文由掘金首发。未经许可禁止转载?

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门