阅读 2424

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

前言

之前写移动端项目的时候,使用骨架屏来解决首屏渲染时出现短暂空白现象,采用了就是饿了么page-skeleton-webpack-plugin方法

但是page-skeleton-webpack-plugin需要puppeteer这个依赖,这玩意会导致整个项目在开发阶段很笨重,而且不是所有的页面都要用到骨架屏,后面找了套方案,决定使用谷歌插件代替puppeteer

Chrome扩展程序生成网页骨架屏

谷歌插件下载

image.png

最新版本下载地址,还未通过谷歌官方审核, PS: 谷歌插件如何安装,自行谷歌

效果图

如何使用

插件参数

同饿了么骨架屏文档保持一样,如下图

骨架屏原理

饿了么骨架屏原理,具体可以看看这篇文章

其实思路很简单,我们可以根据已有的dom结构,覆盖指定上的颜色,这样就大致实现了,不过这套方案有两个难点

  • 如何辨别容器和块
  • css冗余样式和冗余dom结构处理

容器和块

因为不是所有的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))
复制代码

解决的方式很简单,根据该dom是否有background、backgroundImage、linear-gradient是否为容器

css冗余样式和冗余dom结构处理

饿了么那套解决方案是有对冗余节点和样式做了处理,但是效果并不是很明显,我们换种思路想,竟然我们已经知道那个节点是容器,那个节点是,那么我们是不是对于容器这种节点做剔除,因为真正展示在页面的是对应的骨架屏块,而对于具体位置,可以使用绝对定位,通过getBoundingClientRect这个api获取

我的前端学习笔记📒

最近花了点时间把笔记整理到语雀上了,方便童鞋们阅读

总结

  • 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
  • 本文首发于掘金,未经许可禁止转载💌
文章分类
前端
文章标签