uni-app 页面加载提示对比分析.md 5.8 KB

uni-app 页面加载提示对比分析

概述

本文档对比分析了 uni-app 项目中两种常见的页面加载提示实现方式:全局加载提示和骨架屏加载动画。通过对比 my-patients.vuemessage-detail.vue 两个页面的具体实现,总结各自的特点、适用场景和优缺点。

实现方式对比

1. 全局加载提示(my-patients.vue)

实现原理

  • 使用 uni-app 提供的 uni.showLoading()uni.hideLoading() API
  • 在数据请求开始时显示全局模态框,请求完成后隐藏

代码示例

const fetchPatients = async () => {
  uni.showLoading({ title: '加载中...' })
  
  try {
    // 数据请求逻辑
    const response = await listUserBindingsByBoundUser(...)
    // 处理响应
  } catch (error) {
    // 错误处理
  } finally {
    uni.hideLoading()
  }
}

特点

  • 优点
    • 实现简单,只需几行代码
    • 用户体验一致,uni-app 原生支持
    • 阻塞用户交互,防止重复操作
  • 缺点
    • 全局模态框会遮挡整个页面
    • 无法显示内容预览或进度信息
    • 在小程序中可能有样式限制

适用场景

  • 数据加载时间较短(< 3秒)
  • 页面内容不需要预览
  • 希望阻止用户在加载期间进行其他操作

2. 骨架屏加载动画(message-detail.vue)

实现原理

  • 使用 Vue 的条件渲染 v-if="loading"
  • 在模板中创建模拟真实内容的占位符结构
  • 通过 CSS 动画实现闪烁效果

代码示例

<template>
  <!-- 骨架屏 -->
  <view v-if="loading" class="skeleton-container">
    <view class="skeleton-card" v-for="i in 3" :key="i">
      <view class="skeleton-header">
        <view class="skeleton-line skeleton-title"></view>
        <view class="skeleton-line skeleton-small"></view>
      </view>
      <view class="skeleton-content">
        <view class="skeleton-line skeleton-text"></view>
        <view class="skeleton-line skeleton-text"></view>
        <view class="skeleton-line skeleton-text skeleton-short"></view>
      </view>
    </view>
  </view>

  <!-- 实际内容 -->
  <view v-else class="message-list">
    <!-- 真实消息列表 -->
  </view>
</template>

<script setup>
const loading = ref(true)

const fetchMessages = async () => {
  loading.value = true
  try {
    // 数据请求逻辑
  } finally {
    loading.value = false
  }
}
</script>

CSS 样式示例

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

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

特点

  • 优点
    • 视觉体验更好,能预览页面布局
    • 不阻塞用户交互,可以浏览其他内容
    • 自定义程度高,可设计独特的加载动画
    • 提升用户感知的加载速度
  • 缺点
    • 实现复杂度较高,需要设计骨架结构
    • 需要维护两套布局(骨架和真实内容)
    • CSS 动画可能影响性能

适用场景

  • 数据加载时间较长(> 2秒)
  • 页面布局复杂,需要内容预览
  • 希望保持用户交互流畅性
  • 追求更好的视觉体验

对比总结

特性 全局加载提示 骨架屏加载动画
实现复杂度 中等
用户体验 一般 优秀
视觉效果 简单 丰富
交互阻塞
自定义程度
性能影响 中等
适用数据量 小数据 大数据/复杂页面

选择建议

  1. 简单页面/快速加载:推荐使用全局加载提示
  2. 复杂页面/慢速加载:推荐使用骨架屏
  3. 混合使用:可以结合两者,先显示骨架屏,再叠加全局提示

最佳实践

  1. 根据页面复杂度选择合适的加载方式
  2. 设置合理的超时时间,避免无限加载
  3. 在错误情况下也要隐藏加载状态
  4. 考虑不同平台的兼容性
  5. 测试加载状态下的用户交互

常见问题与解决方案

骨架屏与实际内容同时显示问题

问题现象

在使用骨架屏加载动画时,从其他页面(如编辑页面)返回时,骨架屏下方残留有之前的实际列表内容,导致加载状态与旧数据同时显示,影响用户体验。

问题原因

模板中骨架屏使用 v-if="loading" 条件显示,但实际内容列表没有相应的条件隐藏。在数据重新加载期间,loading 为 true 时骨架屏显示,但旧的列表数据仍然可见,因为没有 v-if="!loading" 限制。

解决办法

将实际内容区域包装在 v-if="!loading" 条件中,确保加载时只显示骨架屏,加载完成后显示实际内容。

错误示例:

<view v-if="loading" class="skeleton-list">
  <!-- 骨架屏 -->
</view>
<view class="news-card" v-for="item in list" :key="item.id">
  <!-- 实际列表,无条件隐藏 -->
</view>

正确示例:

<view v-if="loading" class="skeleton-list">
  <!-- 骨架屏 -->
</view>
<view v-if="!loading">
  <view class="news-card" v-for="item in list" :key="item.id">
    <!-- 实际列表 -->
  </view>
  <!-- 其他内容如空状态、加载更多等 -->
</view>

经验教训

  • 骨架屏和实际内容应使用互斥的条件渲染,避免同时显示
  • 在页面重新加载(如 onShow 触发)时,确保旧数据被正确隐藏
  • 参考 message-detail.vue 的实现模式,确保加载状态管理的完整性

相关文件

  • src/pages/doctor/index/my-patients.vue - 全局加载提示示例
  • src/pages/public/message-detail.vue - 骨架屏加载动画示例
  • src/pages/doctor/manage/news.vue - 骨架屏逻辑修复示例
  • d:\慢病APP\Dev\uniapp-ts\docs\uni-app 页面加载提示对比分析.md