工作问题记录React(持续更新中)

ops/2024/9/24 20:24:47/

一、backdrop-filter:blur(20px);

毛玻璃效果,在安卓机上有兼容问题,添加兼容前缀也无效;
解决方案:让设计师调整渐变,不要使用该属性!

在这里插入图片描述

复制代码

background: radial-gradient(33% 33% at 100% 5%, #e9e5e5 0%, rgba(254, 251, 243, 0) 100%),radial-gradient(54% 54% at -5% 6%,#d2d1cf 0%,#ebe9e2 30%,#fdfaf0 42%,rgba(255, 255, 255, 0) 100%),linear-gradient(160deg, #edeae3 0%, #fffdfe 31%, #ffeff7 94%),linear-gradient(180deg, rgba(255, 255, 255, 0.6) 0%, #ffffff 32%);

二、如何实现倒计时效果

首先我们需要一个时间差,并且这个差值根据现在的差值一直在递减
其次我们需要维护一个时间状态,每隔一秒钟就需要更新这个状态从而触发页面的更新
JavaScript
复制代码

useEffect(()=>{let timer = null;// 注意月份是从0开始的,所以4月是3const targetTime = new Date(2024, 3, 20, 20, 0, 0).getTime();timer = setInterval(() => {const currentTime = new Date().getTime();if (new Date(2024, 3, 20, 0, 0, 1).getTime() >= new Date(2024, 3, 20, 0, 0, 0).getTime()) {setShowCount(true);} else {return;}const remainingTime = targetTime - currentTime;if (remainingTime >= 0) {const total = remainingTime / 1000; // 剩余秒数const hh = parseInt(total / (60 * 60)); // 剩余小时const day = parseInt(hh / 24); // 剩余天数const h = hh - parseInt(day * 24);const mm = parseInt((total - hh * 60 * 60) / 60); // 剩余分钟const ss = parseInt(total % 60); // 剩余秒setTime({day,h,m: mm,s: ss,});} else {clearInterval(timer);}}, 1000);return () => {if (timer) clearInterval(timer);};
},[]);
<View className="header">距离直播开始{time.day}天{time.h}小时{time.m.toString().padStart(2, '0')}分钟{time.s.toString().padStart(2, '0')}秒钟
</View>

三、如何实现两个动画丝滑的切换

大概的思路基本上是只针对url的切换,但是只是这样局部更新url 并不会引起容器里动画的更新

const initLottieRef = useRef();// 展示动画的容器
const [url, setUrl] = useState('https://g.alicdn.com/ani-assets/1bb995ac4ad001ab8f091e412dc5e7c0/0.0.1/lottie.json',
);
const curlt = useRef();// 用来接第一个动画实例
useEffect(() => {curlt.current = lottie.loadAnimation({container: initLottieRef.current,renderer: 'svg',loop: true,autoplay: true,path: url, // 替换为你的第一个动画的 JSON 文件路径});
}, [url]);const onClick = () => {// 停止第一个动画并移除其容器curlt.current.stop();// 清空容器以移除第一个动画initLottieRef.current.innerHTML = ''; // 初始化并显示第二个动画setUrl('https://g.alicdn.com/ani-assets/93cbb9eeb82ff32a1fd746bc7a284e04/0.0.1/lottie.json');};

四、弹窗组件如何阻止点击滚动穿透

蒙层级别提高,在容器点击阻止冒泡和默认行为

onClick={(e) => e.stopPropagation()}
onTouchMove={(e) => e.preventDefault()}设置了这个可能回影响本身的滚动
const onAppear = () => {// 防止蒙层滚动穿透document.body.style.overflow = 'hidden';goldlog.realtime('pending-payment-prompt-pop', 'EXP', 'pending-payment-prompt-pop-express');};const onClose = () => {setIsShow(false);document.body.style.overflow = 'auto';};

五、实现淡入淡出

用原生js 动态添加类名的方式试了好久,还是不行
reatc 组件有自己的更新机制,即使添加上了类名但没有遵守react 更新规则并不会触发更新

<div className={`${classlist.join(' ')}`} ></div>
const [classlist, setClasslist] = useState(['container', 'show-pop']);
const onClose = () => {goldlog.realtime('equity-comparison-pop', 'CLK', 'equity-comparison-pop-close');setClasslist(['container', 'hide-pop']);setTimeout(() => {setIsShow(false);document.body.style.overflow = 'auto';setClasslist(['container', 'show-pop']);}, 300);};
.show-pop {animation: show-pop 0.3s ease-in-out forwards;
}
.hide-pop {animation: hide-pop 0.3s ease-in-out forwards;
}@keyframes show-pop {0% {transform: translateY(100%); /* 初始位置:屏幕底部之外 */opacity: 0; /* 初始透明度为0,实现淡入效果 */}100% {transform: translateY(0); /* 结束位置:屏幕顶部 */opacity: 1; /* 结束透明度为1,完全显示 */}
}@keyframes hide-pop {0% {transform: translateY(0); /* 结束位置:屏幕顶部 */opacity: 1; /* 结束透明度为1,完全显示 */}100% {transform: translateY(100%); /* 初始位置:屏幕底部之外 */opacity: 0; /* 初始透明度为0,实现淡入效果 */}
}

六、实现骨架屏

先上关键代码

 background: linear-gradient(90deg,rgba(190, 190, 190, 0.2) 25%,rgba(129, 129, 129, 0.24) 37%,rgba(190, 190, 190, 0.2) 63%);background-size: 400% 100%;animation: skeleton 1.4s ease infinite; @keyframes skeleton {0% {background-position: 0% 0%;}100% {background-position: 100% 0%;}}

为什么这样能实现?
以下是这段代码的工作原理:

背景渐变: background: linear-gradient(90deg, …); 定义了一个从左到右的线性渐变。渐变中有三个颜色停止点:

rgba(190, 190, 190, 0.2) 25%: 在25%的位置,颜色为浅灰色,透明度为20%。
rgba(129, 129, 129, 0.24) 37%: 在37%的位置,颜色为深灰色,透明度为24%。
rgba(190, 190, 190, 0.2) 63%: 在63%的位置,再次变为浅灰色,透明度为20%。 这样的渐变在视觉上产生了一种类似条纹的效果,模拟数据加载时的动态感。
背景尺寸: background-size: 400% 100%; 设置背景的尺寸为元素宽度的400%。这使得背景图像是元素宽度的4倍,为动画提供了足够的空间。

动画: animation: skeleton 1.4s ease infinite; 应用名为skeleton的动画,持续时间为1.4秒,缓动函数为ease(意味着动画开始和结束时速度较慢,中间速度快),并且无限循环。

@keyframes定义了一个动画,从0%到100%的动画过程中,背景的位置从0%平移到100%,即从左到右移动一个完整背景的长度。由于背景尺寸是元素宽度的400%,所以在动画过程中,这个条纹效果会来回移动,模拟数据加载的进度。

这个简单动画组合起来就形成了一个骨架屏效果,给人一种数据正在加载的感觉。当然,真正的骨架屏通常会包含更复杂的形状和元素来匹配页面的实际布局。

七、隐藏滚动条

 <style>{` #scroll-list::-webkit-scrollbar { display: none }`}</style><div className="root" id="scroll-list">

八、实现吸顶效果

使用粘性定位来实现,他的参考点是距离它最近的一个拥有滚动机制的祖先元素,不设置默认就是当前窗口

  position: -webkit-sticky; /* Safari */position: sticky;top: 30px;

九、实现回到顶部,按钮带动画效果

按钮实现从右向左出现,从左向右消失

import React, { useState, useEffect } from 'react';
import './styles.css'; // 引入样式const ScrollToTopButton = () => {const [isVisible, setIsVisible] = useState(false);const [isAnimating, setIsAnimating] = useState(false);const scrollToTop = () => {window.scrollTo({ top: 0, behavior: 'smooth' });};useEffect(() => {const toggleVisibility = () => {if (window.pageYOffset > 300) {setIsVisible(true);setIsAnimating(true);} else {setIsAnimating(false);setTimeout(() => {setIsVisible(false);}, 1000); // 动画持续时间加一点延迟,确保动画完成后再重置}};window.addEventListener('scroll', toggleVisibility);// 清理函数,移除滚动事件监听器return () => window.removeEventListener('scroll', toggleVisibility);}, [])return ({isVisible && <button className={`back-top ${isAnimating ? 'fade-in-right' : 'fade-out-left'}`} onClick={scrollToTop}>top</button>});
};export default ScrollToTopButton;
.fade-in-right {animation: fade-in-right 1s ease-in-out forwards;
}.fade-out-left {animation: fade-out-left 1s ease-in-out forwards;
}@keyframes fade-in-right {0% {transform: translateX(100%);opacity: 0;}100% {transform: translateX(0);opacity: 1;}
}@keyframes fade-out-left {0% {transform: translateX(0);opacity: 1;}100% {transform: translateX(100%);opacity: 0;}
}

十、轮播

滚动的方式:
1 transform
2 scrollto
3 绝对定位移动left
困惑 :滚完就反向弹回了第一个,怎么让他继续滚?
要解决视觉上回弹的问题只需要在滚到最初位置的时候取消过渡效果

javascript">import React, { useEffect, useRef } from 'react';
import './index.css'; // 假设你有一个外部CSS文件来定义样式const Slider = () => {const images = ['1', '2', '3', '4']const currentIndex = useRef(0);const sliderRef = useRef(null);// 自动切换到下一张的逻辑useEffect(() => {const timer = setInterval(() => {const nextIndex = currentIndex.current === images.length - 1 ? 0 : currentIndex.current + 1;const translateX = nextIndex * -100 + '%'; // 假设每张图片占据100%的宽度。sliderRef.current.style.transform = `translateX(${translateX})`;if (translateX === '0%') {sliderRef.current.style.transition = '';//取消过渡视觉上不会出现反向滚动} else {sliderRef.current.style.transition = 'transform 0.5s ease-in-out';}currentIndex.current = nextIndex;}, 2000);// 清理函数,防止内存泄漏return () => {clearInterval(timer);};}, []);return (<div ref={sliderRef} ><div style={{ display: 'flex' }}>{images.map((image, index) => (<div style={{ width: '100%', height: 100, border: '1px solid red', flexShrink: 0, boxSizing: 'border-box' }}>slide {index + 1}</div>))}</div></div>);
};export default function App() {return (<div className="App"><Slider /></div>);
}

十一、下拉刷新

javascript">import React, { useState, useEffect, useRef } from 'react';
import './index.css';let startY;
// 提取防抖函数到组件外
const debounce = (func, wait) => {let timeout;return function (...args) {clearTimeout(timeout);timeout = setTimeout(() => {try {func.apply(this, args);} catch (error) {console.error('Error in debounced function:', error);}}, wait);};
};
const MyComponent = () => {const scrollRef = useRef(null);const [loading, setLoading] = useState(false);const [refresh, setRefresh] = useState(false);const fetachData = () => new Promise(resolve => setTimeout(() => {console.log('数据刷新完成');setLoading(false);resolve();}, 1000));const fetchNewData = debounce(async () => {await fetachData();}, 500); // 防抖延迟时间const onTouchStart = (e) => {startY = e.touches[0].clientY;}const onTouchmove = (e) => {requestAnimationFrame(() => { // 使用 requestAnimationFrame 优化const moveY = e.touches[0].clientY;const diffY = moveY - startY;scrollRef.current.style.transform = `translateY(${diffY > 100 ? 100 : diffY}px)`;if (diffY > 90) {setRefresh(true);// 发起请求if (!loading) {setLoading(true);fetchNewData();}}});};const onTouchend = () => {requestAnimationFrame(() => { // 使用 requestAnimationFrame 优化scrollRef.current.style.transform = `translateY(0)`;scrollRef.current.style.transition = 'transform 0.3s ease';setRefresh(false);setLoading(false);});}useEffect(() => {const element = scrollRef.current;element.addEventListener('touchstart', onTouchStart);element.addEventListener('touchmove', onTouchmove);element.addEventListener('touchend', onTouchend);return () => {element.removeEventListener('touchstart', onTouchStart);element.removeEventListener('touchmove', onTouchmove);element.addEventListener('touchend', onTouchend);};}, []);useEffect(() => {if (refresh && !loading) {setTimeout(() => {scrollRef.current.style.transform = `translateY(0)`;scrollRef.current.style.transition = 'transform 0.3s ease';setRefresh(false);}, 500)}}, [loading]);return (<div ref={scrollRef} >{refresh && <div className='top-container'>{loading ? '数据刷新中...' : '刷新成功了'}</div>}<div className='tabbar'>我是导航栏</div><div className='content'>{Array.from({ length: 10 }, (v, i) => {return <div key={i} className='content-item'>我是内容{i}</div>})}</div></div >);
};export default MyComponent;

http://www.ppmy.cn/ops/32418.html

相关文章

node.js中的fs模块,读写语法讲解

本文分享node.js的入门知识&#xff0c;使用 fs 模块封装的方法读写文件内容 node中的fs 模块&#xff1a;封装了与本机文件系统进行交互的&#xff0c;方法和属性&#xff0c;使用语法如下&#xff1a; 1、加载 fs 模块&#xff0c;得到 fs 对象 const fs require(fs) 2、…

【游戏行业】2024年电子游戏分类,国内游戏产业报告,发展趋势

文章目录 一、电子游戏分类1、传统游戏分类2、混合手游分类3、二次元、开放设计、调查问卷 二、游戏产业报告1、游戏产业数据2、游戏公司名单&#xff08;独角兽&#xff09;3、营收与利润&#xff08;对比互联网、国企&#xff09; 三、发展趋势1、游戏行业上下游2、游戏行业趋…

Rust入门篇:你好,世界

文章目录 前言编写程序编译运行最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;欢迎回来 对于我们大多数人接触一门新的编程语言时&#xff0c;第一个任务一般是编写一个控制台输出hello world的程序 我们这篇博客也是如此&#xff0c;让我们一起使用rust去和世界打个招…

Unity 性能优化之动态批处理(四)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、动态合批是什么&#xff1f;二、使用动态批处理1.打开动态合批2.满足条件 三、检查动态合批是否成功五、动态合批弊端总结 前言 动态批处理是常用优…

mac安装虚拟机linux系统

需要下载的有&#xff1a;centos8镜像 , 虚拟器 VMware 软件包 , Termius 或者xshell 1. CentOS系统下载 linux系统一般有&#xff1a; CentOS、ubuntu、redhat&#xff0c;选择一种进行安装就可以 CentOS 2024 年开始停止维护和发布 CentOS8的下载与安装(windows下安装) 镜…

RabbiMQ(Docker 单机部署)

序言 本文给大家介绍如何使用 Docker 单机部署 RabbitMQ 并与 SpringBoot 整合使用。 一、部署流程 拉取镜像 docker pull rabbitmq:3-management镜像拉取成功之后使用下面命令启动 rabbitmq 容器 docker run \# 指定用户名-e RABBITMQ_DEFAULT_USERusername \# 指定密码-e R…

等级保护小知识

等级保护&#xff08;Grade Protection&#xff09;通常指的是一种信息安全保护机制&#xff0c;它根据信息系统的重要程度和所承担的风险级别&#xff0c;将其划分为不同的安全保护等级&#xff0c;并依据相关标准和法规实施相应的安全保护措施。等级保护的概念在很多国家和地…

通过多组光电判断货物大小以及位置

测试需求 需要判断出货叉上的货物类型&#xff0c;大货和小货。大货居中货叉&#xff0c;小货因为放置位置不同&#xff0c;需要把小货进行偏左或偏右放置。前提条件 1.货叉由变频器驱动&#xff0c;走EPOS定位模式&#xff0c;可以读取位置以及速度。 2. 检测光电有四组&…