跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptWeChat大前端

前端骨架屏实现详解:Vue、React、Angular、jQuery 及小程序实践

前端骨架屏的实现原理与应用。首先介绍骨架屏的概念及其在优化用户等待体验中的作用,通过流程图展示数据加载与界面渲染的逻辑关系。随后分别提供原生 JavaScript、Vue、React、Angular、jQuery 及微信小程序等多种环境下的骨架屏代码实现方案,包含 HTML 结构、CSS 动画样式及逻辑控制。文章还涵盖移动端适配要点、性能对比分析及常见问题解决方案,旨在帮助开发者提升页面加载感知速度,改善用户体验。

莫名其妙发布于 2026/3/30更新于 2026/9/1071 浏览
前端骨架屏实现详解:Vue、React、Angular、jQuery 及小程序实践

前端骨架屏实现详解

1. 引言:什么是骨架屏?

骨架屏是解决用户等待焦虑的神器。当页面加载时,先展示一个模拟真实内容布局的占位元素(骨架),告知用户'正在加载中',避免白屏带来的体验下降。

2. 学习目标

  1. 搞懂骨架屏的基本原理和机制;
  2. 掌握原生 JS 实现骨架屏的方法;
  3. 熟悉 Vue、React、Angular 等框架的最佳实践;
  4. 熟练运用移动端和小程序骨架屏实现;
  5. 会排查骨架屏常见坑点,避免踩雷。

3. 骨架屏原理详解

3.1 骨架屏基本流程图

graph TD
    A[页面开始加载] --> B{数据是否加载完成?}
    B -- 否 --> C[显示骨架屏]
    C --> D[展示占位元素]
    D --> B
    B -- 是 --> E[隐藏骨架屏]
    E --> F[渲染真实内容]

3.2 用户感知时间对比

使用骨架屏可显著降低用户感知的加载时间,提升满意度。

注意:骨架屏涉及用户体验、性能优化与视觉设计,不仅仅是画框。

4. 原生 JS 骨架屏实现思路与算法步骤

4.1 实现思路

  1. 在真实内容加载前,插入占位元素;
  2. 占位元素模拟真实内容的布局结构;
  3. 数据加载完成后,移除占位元素,显示真实内容。

4.2 算法步骤

步骤 1:创建骨架屏 HTML 结构
<div id="skeleton">
  <div class="skeleton-header"></div>
  <div class="skeleton-content">
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
  </div>
</div>
<div id="content" style="display:none;">
  <!-- 真实内容 -->
</div>
步骤 2:添加 CSS 样式
.skeleton-header {
  width: 100%;
  height: 60px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

.skeleton-line {
  width: 100%;
  height: 20px;
  margin: 10px 0;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
步骤 3:JavaScript 控制显示/隐藏
// 模拟数据加载
function loadData() {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve({ title: '真实标题', content: '真实内容内容内容...' });
    }, 2000);
  });
}

// 显示骨架屏
function showSkeleton() {
  document.getElementById('skeleton').style.display = 'block';
  document.getElementById('content').style.display = 'none';
}

// 隐藏骨架屏,显示真实内容
function hideSkeleton(data) {
  document.getElementById('skeleton').style.display = 'none';
  document.getElementById('content').style.display = 'block';
  document.getElementById('content').innerHTML = `
    <h1>${data.title}</h1>
    <p>${data.content}</p>
  `;
}

// 主流程
async function init() {
  showSkeleton();
  const data = await loadData();
  hideSkeleton(data);
}
init();

5. Vue 骨架屏最佳实践

5.1 Vue 组件实现

核心思想
  1. 通过 loading 状态控制骨架屏和真实内容的显示切换;
  2. 使用 v-if 指令根据加载状态显示不同内容;
  3. 用渐变动画模拟'加载中'的效果;
  4. 加载完成后更新数据,自动切换到真实内容。
代码详解
<template>
  <div class="page-container">
    <!-- 骨架屏 -->
    <div v-if="loading" class="skeleton-wrapper">
      <div class="skeleton-header"></div>
      <div class="skeleton-content">
        <div class="skeleton-line" v-for="i in 5" :key="i"></div>
      </div>
    </div>
    <!-- 真实内容 -->
    <div v-else class="content-wrapper">
      <h1>{{ article.title }}</h1>
      <p>{{ article.content }}</p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ArticlePage',
  data() {
    return {
      loading: true,
      article: {}
    };
  },
  async mounted() {
    // 模拟 API 调用
    const response = await this.fetchArticle();
    this.article = response;
    this.loading = false;
  },
  methods: {
    fetchArticle() {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve({ title: 'Vue 骨架屏实践', content: '这是 Vue 骨架屏的详细内容...' });
        }, 2000);
      });
    }
  }
};
</script>

<style scoped>
.skeleton-header {
  width: 100%;
  height: 60px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  margin-bottom: 20px;
}

.skeleton-line {
  width: 100%;
  height: 20px;
  margin: 10px 0;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  border-radius: 4px;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
</style>
关键点分析
  1. v-if="loading":核心逻辑,控制显示状态。
  2. v-for:循环生成骨架行,模拟内容区域。
  3. scoped:样式作用域限制,避免影响其他组件。
优化建议
  1. 添加最小显示时间:防止网络极快时骨架屏一闪而过。
    async mounted() {
      const startTime = Date.now();
      const response = await this.fetchArticle();
      const elapsed = Date.now() - startTime;
      if (elapsed < 1000) {
        await new Promise(resolve => setTimeout(resolve, 1000 - elapsed));
      }
      this.article = response;
      this.loading = false;
    }
    
  2. 错误处理:确保加载失败也能关闭骨架屏。
    async mounted() {
      try {
        const response = await this.fetchArticle();
        this.article = response;
      } catch (error) {
        console.error('加载失败:', error);
      } finally {
        this.loading = false;
      }
    }
    

6. React 骨架屏最佳实践

6.1 React 组件实现

import React, { useState, useEffect } from 'react';
import './Skeleton.css';

const SkeletonScreen = () => {
  const [loading, setLoading] = useState(true);
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setTimeout(() => {
        setData({ title: 'React 骨架屏实践', content: '这是 React 骨架屏的详细内容...' });
        setLoading(false);
      }, 2000);
    };
    fetchData();
  }, []);

  if (loading) {
    return (
      <div className="skeleton-wrapper">
        <div className="skeleton-header"></div>
        <div className="skeleton-content">
          {[...Array(5)].map((_, index) => (
            <div key={index} className="skeleton-line"></div>
          ))}
        </div>
      </div>
    );
  }

  return (
    <div className="content-wrapper">
      <h1>{data.title}</h1>
      <p>{data.content}</p>
    </div>
  );
};

export default SkeletonScreen;

6.2 CSS 样式文件

/* Skeleton.css */
.skeleton-wrapper { padding: 20px; }
.skeleton-header {
  width: 100%;
  height: 60px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  margin-bottom: 20px;
  border-radius: 8px;
}
.skeleton-line {
  width: 100%;
  height: 20px;
  margin: 10px 0;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  border-radius: 4px;
}
@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

7. jQuery 骨架屏实现

<!DOCTYPE html>
<html>
<head>
<title>jQuery 骨架屏</title>
<style>
.skeleton-header {
  width: 100%;
  height: 60px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  margin-bottom: 20px;
}
.skeleton-line {
  width: 100%;
  height: 20px;
  margin: 10px 0;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}
@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
</style>
</head>
<body>
<div id="skeleton">
  <div class="skeleton-header"></div>
  <div class="skeleton-content">
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
    <div class="skeleton-line"></div>
  </div>
</div>
<div id="content" style="display:none;"><!-- 真实内容将在这里显示 --></div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
  function showSkeleton() {
    $('#skeleton').show();
    $('#content').hide();
  }

  function hideSkeleton(content) {
    $('#skeleton').hide();
    $('#content').html(content).show();
  }

  function loadData() {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve('<h1>jQuery 骨架屏内容</h1><p>这是通过 jQuery 实现的骨架屏效果</p>');
      }, 2000);
    });
  }

  async function init() {
    showSkeleton();
    const content = await loadData();
    hideSkeleton(content);
  }
  init();
});
</script>
</body>
</html>

8. Angular 骨架屏最佳实践

// skeleton.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-skeleton',
  template: `
    <div *ngIf="loading">
      <div></div>
      <div>
        <div *ngFor="let i of [1,2,3,4,5]"></div>
      </div>
    </div>
    <div *ngIf="!loading">
      <h1>{{ data.title }}</h1>
      <p>{{ data.content }}</p>
    </div>
  `,
  styles: [`
    .skeleton-header { width: 100%; height: 60px; background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: loading 1.5s infinite; margin-bottom: 20px; border-radius: 8px; }
    .skeleton-line { width: 100%; height: 20px; margin: 10px 0; background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: loading 1.5s infinite; border-radius: 4px; }
    @keyframes loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
  `]
})
export class SkeletonComponent implements OnInit {
  loading = true;
  data: any = {};

  ngOnInit() {
    this.loadData();
  }

  loadData() {
    setTimeout(() => {
      this.data = { title: 'Angular 骨架屏实践', content: '这是 Angular 骨架屏的详细内容...' };
      this.loading = false;
    }, 2000);
  }
}

9. 移动端骨架屏最佳实践

9.1 移动端适配要点

  1. 响应式设计:适配不同屏幕尺寸;
  2. 触摸友好:避免误触;
  3. 性能优化:减少 DOM 操作。

9.2 移动端 CSS 优化

/* 移动端骨架屏样式 */
.skeleton-mobile { padding: 15px; }
.skeleton-mobile .skeleton-header { height: 50px; border-radius: 6px; }
.skeleton-mobile .skeleton-line { height: 16px; margin: 8px 0; border-radius: 3px; }

/* 媒体查询适配 */
@media(max-width: 768px) {
  .skeleton-mobile .skeleton-header { height: 45px; }
  .skeleton-mobile .skeleton-line { height: 14px; margin: 6px 0; }
}

10. 小程序骨架屏最佳实践

10.1 微信小程序实现

<!-- skeleton.wxml -->
<view class="skeleton-container" wx:if="{{loading}}">
  <view class="skeleton-header"></view>
  <view class="skeleton-content">
    <view class="skeleton-line" wx:for="{{lines}}" wx:key="index"></view>
  </view>
</view>
<view class="content-container" wx:else>
  <text class="title">{{article.title}}</text>
  <text class="content">{{article.content}}</text>
</view>
/* skeleton.wxss */
.skeleton-header {
  width: 100%;
  height: 60rpx;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  margin-bottom: 20rpx;
  border-radius: 8rpx;
}
.skeleton-line {
  width: 100%;
  height: 30rpx;
  margin: 15rpx 0;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  border-radius: 4rpx;
}
@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
// skeleton.js
Page({
  data: {
    loading: true,
    lines: [1, 2, 3, 4, 5],
    article: {}
  },
  onLoad() {
    this.loadArticle();
  },
  loadArticle() {
    setTimeout(() => {
      this.setData({
        loading: false,
        article: { title: '小程序骨架屏实践', content: '这是小程序骨架屏的详细内容...' }
      });
    }, 2000);
  }
});

11. 骨架屏性能对比与优化建议

11.1 性能对比表

实现方式加载感知时间用户满意度实现复杂度
无骨架屏3.2s60%简单
骨架屏2.1s85%中等
预加载1.5s95%复杂

11.2 优化建议

  1. 合理使用:只在必要时使用骨架屏;
  2. 样式简洁:避免过于复杂的动画效果;
  3. 内容匹配:骨架屏结构要与真实内容一致;
  4. 性能监控:监控骨架屏对性能的影响。

12. 常见问题与解决方案

问题原因解决方案
骨架屏闪烁显示时间过短增加最小显示时间
布局错位样式不匹配精确匹配真实内容布局
性能下降动画过多简化动画效果
兼容性问题CSS 不支持使用兼容性更好的方案

13. 总结

项目内容
核心原理占位元素 + 动画效果
实现方式原生 JS、Vue、React、Angular 等
关键技术CSS 动画、条件渲染
移动端适配响应式设计、触摸优化
小程序支持微信、支付宝等平台
性能优化减少 DOM 操作、简化动画
用户体验降低等待焦虑、提升感知速度

14. 结语

骨架屏只是优化用户体验的第一步,后面还有懒加载、预加载、缓存策略等等一堆东西等着你去探索。动手实践,让页面加载更丝滑!

目录

  1. 前端骨架屏实现详解
  2. 1. 引言:什么是骨架屏?
  3. 2. 学习目标
  4. 3. 骨架屏原理详解
  5. 3.1 骨架屏基本流程图
  6. 3.2 用户感知时间对比
  7. 4. 原生 JS 骨架屏实现思路与算法步骤
  8. 4.1 实现思路
  9. 4.2 算法步骤
  10. 步骤 1:创建骨架屏 HTML 结构
  11. 步骤 2:添加 CSS 样式
  12. 步骤 3:JavaScript 控制显示/隐藏
  13. 5. Vue 骨架屏最佳实践
  14. 5.1 Vue 组件实现
  15. 核心思想
  16. 代码详解
  17. 关键点分析
  18. 优化建议
  19. 6. React 骨架屏最佳实践
  20. 6.1 React 组件实现
  21. 6.2 CSS 样式文件
  22. 7. jQuery 骨架屏实现
  23. 8. Angular 骨架屏最佳实践
  24. 9. 移动端骨架屏最佳实践
  25. 9.1 移动端适配要点
  26. 9.2 移动端 CSS 优化
  27. 10. 小程序骨架屏最佳实践
  28. 10.1 微信小程序实现
  29. 11. 骨架屏性能对比与优化建议
  30. 11.1 性能对比表
  31. 11.2 优化建议
  32. 12. 常见问题与解决方案
  33. 13. 总结
  34. 14. 结语

更多推荐文章

查看全部
  • Python 进阶与高级语法详解
  • Neo4j 安装与配置教程(Windows/MacOS/Linux)
  • YOLOv8 旋转框角度回归优化:CSL 与 DCL 编码实战
  • Vue3 组件方法调用无效或提示不存在的排查与修复
  • Spring Boot 与 Leaflet 实现省域迂回可视化实战
  • VS Code 远程连接服务器后 GitHub Copilot 无法使用问题排查
  • OpenClaw:AI 直接操控电脑的开源工具
  • Spring Cloud Alibaba 2026 微服务实战指南
  • 基于MATLAB的三维A星算法无人机导航与路径规划
  • 基于 AI 与代理池的智能电商价格监控系统实战
  • OpenClaw 搭建飞书 AI 办公机器人(含本地 Ollama 接入与 Skills)
  • VS Code GitHub Copilot 完整使用教程
  • PyCharm 安装 Python 模块失败?常见 pip 报错原因与解决方案
  • Python 接口测试之 requests 库核心用法
  • Python 正则表达式基础、常用函数及 Pandas 应用示例
  • DeepSeek 云电脑部署实测:ToDesk、顺网与海马云横向对比
  • FPGA 实现任意角度图像旋转原理与代码设计
  • MCP 协议详解:与 Function Call 的区别及 Python 实现
  • 自然语言处理高级应用与前沿技术实战指南
  • Python 使用 Pandas 筛选 Excel 数据并剔除区间外值

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online