用GSAP重新创建滑块并进行反应
我正在尝试使用React和GSAP重新创建此代码epen,我一直在尝试重新创建它几个小时,甚至不知道从哪里开始。我不想在该编码epen中以相同的方式创建各节,而是想从一系列对象中形成细节,这意味着仅创建一个组件就可以使其干燥。我对反应很陌生,我想知道如何从Vanillajs的角度看待这种反应。我已经知道发生了什么事,我也在React中创建了它,但是我想要一种我的代码最小的情况,并且一系列对象形成一个组件,使其更具动态性,以便我可以单击它以获取有关有关的更多信息each section that comes in.
HTML
<div class="slider">
<div class="slider__slide slider__slide--1">
<div class="slider__img slider__img--1"></div>
<div class="slider__text slider__text--1">
<h1 class="slider__header">Rejuvenate your, true self.</h1>
<a href="ign.com" class="cta">discover</a>
</div>
</div>
<div class="slider__slide slider__slide--2">
<div class="slider__img slider__img--2"></div>
<div class="slider__text slider__text--2">
<h1 class="slider__header">Professonial, trust-worthy, and compassionate.</h1>
<a href="google.com" class="cta">learn more</a>
</div>
</div>
<div class="slider__slide slider__slide--3">
<div class="slider__img slider__img--3"></div>
<div class="slider__text slider__text--3">
<h1 class="slider__header">Trust in us.</h1>
<a href="youtube.com" class="cta">learn more</a>
</div>
</div>
<div class="slider__slide slider__slide--4">
<div class="slider__img slider__img--4"></div>
<div class="slider__text slider__text--4">
<h1 class="slider__header">What we do.</h1>
<a href="tsn.ca" class="cta">discover</a>
</div>
</div>
<div class="slider__navigation">
<div class="slider__count slider__count--top">
<p class="count count--top count--top-1">01</p>
<p class="count count--top count--top-2">02</p>
<p class="count count--top count--top-3">03</p>
<p class="count count--top count--top-4">04</p>
</div>
<div class="slider__bar">
<div id="sliderBarDynamic" class="slider__bar--dynamic"></div>
<div class="slider__bar--static"></div>
</div>
<div class="slider__count slider__count--bottom">
<p class="count count--bottom count--bottom-1">02</p>
<p class="count count--bottom count--bottom-2">03</p>
<p class="count count--bottom count--bottom-3">04</p>
<p class="count count--bottom count--bottom-3">01</p>
</div>
</div>
</div>
CSS
@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&family=Roboto&display=swap');
*,
*::before,
*::after{
padding:0;
margin:0;
box-sizing:inherit;
}
html{
font-size:16px;
box-sizing:border-box;
}
body{
font-family: 'Roboto', sans-serif;
color:#444444;
font-weight: 300;
line-height: 1.6;
}
img{
max-width:100%;
}
h1{
font-size: 100px;
color: #fff;
font-family: 'Gilda Display', serif;
font-weight: 300;
line-height: 1;
}
h2{
}
h3{
}
P{
color: #fff;
}
a{
text-decoration:none;
color:#ffffff;
font-size: 24px;
}
ul{
list-style-type:none;
}
// Slider
.slider{
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;
&__slide{
width: 100%;
height: 100%;
display: flex;
position: absolute;
top: 0;
left:0;
&--1{
z-index: 4;
}
&--2{
z-index: 3;
}
&--3{
z-index: 2;
}
&--4{
z-index: 1;
}
}
&__img{
width: 100%;
height: 100%;
position: absolute;
z-index: -1;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
&--1{
background-image: url('https://i.postimg.cc/Y0T3F1tc/about-landing.jpg');
}
&--2{
background-image: url('https://i.postimg.cc/FHHyKWyf/i-Stock-1148043788.jpg');
}
&--3{
background-image: url('https://i.postimg.cc/tTqp06QH/i-Stock-1064136816.jpg');
}
&--4{
background-image: url('https://i.postimg.cc/435R13K2/i-Stock-1179976698.jpg');
}
}
&__text{
align-self: flex-end;
padding: 0 0 5vw 15vh;
opacity: 0;
width: 80%;
max-width: 1005px;
.slider__header{
margin-bottom: 40px;
text-transform: capitalize;
}
.cta{
font-weight: 700;
text-transform: uppercase;
letter-spacing: 6px;
margin-left: 65px;
position: relative;
&:before{
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -55px;
width: 40px;
height: 1px;
background-color: white;
}
}
}
// Slider Navigation
&__navigation{
width: 21px;
height: 400px;
position: fixed;
top: 50%;
transform: translateY(-50%);
left: calc(100% - 5vw);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.count--top{
position: absolute;
top: 0;
left: 0;
// position:
}
.count{
opacity: 0;
}
.count:first-child{
opacity: 1;
}
.count--bottom{
position: absolute;
bottom: 0;
left: 0;
}
&__bar{
width: 2px;
height: 250px;
position: relative;
&--dynamic{
width: 100%;
height: 100%;
background-color: #FF69B4;
transform-origin: top center;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
&--static{
width: 100%;
height: 100%;
background-color: darkgrey;
position: absolute;
top: 0;
left: 0;
}
}
}
// Slider end
Javascript
/*
*/
// timeline to control animations everytime the timeline restarts/repeats
let tlRepeat = gsap.timeline();
// Need first slides elements - img and text to animate on each repeat of timeline
let repeatBeginning = ()=>{
gsap.set(bgImage[0], {opacity: 0, scale: 1.2, webkitFilter:"blur(" + 6 + "px)"})
tlRepeat
.add("slide1-in")
.fromTo([countTop[0], countBottom[0]], {opacity: 0}, {duration: 0.3, opacity: 1, ease: "Power2.easeIn"}, "slide1-in")
.to(bgImage[0], {duration: 1.8, scale: 1, opacity: 1, webkitFilter:"blur(" + 0 + "px)"}, "slide1-in")
.fromTo(text[0], {opacity: 0, x: -30, ease: "Power2.easeIn"}, {duration: 0.8, opacity: 1, x: 0}, "-=1")
}
// On start animations
// let onStartSlide1Animations = ()=>{
// // gsap.to(text[0], {duration: 0.7, opacity: 1, x: -15, ease: "Power2.easeIn"})
// }
// Variables
let slides = document.querySelectorAll('.slider__slide'),
dynamicBar = document.querySelector('#sliderBarDynamic'),
countTop = document.querySelectorAll(".count--top"),
countBottom = document.querySelectorAll(".count--bottom"),
bgImage = document.querySelectorAll(".slider__img"),
text = document.querySelectorAll(".slider__text"),
tl = gsap.timeline({repeat: 0, delay: 1, paused: false, onRepeat: repeatBeginning});
// Push all text back and only make first one visible
gsap.set(text, {x: -30});
gsap.set(text[0], {opacity: 1});
// Animate slide's elements but not the first one.
// Make first slide's elements animate when timeline is repeating,
// Follow the flow of rest of the slide's animations
slides.forEach((slide, i) =>{
tl
.fromTo(dynamicBar, {scaleY: 0}, {duration: 1.4, scaleY: 1}, "+=2")
.set(dynamicBar, {transformOrigin: "bottom center"})
.to(dynamicBar, {duration: 1, scaleY: 0}, "+=0.4")
.set(dynamicBar, {transformOrigin: "top center"})
.add("elements-in-out")
.to([countTop[i], countBottom[i]], {opacity: 0}, "elements-in-out")
.to([countTop[i+1], countBottom[i+1]], {opacity: 1}, "elements-in-out")
.to(bgImage[i], {duration: 0.2, opacity: 0}, "elements-in-out")
.set(bgImage[i+1], {scale: 1.2, webkitFilter:"blur(" + 6 + "px)"}, "elements-in-out")
.to(bgImage[i+1], {duration: 1.8, scale: 1, webkitFilter:"blur(" + 0 + "px)"}, "elements-in-out")
.to(text[i], {duration: 0.3, opacity: 0}, "elements-in-out")
.to(text[i+1], {duration: 0.8, opacity: 1, x: 0}, "-=1")
})
I am trying to recreate this codepen with react and gsap on here and i have been trying to recreate this for some hours now and do not even know where to start from. i do not want to create the sections the same way in that codepen but rather form the details from an array of objects meaning creating just once component making it DRY. i am fairly new to react and i would like know how to do something like that in react, looking at it from vanillajs perspective. i already know what is going on and i also created it like this in react but i want a situation where i have minimal code and the an array of objects forms one component making it more dynamic so i can click on it to get more information about each section that comes in.
HTML
<div class="slider">
<div class="slider__slide slider__slide--1">
<div class="slider__img slider__img--1"></div>
<div class="slider__text slider__text--1">
<h1 class="slider__header">Rejuvenate your, true self.</h1>
<a href="ign.com" class="cta">discover</a>
</div>
</div>
<div class="slider__slide slider__slide--2">
<div class="slider__img slider__img--2"></div>
<div class="slider__text slider__text--2">
<h1 class="slider__header">Professonial, trust-worthy, and compassionate.</h1>
<a href="google.com" class="cta">learn more</a>
</div>
</div>
<div class="slider__slide slider__slide--3">
<div class="slider__img slider__img--3"></div>
<div class="slider__text slider__text--3">
<h1 class="slider__header">Trust in us.</h1>
<a href="youtube.com" class="cta">learn more</a>
</div>
</div>
<div class="slider__slide slider__slide--4">
<div class="slider__img slider__img--4"></div>
<div class="slider__text slider__text--4">
<h1 class="slider__header">What we do.</h1>
<a href="tsn.ca" class="cta">discover</a>
</div>
</div>
<div class="slider__navigation">
<div class="slider__count slider__count--top">
<p class="count count--top count--top-1">01</p>
<p class="count count--top count--top-2">02</p>
<p class="count count--top count--top-3">03</p>
<p class="count count--top count--top-4">04</p>
</div>
<div class="slider__bar">
<div id="sliderBarDynamic" class="slider__bar--dynamic"></div>
<div class="slider__bar--static"></div>
</div>
<div class="slider__count slider__count--bottom">
<p class="count count--bottom count--bottom-1">02</p>
<p class="count count--bottom count--bottom-2">03</p>
<p class="count count--bottom count--bottom-3">04</p>
<p class="count count--bottom count--bottom-3">01</p>
</div>
</div>
</div>
CSS
@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&family=Roboto&display=swap');
*,
*::before,
*::after{
padding:0;
margin:0;
box-sizing:inherit;
}
html{
font-size:16px;
box-sizing:border-box;
}
body{
font-family: 'Roboto', sans-serif;
color:#444444;
font-weight: 300;
line-height: 1.6;
}
img{
max-width:100%;
}
h1{
font-size: 100px;
color: #fff;
font-family: 'Gilda Display', serif;
font-weight: 300;
line-height: 1;
}
h2{
}
h3{
}
P{
color: #fff;
}
a{
text-decoration:none;
color:#ffffff;
font-size: 24px;
}
ul{
list-style-type:none;
}
// Slider
.slider{
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;
&__slide{
width: 100%;
height: 100%;
display: flex;
position: absolute;
top: 0;
left:0;
&--1{
z-index: 4;
}
&--2{
z-index: 3;
}
&--3{
z-index: 2;
}
&--4{
z-index: 1;
}
}
&__img{
width: 100%;
height: 100%;
position: absolute;
z-index: -1;
background-size: cover;
background-repeat: no-repeat;
background-position: 50% 50%;
&--1{
background-image: url('https://i.postimg.cc/Y0T3F1tc/about-landing.jpg');
}
&--2{
background-image: url('https://i.postimg.cc/FHHyKWyf/i-Stock-1148043788.jpg');
}
&--3{
background-image: url('https://i.postimg.cc/tTqp06QH/i-Stock-1064136816.jpg');
}
&--4{
background-image: url('https://i.postimg.cc/435R13K2/i-Stock-1179976698.jpg');
}
}
&__text{
align-self: flex-end;
padding: 0 0 5vw 15vh;
opacity: 0;
width: 80%;
max-width: 1005px;
.slider__header{
margin-bottom: 40px;
text-transform: capitalize;
}
.cta{
font-weight: 700;
text-transform: uppercase;
letter-spacing: 6px;
margin-left: 65px;
position: relative;
&:before{
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -55px;
width: 40px;
height: 1px;
background-color: white;
}
}
}
// Slider Navigation
&__navigation{
width: 21px;
height: 400px;
position: fixed;
top: 50%;
transform: translateY(-50%);
left: calc(100% - 5vw);
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
.count--top{
position: absolute;
top: 0;
left: 0;
// position:
}
.count{
opacity: 0;
}
.count:first-child{
opacity: 1;
}
.count--bottom{
position: absolute;
bottom: 0;
left: 0;
}
&__bar{
width: 2px;
height: 250px;
position: relative;
&--dynamic{
width: 100%;
height: 100%;
background-color: #FF69B4;
transform-origin: top center;
position: absolute;
top: 0;
left: 0;
z-index: 2;
}
&--static{
width: 100%;
height: 100%;
background-color: darkgrey;
position: absolute;
top: 0;
left: 0;
}
}
}
// Slider end
Javascript
/*
*/
// timeline to control animations everytime the timeline restarts/repeats
let tlRepeat = gsap.timeline();
// Need first slides elements - img and text to animate on each repeat of timeline
let repeatBeginning = ()=>{
gsap.set(bgImage[0], {opacity: 0, scale: 1.2, webkitFilter:"blur(" + 6 + "px)"})
tlRepeat
.add("slide1-in")
.fromTo([countTop[0], countBottom[0]], {opacity: 0}, {duration: 0.3, opacity: 1, ease: "Power2.easeIn"}, "slide1-in")
.to(bgImage[0], {duration: 1.8, scale: 1, opacity: 1, webkitFilter:"blur(" + 0 + "px)"}, "slide1-in")
.fromTo(text[0], {opacity: 0, x: -30, ease: "Power2.easeIn"}, {duration: 0.8, opacity: 1, x: 0}, "-=1")
}
// On start animations
// let onStartSlide1Animations = ()=>{
// // gsap.to(text[0], {duration: 0.7, opacity: 1, x: -15, ease: "Power2.easeIn"})
// }
// Variables
let slides = document.querySelectorAll('.slider__slide'),
dynamicBar = document.querySelector('#sliderBarDynamic'),
countTop = document.querySelectorAll(".count--top"),
countBottom = document.querySelectorAll(".count--bottom"),
bgImage = document.querySelectorAll(".slider__img"),
text = document.querySelectorAll(".slider__text"),
tl = gsap.timeline({repeat: 0, delay: 1, paused: false, onRepeat: repeatBeginning});
// Push all text back and only make first one visible
gsap.set(text, {x: -30});
gsap.set(text[0], {opacity: 1});
// Animate slide's elements but not the first one.
// Make first slide's elements animate when timeline is repeating,
// Follow the flow of rest of the slide's animations
slides.forEach((slide, i) =>{
tl
.fromTo(dynamicBar, {scaleY: 0}, {duration: 1.4, scaleY: 1}, "+=2")
.set(dynamicBar, {transformOrigin: "bottom center"})
.to(dynamicBar, {duration: 1, scaleY: 0}, "+=0.4")
.set(dynamicBar, {transformOrigin: "top center"})
.add("elements-in-out")
.to([countTop[i], countBottom[i]], {opacity: 0}, "elements-in-out")
.to([countTop[i+1], countBottom[i+1]], {opacity: 1}, "elements-in-out")
.to(bgImage[i], {duration: 0.2, opacity: 0}, "elements-in-out")
.set(bgImage[i+1], {scale: 1.2, webkitFilter:"blur(" + 6 + "px)"}, "elements-in-out")
.to(bgImage[i+1], {duration: 1.8, scale: 1, webkitFilter:"blur(" + 0 + "px)"}, "elements-in-out")
.to(text[i], {duration: 0.3, opacity: 0}, "elements-in-out")
.to(text[i+1], {duration: 0.8, opacity: 1, x: 0}, "-=1")
})
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因此,首先,为了在ReactJ中重新想象任何HTML摘要,请尝试在片段中查找smilarities / Repetation。一旦这样做,您就可以将要分开的要点分开为单独的组成部分,以及它们如何将它们联系在一起。
现在,仅通过查看HTML片段,我们就可以看到幻灯片正在重复,因此可以将其保存为单独的组件。我们还看到,每个幻灯片都显示一个唯一的标题和段落文本,并且具有配色方案。因此,为了使我们的
幻灯片
组件动态,我们可以将它们作为支架传递给组件。因此,我们的
数据
创建整个slider
component(由slide
's组成)看起来像这样:接下来,我们注意到,某些UI是使用CSS创建的,此主要是导致整个片段是静态的。因此,为了实现动态性,我们根据所获得的数据在组件中使用了一些样式。这样:
此外,每个幻灯片都被分配了一个静态类,例如
box1,box2 ... etc
。因此,这些样式需要为每个幻灯片渲染:(请注意,上面的摘要中的对象
data
对应于我们的数组中的对象sliderdata
,可以使整个塑造整个变形滑块组件)。一旦准备好了UI,引入GSAP动画就很简单了。首先,我们为GSAP在动画过程中使用的UI元素创建了
refs
。接下来,我们触发了动画,就像您在Plain JavaScript中的方式一样。这里唯一的区别是,我们在加载功能组件(空依赖量阵列)后在
usefect
挂钩中执行它们。此外,还有一些硬编码的东西使五个幻灯片动画。我们通过引入
LET Ratio = 100 / SliderData.length < / code>
整个组件:
stylenew.css:
So first off, in order to re-imagine any html snippet in terms of ReactJS, try and look for smilarities / repetation with in the snippet. Once you do that you would kind of get the gist of what can be seperated out as individual components and how it all ties together.
Now, just by looking at the html snippet, we can see that the slides are repeating, thus they can be kept as a seperate component. We also see that each slide displays a unique heading and paragraph text and also has a color scheme. So in order to make our
Slide
component dynamic, we can pass these as props to the component.So our
data
that creates the wholeSlider
component (composed ofSlide
's) looks something like this:Next we notice, some of the UI was created using CSS, and this mainly caused the whole snippet to be static. So in order to achieve dynamicity we rendered some styles with in the component(s) based on the data we are getting. Like this:
Moreover, each slide was assigned a static class like
box1, box2... etc
. Therefore these styles need to be rendered for each slide like this:(Notice that the object
data
in the above snippet corresponds to the object in our arraysliderData
that shapes up the whole slider component).Once we have our UI ready, introducing GSAP animations was simple. First we created
refs
to the UI elements that were being used by GSAP in the animation process.Next up, we triggered the animations just like how you would in plain javascript. The only difference here is that we executed them in the
useEffect
hook that runs once the functional component is loaded (empty dependancy array).Moreover there were a few hard-coded stuff that animated just the five slides. Which we made dynamic by introducing
let ratio = 100 / sliderData.length
The whole component:
The styleNew.css: