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

记录--Loading 用户体验 - 加载时避免闪烁

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

在切换详情页中有这么一个场景,点击上一条,会显示上一条的详情页,同理,点击下一条,会显示下一条的详情页。

伪代码如下所示:

我们定义了一个 switcher 模版, 用户点击上一条、下一条时调用 goToPreOrNext 方法。该页面通过 loadingDone 状态判断是否展示加载效果。

// html
<thy-loading [thyDone]="loadingDone"></thy-loading>
<ng-container *ngIf="loadingDone"><styx-pivot-detail>...<thy-arrow-switcher...(thyPrevious)="goToPreOrNext($event)"(thyNext)="goToPreOrNext($event)"></thy-arrow-switcher>...</styx-pivot-detail>
</ng-container>

在 goToPreOrNext 方法中,当调用该方法时,通过 goToPreOrNextResolve 接口返回下一条的详情 id,通过该 id 请求详情数据。

// 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {...this.goToPreOrNextResolve(event.index, topicId).subscribe((id: string) => {this.getDetail(id);}...)
}// 请求详情数据
getDetail(postId: string) {this.loadingDone = false;this.store.fetchPost(postId).pipe(finalize(() => {this.loadingDone = true;})).subscribe();
}

这看起来好像没有什么问题,应该一般都是这么干的,我们运行看看。

🌠 如何切换时候不闪?

与最上面的相比,有没有发现每次切换时,都会闪一下,用户体验很不好,有没有办法可以解决它?

这个问题就是 loadingDone 的状态切换导致的,我们把 loadingDone 干掉是不是就可以了?

如下代码所示:

// 请求详情数据
getDetail(postId: string) {// 注释掉这一行// this.loadingDone = false;this.store.fetchPost(postId).pipe(finalize(() => {this.loadingDone = true;})).subscribe();
}

好像方案可行?

但是把网络调成低速 3G 后,会发现,我们的加载效果没了,页面像卡住了一样,这当然不行。

有没有更好的方案?

⏰ setTimeout 方案

把先前 loadingDone 状态不放到 getDetail 方法中,而是单独拿出来紧跟 this.getDetail(id) 后面。

代码如下:

// 定义一个 timer
**private timer = null;**// 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {...this.goToPreOrNextResolve(event.index, topicId).subscribe((id: string) => {this.getDetail(id);**this.timer = setTimeout(() => {this.loadingDone = false;}, 500);**}...)
}// 请求详情数据
getDetail(postId: string) {// 删除掉该行loadingDone 代码**// this.loadingDone = false;**this.store.fetchPost(postId).pipe(finalize(() => {this.loadingDone = true;// 记得清除**clearTimeout(this.timer);**})).subscribe();
}

这么做的含义就是,我们给到 loadingDone 500ms 的缓冲时间,如果 500ms 内返回数据了,则没有 loading 的效果,如果没有加载回来,在会显示加载中。

一般情况如下所示:

 低速网络下的效果:

这确实是一种方案,但是总感觉哪里怪怪的。

这里是个定时任务并且 500ms 后触发。试想一种结果,当我快速点击下一条并且在 300ms 获取到了数据并把 loadingDone 状态置为 true, 但 500ms时,loadingDone 状态置为 false,造成假死的情况,显然这不是我们想要的。

那这该如何解决?

💎 RxJS 大法

抛去使用 setTimeout 的方案,我们对 getDetail 代码改成如下的形式。

大致的思路是,将请求的 loading 状态与数据获取的状态分离,并定义了两个流 result$showLoadingIndicator$

result$ 流请求到数据之后,之后之后的一些操作, showLoadingIndicator$ 流则负责 loading 状态的推送。

来看看怎么一步一步实现的:

首先我们定义一个请求的流。

const fetchPost$ = () => this.store.fetchPost(postId);

然后分别定义了两个流 result$ 和 showLoadingIndicator$。这里的 share() 函数是因为会有两个订阅它的地方。

 const result$ = fetchPost$().pipe(share());const showLoadingIndicator$;

然后我们来处理 showLoadingIndicator$ 流。

我们期望在 500ms 内请求到的数据,则不应该展示 loading,否则,应该展示 loading 状态。

const showLoadingIndicator$ = timer(500).pipe(mapTo(true), takeUntil(result$))

如果在 500ms 后很快请求到了数据,为了避免闪屏,我们需要让 loading 至少显示 1s。然后使用 merge() 合并这两种结果。

const showLoadingIndicator$ = merge(timer(500).pipe(mapTo(true), takeUntil(result$)),combineLatest(result$, timer(1000)).pipe(mapTo(false))).pipe(startWith(false), distinctUntilChanged());

最后订阅它们。

result$.subscribe(result => {// 请求到结果后的操作},error => {// TODO});showLoadingIndicator$.subscribe(isLoading => {// 更新 loadingDone 状态this.loadingDone = !isLoading;});

完整的代码如下:

// 请求下一条 id
fetchPreOrNext(event: ThyArrowSwitcherEvent) {...this.goToPreOrNextResolve(event.index, topicId).subscribe((id: string) => {this.getDetail(id);}...)
}// 请求详情数据
getDetail(postId: string) {const fetchPost$ = () => this.store.fetchPost(postId);const result$ = fetchPost$().pipe(share());const showLoadingIndicator$ = merge(timer(500).pipe(mapTo(true), takeUntil(result$)),combineLatest(result$, timer(1000)).pipe(mapTo(false))).pipe(startWith(false), distinctUntilChanged());result$.subscribe(result => {// TODO},error => {// TODO});showLoadingIndicator$.subscribe(isLoading => {this.loadingDone = !isLoading;});
}

如果想更细致知道如何实现的,参考下面这篇文档:

Loading indication with a delay and anti-flickering in RxJS

本文转载于:

https://juejin.cn/post/7176943529057321017

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 

相关文章:

记录--Loading 用户体验 - 加载时避免闪烁

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 在切换详情页中有这么一个场景&#xff0c;点击上一条&#xff0c;会显示上一条的详情页&#xff0c;同理&#xff0c;点击下一条&#xff0c;会显示下一条的详情页。 伪代码如下所示&#xff1a; 我们…...

系统架构设计专业技能 · 软件工程之软件测试与维护(六)【系统架构设计师】

系列文章目录 系统架构设计专业技能 网络规划与设计&#xff08;三&#xff09;【系统架构设计师】 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师…...

基于亚奈奎斯特采样和SOMP算法的平板脉冲响应空间插值matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...................................................................... %fine regular gr…...

柏睿向量数据库Rapids VectorDB赋能企业级大模型构建及智能应用

ChatGPT的问世,在为沉寂已久的人工智能重新注入活力的同时,也把长期默默无闻的向量数据库推上舞台。今年4月以来,全球已有4家知名向量数据库公司先后获得融资,更加印证了向量数据库在AI大模型时代的价值。 什么是向量数据库? 在认识向量数据库前,先来了解一下最常见的关…...

装备合成(牛客)

登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 牛牛有x件材料a和y件材料b&#xff0c;用2件材料a和3件材料b可以合成一件装备&#xff0c;用4件材料a和1件材料b也可以合成一件装备。牛牛想要最大化合成的装备的数量&#xff0c;于是牛牛找来了你帮忙。 分析&#xff…...

C语言学习之一级指针二级指针

一级指针&#xff1a;内存中每个字节都有一个编号&#xff0c;这个编号就是指针&#xff0c;也称作地址&#xff1b;专门用来存储地址的变量&#xff0c;就是指针变量&#xff1b;定义一级指针变量并初始化&#xff1a; 数据类型 *指针变量名 &普通变量名; 数据类型 *指针…...

【腾讯云 Cloud Studio 实战训练营】使用 Cloud Studio 快速构建 Vue + Vite 完成律师 H5 页面

【腾讯云 Cloud Studio 实战训练营】使用 Cloud Studio 快速构建 Vue Vite 完成律师 H5 页面 前言一、基本介绍1.应用场景2.产品优势 二、准备工作1.注册 Cloud Studio2.进入 Vue 预置开发环境 三、使用 Cloud Studio 快速构建 Vue Vite 完成律师 H5 页面1.安装相关依赖包2.主…...

Vim常用指令

Vim常用指令 Vim是一个强大的文本编辑器&#xff0c;它在命令行界面下工作&#xff0c;拥有丰富的功能和快捷键。本文将介绍一些常用的Vim指令&#xff0c;帮助您更高效地使用Vim编辑器。 基本操作 以下是一些基本的Vim操作指令&#xff1a; i&#xff1a;进入插入模式&…...

24届近3年青岛理工大学自动化考研院校分析

今天给大家带来的是青岛理工大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、青岛理工大学 学校简介 青岛理工大学是一所以工为主&#xff0c;土木建筑、机械制造、环境能源学科特色鲜明&#xff0c;理工经管文法艺等学科协调发展的多科性大学。是国家首批地方…...

进入现代云技术的世界-APIGateway、ServiceMesh、OpenStack、异步化框架、云原生框架、命令式API与声明式API

目录 APIGateway Service Mesh OpenStack 异步化框架 云原生框架 命令式API与声明式API APIGateway API网关&#xff08;API Gateway&#xff09;是一个服务器——充当了客户端和内部服务之间的中间层。API网关负责处理API请求&#xff0c;将客户端的请求路由到相应的后端…...

Macbook 终端 git 命令补全和提示

Mac OS自带的终端&#xff0c;用起来虽然有些不太方便&#xff0c;界面也不够友好&#xff0c;关键是在windows上用习惯了自动补全功能&#xff0c;在Mac上一个个的拼写单词是真的难受&#xff0c;逼着我记英文单词。 经过一天的磨合&#xff0c;我实在忍不了&#xff0c;在网上…...

2024考研408-计算机网络 第六章-应用层学习笔记

文章目录 前言一、网络应用模型1.1、认识应用层功能和特点1.2、网络应用层模型&#xff1a;1.2.1、客户/服务器&#xff08;C/S&#xff09;模型1.2.2、P2P模型 二、DNS系统2.1、认识DNS与IP地址的关系2.2、DNS解析的大致流程2.3、域名的分类2.4、域名服务器的分类2.5、域名解析…...

使用阿里云服务器部署和使用GitLab

本文阿里云百科分享使用阿里云服务器部署和使用GitLab&#xff0c;GitLab是Ruby开发的自托管的Git项目仓库&#xff0c;可通过Web界面访问公开的或者私人的项目。本教程介绍如何部署和使用GitLab。 目录 准备工作 部署GitLab环境 使用GitLab 登录GitLab 生成密钥对文件并…...

React入门学习笔记3

事件处理 通过onXxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件——为了更好的兼容性 eg&#xff1a;οnclick》onClickReact中的事件是通过事件委托方式处理的(委托给组件最外层的元素)——为了更高效通过event.target得到发生…...

从零开始理解Linux中断架构(25)中断运行全景实例

前面我们基本理解了软中断处理的基本框架,为了对中断调用有一个全景的直观感受,我们在网卡驱动程序的中断函数dump_stack,观看一下各种情况下的软中断调用call Stack的情况。 (1)ksoftirqd处理软中断的情况 有线以太网卡NAPI轮询的调用栈 [ 106.374117] Hardware name: K…...

go-zero 是如何实现计数器限流的?

原文链接&#xff1a; 如何实现计数器限流&#xff1f; 上一篇文章 go-zero 是如何做路由管理的&#xff1f; 介绍了路由管理&#xff0c;这篇文章来说说限流&#xff0c;主要介绍计数器限流算法&#xff0c;具体的代码实现&#xff0c;我们还是来分析微服务框架 go-zero 的源…...

【考研复习】24王道数据结构课后习题代码|第3章栈与队列

文章目录 3.1 栈3.2 队列3.3 栈和队列的应用 3.1 栈 int symmetry(linklist L,int n){char s[n/2];lnode *pL->next;int i;for(i0;i<n/2;i){s[i]p->data;pp->next;}i--;if(n%21) pp->next;while(p&&s[i]p->data){i--;pp->next;}if(i-1) return 1;…...

java中excel文件下载

1、System.getProperty(user.dir) 获取的是启动项目的容器位置 2、 Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING); StandardCopyOption.REPLACE_EXISTING 来忽略文件已经存在的异常&#xff0c;如果存在就去覆盖掉它Sta…...

29 | 广州美食店铺数据分析

广州美食店铺数据分析 一、数据分析项目MVP加/价值主张宣言 随着经济的快速发展以及新媒体的兴起,美食攻略、美食探店等一系列东西进入大众的眼球,而人们也会在各大平台中查找美食推荐,因此本项目做的美食店铺数据分析也是带有可行性的。首先通过对广东省的各市美食店铺数量…...

fastApi基础

1、fastApi简介 官方文档&#xff1a;https://fastapi.tiangolo.com/ 源码&#xff1a; https://github.com/tiangolo/fastapi 2、环境准备 安装python 安装pycharm 安装fastAPI 安装 uvicorn 查看已经安装的第三方库&#xff1a;pip list 查看pip 配置信息&#xff1a;pip co…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

Caliper 负载(Workload)详细解析

Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...