当前位置: 首页 > 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.gsyq.cn/news/137628.html

相关文章:

  • 歌词滚动姬:终极免费歌词制作工具完整指南
  • 使用STM32对SD卡进行性能测试
  • 重新定义游戏视觉:深度解锁个性化外观定制全攻略
  • Java毕设选题推荐:基于Springboot+vue+mysql的人力资源管理系统设计与基于springboot的人力资源管理系统的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 如何快速掌握LeagueSkinChanger:游戏爱好者的终极皮肤定制指南
  • 提高STM32数据完整性:奇偶校验实战教程
  • 小爱音箱音乐自由:5分钟解锁无限播放权限的终极方案
  • BetterNCM Installer:让网易云音乐焕然一新的智能安装神器
  • NVIDIA显卡色彩校准终极指南:novideo_srgb完全使用教程
  • 3分钟搞定Figma中文界面:零基础设计师的完美本地化方案
  • APK Editor Studio 终极指南:一站式安卓应用编辑解决方案
  • 终极指南:如何用CTFCrackTools快速应对CTF密码挑战
  • BetterNCM安装工具完整使用指南:新手上手指南
  • 业的通讯调试工具或者平台有哪些
  • 2025年国内地坪源头厂商最新推荐排行榜:聚焦优质企业服务与性能,助力客户精准选型 - 呼呼拉呼
  • Deepin Boot Maker 终极指南:一键制作Linux启动盘的完整教程
  • 容器化部署中的目录挂载问题排查与修复指南
  • 2025.12.22 - 呓语
  • 快速提取碧蓝航线Live2D模型:新手3分钟入门指南
  • 2025.12.21 模拟赛
  • qmc-decoder:彻底解决音频格式受限的专业解码方案
  • 香港理工大学发布DeContext:首个阻挡AI恶意换脸的“隐身衣“
  • Sketchfab模型下载终极教程:新手轻松上手完全指南
  • 2025年膜结构厂家最新推荐排行榜:膜结构停车棚、汽车棚、充电棚、自行车棚、景观棚、收费棚、体育棚、污水池棚、门头出入口棚、推拉棚公司推荐 - 呼呼拉呼
  • 深入解析:数据库操作与数据管理——Rust 与 SQLite 的集成
  • BetterNCM插件管理器:一键解锁音乐播放器无限潜能
  • WinDbg Preview反汇编窗口使用:入门级深度剖析
  • QMC音频解密终极教程:轻松解锁QQ音乐加密文件
  • 2025最值得关注的AI培训讲师大盘点,错过血亏! - 品牌测评鉴赏家
  • 直播弹幕数据如何真正为你的业务赋能?