一杯茶的时间,手撸一个Skeleton骨架屏组件

201 阅读2分钟

一、浅谈

骨架屏组件是一种占位组件,效果类似于加载框。

其实这个组件本身没多少东西,但是为什么要写呢?因为我发现“实现骨架屏组件”这类的文章在掘金上少之又少,同时我的“UI组件”系列好久也没更新了,所以写了这篇文章,一举两得,既能给基础不牢的同学指明思路,又能更新专栏。

二、效果展示

使用方式如下:

<YonSkeleton>
    <YonSkeleton.Title animated={true}></YonSkeleton.Title>
    <YonSkeleton.Paragraph animated={true}></YonSkeleton.Paragraph>
</YonSkeleton>

展示效果如下:

骨架屏组件1.gif

三、实现细节

这个效果其实就是无限循环的动画(animation),这个动画的目的就是“主动改变背景图片的位置”。

3.1、animation讲解

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

name:指定动画名称。

duration:动画完成一次所需的时间。

timing-function:动画完成一次周期内,速度如何分配。

delay:何时开启动画。

iteration-count:在这个元素上播放多少次动画。

direction:动画播放的顺序。

fill-mode:当元素上的动画不播放时,此时元素上的样式应用动画里的哪一帧动画样式。

play-state:指定动画暂停或者运行。

3.2、代码实操

<style>
    .box-item {
        width: 200px;
        height: 15px;
        background-image: linear-gradient(
          90deg,
          rgba(190, 190, 190, 0.2) 25%,
          rgba(129, 129, 129, 0.24) 37%,
          rgba(190, 190, 190, 0.2) 63%
        );
        background-size: 400% 100%;
        animation-name: yon-skeleton-loading;
        animation-duration: 1.4s;
        animation-iteration-count: infinite;
        animation-timing-function: ease;
    }

    @keyframes yon-skeleton-loading {  // 指定动画帧集合
        0% {
            background-position: 100% 50%;
        }
        100% {
            background-position: 0 50%;
        }
    }
</style>
<div class = 'box-item'></div>

上面代码效果如下:

骨架屏组件2.gif

react版本的代码:


import React from 'react';

class Title extends React.Component {
    constructor(props){
        super(props);
    }
    render(){
        let { animated } = this.props;
        return <div className = {`yon-skeleton-title-box ${animated ? 'yon-skeleton-title-box-animated' : ''}`}></div>
    }
}

class Paragraph extends React.Component {
    constructor(props){
        super(props);
    }
    render(){
        let { lines = 1, animated } = this.props;
        return <div className = 'yon-skeleton-paragraph-box'>
            {
                new Array(lines).fill(1).map(item => {
                    return <div className={`yon-skeleton-paragraph ${animated ? 'yon-skeleton-title-box-animated' : ''}`}></div>
                })
            }
        </div>
    }
}

class YonSkeleton extends React.Component {
    constructor(props){
        super(props);
    }
    render (){
        let { children } = this.props;
        return <div className = 'yon-skeleton-box'>
            {
                children
            }
        </div>
    }
}

YonSkeleton.Title = Title;
YonSkeleton.Paragraph = Paragraph;

export default YonSkeleton;

组件样式如下:

.yon-skeleton-title-box {
    width: 500px;
    height: 32px;
    background-color: rgba(190, 190, 190, 0.2);
}
.yon-skeleton-title-box-animated {
    background-image: linear-gradient(
      90deg,
      rgba(190, 190, 190, 0.2) 25%,
      rgba(129, 129, 129, 0.24) 37%,
      rgba(190, 190, 190, 0.2) 63%
    );
    background-size: 400% 100%;
    animation: yon-skeleton-loading 1.4s ease infinite;
}
.yon-skeleton-paragraph-box {
    margin-top: 10px;
    .yon-skeleton-paragraph {
        margin-top: 10px;
        width: 500px;
        height: 16px;
        background-color: hsla(0,0%,74.5%,.2);
    }
}
@keyframes yon-skeleton-loading {
    0% {
        background-position: 100% 50%;
    }
    100% {
    background-position: 0 50%;
    }
}

最后

这篇骨架屏组件的文章说实话有点水,想喷我的不要隐藏,欢迎评论区里指点江山,那么下篇文章再见啦。