来自对象数组的部分

Sections from an array of objects

我正在尝试在此处使用 React 和 gsap 重新创建此代码笔,我已经尝试重新创建它大约一个小时了,甚至不知道从哪里开始,请谁能提供帮助。我不想在那个代码笔中以相同的方式创建这些部分,而是从一组对象中形成细节,这意味着只创建一次组件,我对反应还很陌生,我想知道如何在反应中做类似的事情,从 vanillajs 的角度来看,我已经知道发生了什么,我也在 React 中创建了它,但我想要一种情况,我的代码最少,并且对象数组形成一个组件,使其更具动态性,因此我可以单击在上面获取有关每个部分的更多信息。请协助 下面的 Codepen link https://codepen.io/designsbyharp/pen/jObpWZg

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

/*
*/

// 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")
})









如果我对你的问题的理解正确,你需要更 DRY 的实现,这样幻灯片就不会在 HTML/JSX 中明确写出。

将每张幻灯片之间不同的值(即标题和图像源)收集到一个数组中,该数组可以映射到 return。

示例:

const slides = [
  {
    id: 0,
    heading: "SCROLL",
    image: {
      src:
        "https://images.unsplash.com/photo-1567016376408-0226e4d0c1ea?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMyMDUzOA&ixlib=rb-1.2.1&q=80&w=400",
      alt: ""
    },
    overlay: {
      src:
        "https://images.unsplash.com/photo-1519710164239-da123dc03ef4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMxOTU4Mw&ixlib=rb-1.2.1&q=80&w=800",
      alt: ""
    }
  },
  {
    id: 1,
    heading: "SWIPE",
    image: {
      src:
        "https://images.unsplash.com/photo-1558603668-6570496b66f8?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMyMDUzOA&ixlib=rb-1.2.1&q=85&w=400",
      alt: ""
    },
    overlay: {
      src:
        "https://images.unsplash.com/photo-1594666757003-3ee20de41568?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMxOTcwOA&ixlib=rb-1.2.1&q=80&w=800",
      alt: ""
    }
  },
  {
    id: 2,
    heading: "SCROLL",
    image: {
      src:
        "https://images.unsplash.com/photo-1537165924986-cc3568f5d454?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMyMDU4NA&ixlib=rb-1.2.1&q=85&w=400",
      alt: ""
    },
    overlay: {
      src:
        "https://images.unsplash.com/photo-1579830341096-05f2f31b8259?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMxOTQ5Ng&ixlib=rb-1.2.1&q=80&w=800",
      alt: ""
    }
  },
  {
    id: 3,
    heading: "SWIPE",
    image: {
      src:
        "https://images.unsplash.com/photo-1589271243958-d61e12b61b97?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMyMDU4NA&ixlib=rb-1.2.1&q=80&w=400",
      alt: ""
    },
    overlay: {
      src:
        "https://images.unsplash.com/photo-1603771628302-c32c88e568e3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0NjMxOTUxNg&ixlib=rb-1.2.1&q=80&w=800",
      alt: ""
    }
  }
];

替换用于映射此 slides 数组的重复 JSX。

{slides.map((slide) => (
  <section key={slide.id} class="slide">
    <div class="slide__outer">
      <div class="slide__inner">
        <div class="slide__content">
          <div class="slide__container">
            <h2 class="slide__heading">{slide.heading}</h2>
            <figure class="slide__img-cont">
              <img
                class="slide__img"
                alt={slide.image.alt}
                src={slide.image.src}
              />
            </figure>
          </div>
        </div>
      </div>
    </div>
  </section>
))}

<section class="overlay">
  <div class="overlay__content">
    <p class="overlay__count">
      0<span className="count">1</span>
    </p>
    <figure class="overlay__img-cont">
      {slides.map((slide) => (
        <img
          key={slide.id}
          class="image"
          src={slide.overlay.src}
          alt={slide.overlay.alt}
        />
      ))}
    </figure>
  </div>
</section>