Skip to content
On this page

认识骨架屏-skeleton

相对于传统的loading加载, 骨架屏skeleton告知用户当前页面处于加载态,
提前预知页面结构,缓解等待的焦虑,从而提升用户体验。

初步认识骨架屏

实际上,微信朋友圈,小红书,饿了么,淘宝等等应用,已经普遍应用了骨架屏。 vue2element-ui组件库,也有skeleton组件Skeleton 骨架屏

实现方式

方式1: 设计类似真实数据的骨架屏dom, 请求完成前显示骨架屏dom.
方式2: 对于图片节点的骨架屏,更好的方式是设置背景为灰色,当请求到内容时,赋值src.
方式3: 使用组件库, 例如element-plusskeleton组件。或者vue-skeleton-webpack-plugin插件。

常规思路

  • css
css
div {
    width: 240px;
    height: 240px;
	/*  1. 骨架屏背景  */
    background-color: #ccc;
    cursor: pointer;
    /* border: 1px solid #ddd; */
}

p {
    width: 100%;
    height: 100%;
	/*  2. 骨架屏动画容器,渐变背景+动画  */
    /* linear-gradient(deg, 浅,深,浅) */
    background: linear-gradient(90deg, #f2f2f2 25%, 
        #e6e6e6 37%, #f2f2f2 63%);
    background-size: 400% 100%;
    animation: anima 1.4s linear infinite;
    /* 以上三句是骨架屏动画的核心代码,渐变色动画 */
    display: flex;
    justify-content: center;
    align-items: center;
}

p svg {
    width: 22%;
    height: 22%;
	/*  2.1 如果有图片  */
    fill: #dcdde0;
    /* fill的好处,可以填充颜色,并且受父盒子的背景色影响 */
}

img {
	/* 真实dom	*/
    width: 100%;
    height: 100%;
}

@keyframes anima {
    0% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0% 50%;
    }
}
  • html
html
<!-- 骨架屏 -->
<p id="p">
    <svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
        <path
            d="M64 896V128h896v768H64z 
            m64-128l192-192 116.352 116.352L640 
            448l256 307.2V192H128v576z m224-480a96 96 0 1 1-0.064 
            192.064A96 96 0 0 1 352 288z" />
    </svg>
</p>
<!-- 真实dom -->
<img src="xxx"
    id="img" hidden>
  • js事件
js
let show = false;
// 控制显示与隐藏
btn.onclick = handleLoad;
function handleLoad() {
    show = !show;
    if (show) {
        // i用于模拟请求进度,
        // 实际开发中,
        // axios: 
            // onUploadProgress 上传进度事件,onDownloadProgress 下载进度事件
        // ajax: onprogress 原生进度事件
        let i = 0;
        let timer = setInterval(() => {
            if (i >= 100) {
                i = 0;
                // 隐藏骨架屏
                p.style.display = 'none';
                // 显示真实dom,真实开发中要将请求成功回来的数据给其src属性。
                img.style.display = 'inline';
                // 清除定时器
                clearInterval(timer);
                return;
            }
            i++;
            progress.textContent = `${i < 10 ? '0' + i : i}%`
        }, 10);
    }
    else {
    	// 显示骨架屏
        p.style.display = 'flex';
        // 隐藏真实dom, 真实开发中要将src属性置空,同时隐藏。
        img.style.display = 'none';
        progress.textContent = `00%`
    }

}

window.onload = function () {
    handleLoad();
}

图片骨架屏

  • html
html
<img class="aImg">
  • css
css
.aImg{
	display: block;
	width: 240px;
    height: 240px;
    background: linear-gradient(90deg, #f2f2f2 25%, 
        #e6e6e6 37%, #f2f2f2 63%);
    background-size: 400% 100%;
    animation: anima 1.4s linear infinite;
}
@keyframes anima{
	0%{
		background-position: 100% 50%;
	}
	100%{
		background-position: 0% 50%;
	}
}
  • js
js
window.onload = function () {
    setTimeout(()=>{
        img.src = 'xxx'
    },3000)
}

封装一个通用的骨架屏组件

  • skeleton.vue
  • 支持width, height, circle, class作为props.
  • 后续可以支持动画。
html
<template>
    <div style="background-color: rgb(245, 245, 241);" :style="getStyle" :class="getClass">

    </div>
</template>

<script>
    export default {
        props: {
            width: {
                type: [Number, String],
                default: 0
            },
            height: {
                type: [Number, String],
                default: 0
            },
            circle:{
                type: Boolean,
                default: false
            },
            oClass: {
                type: String,
                default: ''
            }
        },
        computed:{
            getStyle(){
                return `width:${this.width};height:${this.height}`
            },
            getClass(){
                let c = ""
                if (this.circle) {
                    c += 'rounded-circle'
                }
                return `${c} ${this.oClass}`
            }
        }
    }
</script>

一个陪你成长的前端博客 - XDocs