当前位置: 首页 > news >正文

HarmonyOS Web 加载骨架屏 + Web 淡入动画模板(可直接用)

HarmonyOS Web 加载骨架屏 + Web 淡入动画模板(可直接用)

一起来构建生态吧~

在真实项目里,Web 页面加载体验好不好,不取决于页面最终长什么样,而取决于:
用户点进去后的前 1~3 秒你给了什么反馈

如果这段时间是白屏、卡住、没反应,哪怕页面最后加载得再漂亮,体验分也已经掉了。

这篇文章我给你一套可以直接复制进工程使用的方案,实现这几个目标:

  • 页面一进来 立刻显示原生骨架屏
  • Web 在后台加载,不抢视觉
  • Web 可展示时 淡入
  • 骨架屏 淡出
  • 全程无白屏、无闪烁、无突兀跳变

一、整体思路(先讲清楚,不然容易写歪)

一句话概括这套方案:

Web 始终存在,但一开始是透明的;
骨架屏覆盖在上面;
Web 准备好后淡入,骨架屏淡出。

关键点有 3 个:

  1. Web 不要等加载完才创建(否则必闪)
  2. 骨架屏是原生组件,不是 Web 里的 loading
  3. 动画只控制 opacity,不做 layout 变更

二、页面级完整模板(直接可用)

这是一个完整的 ArkTS 页面,你可以直接新建
WebSkeletonFadePage.ets 使用。

import { webview } from '@kit.ArkWeb';@Entry
@Component
struct WebSkeletonFadePage {private controller: webview.WebviewController = new webview.WebviewController();@State isSkeletonVisible: boolean = true;@State skeletonOpacity: number = 1;@State webOpacity: number = 0;@State progress: number = 0;@State showError: boolean = false;private fadeInWebAndHideSkeleton() {// 避免重复触发if (!this.isSkeletonVisible && this.webOpacity >= 1) return;// Web 淡入animateTo({ duration: 240, curve: Curve.EaseOut }, () => {this.webOpacity = 1;});// 骨架屏淡出animateTo({ duration: 220, curve: Curve.EaseIn }, () => {this.skeletonOpacity = 0;});// 动画结束后移除骨架屏setTimeout(() => {this.isSkeletonVisible = false;}, 240);}build() {Stack() {// Web 组件(始终存在,只是透明度变化)Web({src: 'https://example.com', // 换成你的地址或 rawfilecontroller: this.controller}).javaScriptAccess(true).onPageBegin(() => {this.showError = false;this.progress = 0;this.isSkeletonVisible = true;this.skeletonOpacity = 1;this.webOpacity = 0;}).onProgressChange((p: number) => {this.progress = p;// 经验值:80% 基本可见首屏if (p >= 80) {this.fadeInWebAndHideSkeleton();}}).onPageEnd(() => {// 兜底,确保一定淡入this.fadeInWebAndHideSkeleton();}).onRenderExited(() => {this.showError = true;this.isSkeletonVisible = false;this.webOpacity = 1;}).opacity(this.webOpacity).width('100%').height('100%')// 骨架屏if (this.isSkeletonVisible) {SkeletonLayer({progress: this.progress,opacity: this.skeletonOpacity})}// 错误态(可选)if (this.showError) {Column({ space: 12 }) {Text('加载失败').fontSize(18).fontWeight(FontWeight.Bold)Text('请检查网络后重试').opacity(0.7)Button('重试').onClick(() => {this.showError = false;this.isSkeletonVisible = true;this.skeletonOpacity = 1;this.webOpacity = 0;this.controller.refresh();})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}}.width('100%').height('100%')}
}

三、骨架屏组件(轻量但“像样”)

1️⃣ 骨架屏整体结构

@Component
struct SkeletonLayer {progress: number;opacity: number;build() {Column({ space: 14 }) {SkeletonBlock({ w: '70%', h: 18, r: 8 })SkeletonBlock({ w: '40%', h: 14, r: 8 })Column({ space: 12 }) {ForEach([1, 2, 3, 4, 5], () => {Column({ space: 10 }) {SkeletonBlock({ w: '100%', h: 120, r: 12 })Row({ space: 10 }) {SkeletonBlock({ w: '22%', h: 14, r: 8 })SkeletonBlock({ w: '30%', h: 14, r: 8 })SkeletonBlock({ w: '18%', h: 14, r: 8 })}}})}Text(`加载中… ${this.progress}%`).fontSize(12).opacity(0.6)}.padding(16).width('100%').height('100%').backgroundColor('#FFFFFF').opacity(this.opacity)}
}

单个骨架块(带轻微流光)

@Component
struct SkeletonBlock {w: string;h: number;r: number;@State shimmerOffset: number = -60;aboutToAppear() {setInterval(() => {animateTo({ duration: 900, curve: Curve.Linear }, () => {this.shimmerOffset =this.shimmerOffset >= 260 ? -60 : this.shimmerOffset + 80;});}, 950);}build() {Stack() {Rect().width(this.w).height(this.h).radius(this.r).opacity(0.12)Rect().width('30%').height(this.h).radius(this.r).translate({ x: this.shimmerOffset }).opacity(0.08)}}
}

四、为什么这套方案“看起来就高级”

这是我在项目里反复打磨出来的结论:

  • 骨架屏是“页面结构的预告”,不是转圈圈
  • 淡入动画是心理缓冲,让内容出现得“理所当然”
  • Web 不重排、不重建,性能稳定
  • 动画只改 opacity,最安全、最不容易出问题

五、我踩过的坑,你可以直接避开

骨架屏用 Web 自己的 loading

→ Web 没加载前你根本看不到它,白屏依旧。

onPageEnd 才显示 Web

→ 页面其实早就能看了,被你硬生生挡住。

动画期间改布局

→ 闪、抖、性能下降,一堆莫名其妙的问题。


六、推荐的实际使用策略

  • 首屏 Web 页面:用这套方案
  • 页面内跳转 URL:只用淡入,不用骨架
  • 协议页 / 轻页面:直接 loading 即可

七、一句话总结

Web 页面加载不是“等它加载完”,
而是“在它加载的这段时间,你给用户什么感觉”。

http://www.jsqmd.com/news/125225/

相关文章:

  • Xiaomusic终极安装指南:快速搭建智能音乐播放系统
  • Deepin Boot Maker终极指南:如何轻松制作专业级系统启动盘
  • Obsidian PDF导出终极指南:从笔记到专业文档的完整转换方案
  • XDMA驱动与UIO框架对比:驱动架构选择通俗解释
  • Semantic Kernel人工智能开发 - 第二章:环境搭建与第一个AI应用——从零开始构建智能对话系统
  • 执助考试资料大揭秘!选对资料,医考轻松上岸 - 品牌测评鉴赏家
  • 重新定义游戏视觉:深度解锁个性化外观定制全攻略
  • 歌词滚动姬:终极免费歌词制作工具完整指南
  • 使用STM32对SD卡进行性能测试
  • Andrej Karpathy亲授:2025年大模型技术发展六大关键点
  • BetterNCM安装器完整使用手册:一键解锁网易云音乐隐藏功能
  • 本地Cookie管理工具Get cookies.txt LOCALLY使用指南
  • Java毕设选题推荐:基于Springboot+vue+mysql的人力资源管理系统设计与基于springboot的人力资源管理系统的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • BlenderKit插件manifest配置完整指南:3步解决上传失败问题
  • Windows Defender彻底移除指南:释放系统性能的完整方案
  • 如何快速掌握LeagueSkinChanger:游戏爱好者的终极皮肤定制指南
  • BetterNCM安装器完整指南:3步实现网易云音乐功能升级
  • Chrome搜索替换插件终极指南:轻松修改任意网页文本
  • Deepin启动盘制作:从新手到高手的完整指南
  • Obsidian代码块美化:5个实用技巧让技术笔记脱胎换骨 ✨
  • 小爱音箱音乐自由:5分钟解锁无限播放权限的终极方案
  • 5分钟快速上手:专业歌词制作工具完全指南
  • BetterNCM Installer:让网易云音乐焕然一新的智能安装神器
  • 提高STM32数据完整性:奇偶校验实战教程
  • BetterNCM插件终极指南:打造专属网易云音乐体验
  • 3分钟掌握Reloaded-II模组加载器:新手零基础完整指南
  • APK Editor Studio 终极指南:一站式安卓应用编辑解决方案
  • NVIDIA显卡色彩校准终极指南:novideo_srgb完全使用教程
  • 3分钟搞定Figma中文界面:零基础设计师的完美本地化方案
  • BetterNCM安装工具完整使用指南:新手上手指南