前端性能优化(二) 骨架屏的使用

js代码

import React, { useState, useEffect } from 'react';
import ReactDom from 'react-dom';
import './App.css'
const card = (
  <div className="card">
    <div className="header">
      <img className="skeleton-img" src="https://source.unsplash.com/100x100/?animal" alt="" />
      <div data-title className="title">
        <div className="skeleton-text"></div>
        <div className="skeleton-text"></div>
      </div>
    </div>
    <div data-body>
      <div className="skeleton-text"></div>
      <div className="skeleton-text"></div>
      <div className="skeleton-text"></div>
      <div className="skeleton-text"></div>
    </div>
  </div>
);

function Skeleton() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
      .then((res) => res.json())
      .then((data) => {
        setPosts(data);
      });
  }, []);
  return (
    <div className="grid">
      {posts.length === 0
        ? Array(10).fill().map((_, index) => <div key={index}>{card}</div>)
        : posts.map((post) => (
          <div key={post.id} className="card">
            <div className="header">
              <img className="skeleton-img" src="https://source.unsplash.com/100x100/?animal" alt="Animal" />
              <div data-title className="title">
                {post.title}
              </div>
            </div>
            <div data-body>{post.body}</div>
          </div>
        ))}

    </div>
  );
}

export default Skeleton;

css代码

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  padding: 1rem;
  gap: 1rem;
}

.title {
  font-weight: bold;
  font-size: 1.25rem;
  width: 100%;
  height: 100%;
  word-wrap: none;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  flex-grow: 1;
}

.header {
  display: flex;
  margin-bottom: 1rem;
  align-items: center;
}

.card {
  background-color: white;
  border-radius: 0.5rem;
  box-shadow: rgba(0, 0, 0, 0.1) 0 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
  padding: 1rem;
}

img {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  flex-shrink: 0;
  object-fit: cover;
  margin-right: 1rem;
}

/* 渐进式效果 */
.skeleton-text {
  width: 100%;
  height: 0.5rem;
  /* background-image: linear-gradient(90deg, #ff0000 0%, #41de6a 37%, #ff0000 100%); */
  background-image: linear-gradient(90deg,
      hsl(200, 20%, 70%) 0%,
      hsl(200, 20%, 90%) 50%,
      hsl(200, 20%, 70%) 100%);
  /* background-image: linear-gradient(90deg, white 25%, red 37%, black 63%); */
  margin-bottom: 0.25rem;
  border-radius: 0.125rem;
  opacity: 0.7;
  background-size: 400% 100%;
  background-position: 100% 50%;
  animation: skeleton-text-loading 0.6s linear infinite;
}

.skeleton-text:last-child {
  width: 80%;
  margin-bottom: 0;
}

@keyframes skeleton-text-loading {
  0% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0 50%;
  }
}

/* 呼吸式效果 */
.skeleton-img {
  opacity: 0.7;
  animation: skeleton-img-loading 1s linear infinite alternate;
}

@keyframes skeleton-img-loading {
  0% {
    background-color: hsl(200, 20%, 70%);
  }

  100% {
    background-color: hsl(200, 20%, 95%);
  }
}

li {
  background-image: linear-gradient(90deg, #ff0000 25%, #41de6a 37%, #ff0000 63%);
  width: 100%;
  height: 0.6rem;
  list-style: none;
  background-size: 400% 100%;
  background-position: 300% 50%;
}

参考链接:https://juejin.cn/post/7293765765126733859?searchId=202408271516313ED5BAB612E929DFF4A3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值