古卷轴展开动画本文主要介绍了古卷轴展开动画的实现,包括 jquery 版本和 react 版本,还实现了从中间展开的动画
本文主要介绍了古卷轴展开动画的实现,包括 jquery 版本和 react 版本,还实现了从中间展开的动画效果和从右向左展开的动画效果。
jquery 版本
在网上找了一个 jquery 版本的实现,具体 demo 可以查看下列网址:古卷轴平滑打开 jQuery 动画特效
动画实现代码如下所示,直接从 demo 中复制过来,直接使用即可。
$(document).ready(function () {
//卷轴展开动画效果
$(".l-pic-index").animate({ left: "95px", top: "-4px" }, 1300);
$(".r-pic-index").animate({ right: "-23px", top: "-5px" }, 1450);
$(".l-bg-index").animate({ width: "433px", left: "73px" }, 1500);
$(".r-bg-index").animate(
{ width: "433px", right: "-38px" },
1500,
function () {
$(".main-index").fadeIn(800);
}
);
});
react 版本
上述是用 jquery 实现的版本,但是一般现在开发都用 vue 和 react 框架了,不使用 jquery 了。
我的项目是使用 react 开发的,因此使用 react 重构一下,在 react 项目中实现该功能,整体而言,调整的东西也不多。
1. 初始状态:两个卷轴
固定初始状态的位置:只显示两个卷轴,画卷和内容部分不显示
// reel.tsx组件
function Page() {
return (
<div className="reel_content">
<div className="l-pic-index"></div>
<div className="r-pic-index"></div>
<div className="l-bg-index"></div>
<div className="r-bg-index"></div>
<div className="main-index">
<p className="intro-text">xxx</p>
</div>
</div>
);
}
export default Page;
// reel组件样式
.reel_content {
position: relative;
z-index: 99;
width: 900px;
height: 460px;
padding: 40px 0;
background-color: #6f0b02;
box-sizing: border-box;
.l-pic-index {
position: absolute;
left: 400px;
top: 1px;
z-index: 2;
width: 50px;
height: 460px;
background: url("../img/j1.png") no-repeat right 0;
}
.r-pic-index {
position: absolute;
right: 400px;
top: 0;
z-index: 2;
width: 50px;
height: 460px;
background: url("../img/j4.png") no-repeat left 0;
}
.l-bg-index {
position: absolute;
top: -3px;
left: 430px;
z-index: 1;
width: 25px;
height: 459px;
background: url("../img/j2.png") right 0 no-repeat;
}
.r-bg-index {
position: absolute;
top: -4px;
right: 430px;
z-index: 1;
width: 25px;
height: 459px;
background: url("../img/j3.png") 0 0 no-repeat;
}
.main-index {
display: none;
overflow: hidden;
zoom: 1;
position: absolute;
z-index: 5;
width: 530px;
height: 280px;
left: 145px;
top: 90px;
color: #2e2e2e;
}
}
初始状态效果如下所示:
2. 结束状态:全部展开
固定所有内容的位置,显示卷轴中部和内容部分
.reel_content_finish {
.l-pic-index {
left: 95px !important;
top: -4px !important;
}
.r-pic-index {
right: -23px !important;
top: -5px !important;
}
.l-bg-index {
width: 433px !important;
left: 73px !important;
}
.r-bg-index {
width: 433px !important;
right: -38px !important;
}
.main-index {
display: block !important;
}
}
结束状态效果如下所示:
3. 卷轴展开:中间展开
将 jquery 版本的动画效果代码,转换一下为 react 的,如下所示:
function Page() {
// 控制是否正在动画
const [isAnimating, setIsAnimating] = useState(false);
// 控制主内容区域的样式
const [mainIndexStyle, setMainIndexStyle] = useState({ display: "none" });
// 控制左侧卷轴图片的样式
const [lPicIndexStyle, setLPicIndexStyle] = useState({});
// 控制右侧卷轴图片的样式
const [rPicIndexStyle, setRPicIndexStyle] = useState({});
// 控制左侧背景的样式
const [lBgIndexStyle, setLBgIndexStyle] = useState({});
// 控制右侧背景的样式
const [rBgIndexStyle, setRBgIndexStyle] = useState({});
// 控制主内容区域是否可见
const [mainIndexVisible, setMainIndexVisible] = useState(false);
useEffect(() => {
// 设置定时器,3秒触发一次动画
const intervalId = setInterval(() => {
setIsAnimating(true);
}, 3000);
return () => clearInterval(intervalId); // 清除定时器
}, []);
useEffect(() => {
// 当 isAnimating 改变时触发动画
if (isAnimating) {
animateElements();
}
}, [isAnimating]);
useEffect(() => {
// 当 mainIndexVisible 改变时设置主内容区域的样式
if (mainIndexVisible) {
setTimeout(() => {
setMainIndexStyle({ display: "block" });
}, 800);
}
}, [mainIndexVisible]);
// 动画执行函数
const animateElements = () => {
const lPicIndexStyle = {
left: "95px",
top: "-4px",
transition: "left 1300ms, top 1300ms",
};
const rPicIndexStyle = {
right: "-23px",
top: "-5px",
transition: "right 1450ms, top 1450ms",
};
const lBgIndexStyle = {
width: "433px",
left: "73px",
transition: "width 1500ms, left 1500ms",
};
const rBgIndexStyle = {
width: "433px",
right: "-38px",
transition: "width 1500ms, right 1500ms",
};
// 延迟1500毫秒后设置主内容区域为可见
setTimeout(() => {
setMainIndexVisible(true);
// 再延迟3000毫秒后重置动画
setTimeout(() => {
resetAnimations();
}, 3000);
}, 1500);
// 设置各个元素的样式
setLPicIndexStyle(lPicIndexStyle);
setRPicIndexStyle(rPicIndexStyle);
setLBgIndexStyle(lBgIndexStyle);
setRBgIndexStyle(rBgIndexStyle);
};
// 重置动画
const resetAnimations = () => {
setMainIndexVisible(false);
setMainIndexStyle({ display: "none" });
setLPicIndexStyle({});
setRPicIndexStyle({});
setLBgIndexStyle({});
setRBgIndexStyle({});
setIsAnimating(false);
};
return (
<div className="reel_content">
<div className="l-pic-index" style={{ ...lPicIndexStyle }}></div>
<div className="r-pic-index" style={{ ...rPicIndexStyle }}></div>
<div className="l-bg-index" style={{ ...lBgIndexStyle }}></div>
<div className="r-bg-index" style={{ ...rBgIndexStyle }}></div>
<div className="main-index" style={{ ...mainIndexStyle }}>
<p className="intro-text">xxx</p>
</div>
</div>
);
}
export default memo(Page);
我的版本(右向左展开)
上述实现的实现的版本是:从中间向两边展开的。不满足项目需求,所以需要修改。
而且上述的实现代码太复杂、太繁琐了,需要简化一下,直接使用 CSS3 动画就行了。
我的项目需求为:卷轴滚动时,从右向左打开,并且同步出现诗句
前提条件:将图片 j2.png 和 j3.png 合并成一张完整的图片
精简的代码,如下所示:
function Page() {
// 控制是否正在动画
const [isAnimating, setIsAnimating] = useState(false);
// 控制类名
const [reelClass, setReelClass] = useState("reel_wrap");
useEffect(() => {
const intervalId = setTimeout(() => {
setIsAnimating(true);
}, 3000);
return () => clearTimeout(intervalId); // 清除定时器
}, []);
useEffect(() => {
// 当 isAnimating 改变时设置类名
if (isAnimating) {
setReelClass("reel_wrap reel_wrap_finish");
// // 等待动画结束后重置状态
// setTimeout(() => {
// setIsAnimating(false);
// setReelClass("reel_wrap"); // 重置类名
// }, 3000);
}
}, [isAnimating]);
return (
<div className={reelClass}>
<div className="reel_l"></div>
<div className="reel_r"></div>
<div className="reel_bg"></div>
</div>
);
}
export default memo(Page);
样式实现:
$reelWidth: 48px; // 画轴宽度
$reelHeight: 384px; // 画轴高度
$reelBgWidth: 864px; // 画卷宽度
$time: 3000ms;
.reel_wrap {
position: absolute;
z-index: 99;
width: $reelWidth * 2 + $reelBgWidth;
height: $reelHeight;
background-color: #6f0b02;
box-sizing: border-box;
overflow: hidden;
&_finish {
// 结束状态
.reel_l {
left: 0 !important;
transition: left $time ease-in-out;
}
.reel_bg {
width: $reelBgWidth !important;
left: $reelWidth !important;
transition: width $time ease-in-out, left $time ease-in-out;
}
}
.reel_l {
position: absolute;
z-index: 2;
left: $reelBgWidth;
width: $reelWidth;
height: $reelHeight;
background: url("../img/j1.png") 0 0 / 100% 100% no-repeat;
}
.reel_r {
position: absolute;
z-index: 2;
right: 0;
width: $reelWidth;
height: $reelHeight;
background: url("../img/j4.png") 0 0 / 100% 100% no-repeat;
}
.reel_bg {
position: absolute;
z-index: 11;
left: $reelWidth + $reelBgWidth;
width: 0;
height: $reelHeight;
background: url("../img/j5.png") right 0 no-repeat; // 实现从右向左动画
}
}
其他系列文章:
转载自:https://juejin.cn/post/7411043646132109364