滚动鼠标时动画TweenMax幻灯片

时间:2018-11-08 05:42:47

标签: javascript css3 three.js html5-canvas tweenmax

基本上遵循基于 ES6 TweenMax 的代码,它可以正常工作,但是我想修复滚动事件,例如当鼠标向上滚动滑块从底部动画(更改)时上下滚动鼠标,使滑块从上到下动画。

我也想基于右中心导航更改点击时的滑块!

感谢进阶!

class Slider {
  constructor() {
    this.bindAll();

    this.el = document.querySelector(".js-slider");
    this.inner = this.el.querySelector(".js-slider__inner");
    this.slides = [...this.el.querySelectorAll(".js-slide")];
    this.bullets = [...this.el.querySelectorAll(".js-slider-bullet")];

    this.renderer = null;
    this.scene = null;
    this.clock = null;
    this.camera = null;

    this.images = [
      "https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg1.jpg",
      "https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg2.jpg",
      "https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg3.jpg"
    ];

    this.data = {
      current: 0,
      next: 1,
      total: this.images.length - 1,
      delta: 0
    };

    this.state = {
      animating: false,
      text: false,
      initial: true
    };

    this.textures = null;
    this.init();
  }

  bindAll() {
    ["render", "nextSlide"].forEach(fn => (this[fn] = this[fn].bind(this)));
  }

  setStyles() {
    this.slides.forEach((slide, index) => {
      if (index === 0) return;

      TweenMax.set(slide, {
        autoAlpha: 0
      });
    });

    this.bullets.forEach((bullet, index) => {
      if (index === 0) return;

      const txt = bullet.querySelector(".js-slider-bullet__text");
      const line = bullet.querySelector(".js-slider-bullet__line");

      TweenMax.set(txt, {
        alpha: 0.25
      });
      TweenMax.set(line, {
        scaleX: 0,
        transformOrigin: "left"
      });
    });
  }

  cameraSetup() {
    this.camera = new THREE.OrthographicCamera(
      this.el.offsetWidth / -2,
      this.el.offsetWidth / 2,
      this.el.offsetHeight / 2,
      this.el.offsetHeight / -2,
      1,
      1000
    );

    this.camera.lookAt(this.scene.position);
    this.camera.position.z = 1;
  }

  setup() {
    this.scene = new THREE.Scene();
    this.clock = new THREE.Clock(true);

    this.renderer = new THREE.WebGLRenderer({
      alpha: true
    });
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(this.el.offsetWidth, this.el.offsetHeight);

    this.inner.appendChild(this.renderer.domElement);
  }

  loadTextures() {
    const loader = new THREE.TextureLoader();
    loader.crossOrigin = "";

    this.textures = [];
    this.images.forEach(image => {
      const texture = loader.load(image + "?v=" + Date.now(), this.render);
      texture.minFilter = THREE.LinearFilter;
      this.textures.push(texture);
    });

    this.disp = loader.load(
      "https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/rock-_disp.png",
      this.render
    );
    this.disp.magFilter = this.disp.minFilter = THREE.LinearFilter;
    this.disp.wrapS = this.disp.wrapT = THREE.RepeatWrapping;
  }

  createMesh() {
    this.mat = new THREE.ShaderMaterial({
      uniforms: {
        dispPower: {
          type: "f",
          value: 0.0
        },
        intensity: {
          type: "f",
          value: 0.5
        },
        texture1: {
          type: "t",
          value: this.textures[0]
        },
        texture2: {
          type: "t",
          value: this.textures[1]
        },
        disp: {
          type: "t",
          value: this.disp
        }
      },
      transparent: true,
      vertexShader: document.querySelector("#vertexShader").textContent,
      fragmentShader: document.querySelector("#fragmentShader").textContent
    });

    const geometry = new THREE.PlaneBufferGeometry(
      this.el.offsetWidth,
      this.el.offsetHeight,
      1
    );

    const mesh = new THREE.Mesh(geometry, this.mat);

    this.scene.add(mesh);
  }

  transitionNext() {
    TweenMax.to(this.mat.uniforms.dispPower, 2.5, {
      value: 1,
      ease: Expo.easeInOut,
      onUpdate: this.render,
      onComplete: () => {
        this.mat.uniforms.dispPower.value = 0.0;
        this.changeTexture();
        this.render.bind(this);
        this.state.animating = false;
      }
    });

    const current = this.slides[this.data.current];
    const next = this.slides[this.data.next];

    const currentImages = current.querySelectorAll(".js-slide__img");
    const nextImages = next.querySelectorAll(".js-slide__img");

    const currentText = current.querySelectorAll(".js-slider__text-line div");
    const nextText = next.querySelectorAll(".js-slider__text-line div");

    const currentBullet = this.bullets[this.data.current];
    const nextBullet = this.bullets[this.data.next];

    const currentBulletTxt = currentBullet.querySelectorAll(
      ".js-slider-bullet__text"
    );
    const nextBulletTxt = nextBullet.querySelectorAll(
      ".js-slider-bullet__text"
    );

    const currentBulletLine = currentBullet.querySelectorAll(
      ".js-slider-bullet__line"
    );
    const nextBulletLine = nextBullet.querySelectorAll(
      ".js-slider-bullet__line"
    );

    const tl = new TimelineMax({
      paused: true
    });

    if (this.state.initial) {
      TweenMax.to(".js-scroll", 1.5, {
        yPercent: 100,
        alpha: 0,
        ease: Power4.easeInOut
      });

      this.state.initial = false;
    }

    tl
      .staggerFromTo(
        currentImages,
        1.5, {
          yPercent: 0,
          scale: 1
        }, {
          yPercent: -185,
          scaleY: 1.5,
          ease: Expo.easeInOut
        },
        0.075
      )
      .to(
        currentBulletTxt,
        1.5, {
          alpha: 0.25,
          ease: Linear.easeNone
        },
        0
      )
      .set(
        currentBulletLine, {
          transformOrigin: "right"
        },
        0
      )
      .to(
        currentBulletLine,
        1.5, {
          scaleX: 0,
          ease: Expo.easeInOut
        },
        0
      );

    if (currentText) {
      tl.fromTo(
        currentText,
        2, {
          yPercent: 0
        }, {
          yPercent: -100,
          ease: Power4.easeInOut
        },
        0
      );
    }

    tl
      .set(current, {
        autoAlpha: 0
      })
      .set(
        next, {
          autoAlpha: 1
        },
        1
      );

    if (nextText) {
      tl.fromTo(
        nextText,
        2, {
          yPercent: 100
        }, {
          yPercent: 0,
          ease: Power4.easeOut
        },
        1.5
      );
    }

    tl
      .staggerFromTo(
        nextImages,
        1.5, {
          yPercent: 150,
          scaleY: 1.5
        }, {
          yPercent: 0,
          scaleY: 1,
          ease: Expo.easeInOut
        },
        0.075,
        1
      )
      .to(
        nextBulletTxt,
        1.5, {
          alpha: 1,
          ease: Linear.easeNone
        },
        1
      )
      .set(
        nextBulletLine, {
          transformOrigin: "left"
        },
        1
      )
      .to(
        nextBulletLine,
        1.5, {
          scaleX: 1,
          ease: Expo.easeInOut
        },
        1
      );

    tl.play();
  }

  prevSlide() {}

  nextSlide() {
    if (this.state.animating) return;

    this.state.animating = true;

    this.transitionNext();

    this.data.current =
      this.data.current === this.data.total ? 0 : this.data.current + 1;
    this.data.next =
      this.data.current === this.data.total ? 0 : this.data.current + 1;
  }

  changeTexture() {
    this.mat.uniforms.texture1.value = this.textures[this.data.current];
    this.mat.uniforms.texture2.value = this.textures[this.data.next];
  }

  listeners() {
    window.addEventListener("wheel", this.nextSlide, {
      passive: true
    });
  }

  render() {
    this.renderer.render(this.scene, this.camera);
  }

  init() {
    this.setup();
    this.cameraSetup();
    this.loadTextures();
    this.createMesh();
    this.setStyles();
    this.render();
    this.listeners();
  }
}

// Toggle active link
const links = document.querySelectorAll(".js-nav a");

links.forEach(link => {
  link.addEventListener("click", e => {
    e.preventDefault();
    links.forEach(other => other.classList.remove("is-active"));
    link.classList.add("is-active");
  });
});

// Init classes
const slider = new Slider();
@font-face {
  font-family: 'font';
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/OakesGrotesk-Semi-Bold.woff2") format("woff2");
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/OakesGrotesk-Semi-Bold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
}

@font-face {
  font-family: 'font-2';
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/MaisonNeue-Book.woff2") format("woff2");
  src: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/MaisonNeue-Book.woff") format("woff");
  font-weight: normal;
  font-style: normal;
}

html {
  font-size: 16px;
}

html,
body {
  height: 100%;
}

body {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #111;
  font-family: 'font';
  overflow: hidden;
}

a {
  color: #fff;
  text-decoration: none;
}

.scroll {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  color: rgba(255, 255, 255, 0.5);
  font-family: 'font-2';
  font-size: calc(0.5rem + 0.35vw);
  z-index: 10;
}

.logo {
  position: absolute;
  top: 2rem;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  padding: 0;
  margin: 0;
  z-index: 10;
}

.logo img {
  display: block;
  height: 1rem;
  width: auto;
}

ul,
li {
  list-style: none;
  padding: 0;
  margin: 0;
}

.nav {
  position: absolute;
  top: 2rem;
  z-index: 10;
}

.nav--left {
  left: 1rem;
}

.nav--right {
  right: 1rem;
}

.nav ul {
  display: flex;
  align-items: center;
  height: 1rem;
}

.nav li {
  display: block;
  margin: 0 1rem;
  padding: 0;
}

.nav a {
  position: relative;
  display: flex;
  align-items: center;
  font-size: calc(0.5rem + 0.35vw);
  font-family: 'font-2';
}

.nav a span {
  position: relative;
}

.nav a span:before {
  content: '';
  position: absolute;
  left: 0;
  bottom: -0.35rem;
  width: 100%;
  height: 1px;
  background-color: rgba(255, 255, 255, 0.25);
  transition: -webkit-transform .75s ease;
  transition: transform .75s ease;
  transition: transform .75s ease, -webkit-transform .75s ease;
  -webkit-transform-origin: right;
  transform-origin: right;
  -webkit-transform: scaleX(0);
  transform: scaleX(0);
}

.nav a:hover span:before,
.nav a.is-active span:before {
  -webkit-transform: scaleX(1);
  transform: scaleX(1);
  -webkit-transform-origin: left;
  transform-origin: left;
}

.vert-text {
  position: absolute;
  bottom: 2rem;
  right: 2rem;
  width: 15rem;
  display: flex;
  align-items: center;
  z-index: 10;
}

.vert-text span {
  display: block;
  color: #fff;
  text-transform: uppercase;
  line-height: 1.1;
  -webkit-transform: rotate(-90deg) translateY(15rem);
  transform: rotate(-90deg) translateY(15rem);
  -webkit-transform-origin: bottom left;
  transform-origin: bottom left;
  font-size: 1.35rem;
}

.cart-total {
  display: block;
  height: 2rem;
  width: 2rem;
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 50%;
  text-align: center;
  line-height: 2rem;
  margin-left: 1rem;
}

.slider {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

.slider__text {
  position: absolute;
  bottom: calc(2rem + 3vw);
  left: calc(2rem + 3vw);
  z-index: 10;
  font-size: calc(1rem + 4vw);
  text-transform: uppercase;
  -webkit-transform-origin: top;
  transform-origin: top;
  line-height: 1.075;
  color: #fff;
}

.slider__text-line {
  overflow: hidden;
}

.slider__inner {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

.slider__nav {
  position: absolute;
  top: 50%;
  right: 0;
  -webkit-transform: translateY(-50%);
  transform: translateY(-50%);
  z-index: 10;
}

.slider-bullet {
  display: flex;
  align-items: center;
  padding: 1rem 0;
}

.slider-bullet__text {
  color: #fff;
  font-size: 0.65rem;
  margin-right: 1rem;
}

.slider-bullet__line {
  background-color: #fff;
  height: 1px;
  width: 1rem;
}

.slider canvas {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

.slide {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  overflow: hidden;
}

.slide__content {
  display: flex;
  align-items: center;
  justify-content: center;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
}

.slide__img {
  position: relative;
  width: 25vw;
  height: 70vh;
  padding: 0;
  margin: 0;
  min-width: 12.5rem;
  -webkit-transform-origin: top;
  transform-origin: top;
}

.slide__img:first-child {
  top: -1.5rem;
}

.slide__img:last-child {
  bottom: -1.5rem;
}

.slide__img img {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
<nav class="nav nav--left js-nav">
  <ul>
    <li>
      <a href="#"><span>Mens</span></a>
    </li>
    <li>
      <a href="#"><span>Womens</span></a>
    </li>
    <li>
      <a href="#" class="is-active"><span>Collections</span></a>
    </li>
  </ul>
</nav>

<figure class="logo">
  <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/logo_copy_copy.svg">
</figure>

<nav class="nav nav--right">
  <ul>
    <li>
      <a href="https://twitter.com/Jesper_Landberg?lang=en" target="_blank"><span>Say hi</span></a>
    </li>
    <li>
      <a href="#">
        <span>Cart</span>
        <div class="cart-total">0</div>
      </a>
    </li>
  </ul>
</nav>

<div class="slider js-slider">
  <div class="slider__inner js-slider__inner"></div>

  <div class="slide js-slide">
    <div class="slide__content">
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo1.jpg">
      </figure>
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo2.jpg">
      </figure>
    </div>

    <div class="slider__text js-slider__text">
      <div class="slider__text-line js-slider__text-line">
        <div>Black is</div>
      </div>
      <div class="slider__text-line js-slider__text-line">
        <div>timeless. Black is</div>
      </div>
      <div class="slider__text-line js-slider__text-line">
        <div>the colour of</div>
      </div>
      <div class="slider__text-line js-slider__text-line">
        <div>Eternity.</div>
      </div>
    </div>

  </div>

  <div class="slide js-slide">
    <div class="slide__content">
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo3.jpg">
      </figure>
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo4.jpg">
      </figure>
    </div>
  </div>

  <div class="slide js-slide">
    <div class="slide__content">
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo5.jpg">
      </figure>
      <figure class="slide__img js-slide__img">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/photo6.jpg">
      </figure>
    </div>
  </div>

  <nav class="slider__nav js-slider__nav">
    <div class="slider-bullet js-slider-bullet">
      <span class="slider-bullet__text js-slider-bullet__text">01</span>
      <span class="slider-bullet__line js-slider-bullet__line"></span>
    </div>
    <div class="slider-bullet js-slider-bullet">
      <span class="slider-bullet__text js-slider-bullet__text">02</span>
      <span class="slider-bullet__line js-slider-bullet__line"></span>
    </div>
    <div class="slider-bullet js-slider-bullet">
      <span class="slider-bullet__text js-slider-bullet__text">03</span>
      <span class="slider-bullet__line js-slider-bullet__line"></span>
    </div>
  </nav>

  <div class="scroll js-scroll">Scroll</div>

</div>

<div class="vert-text">
  <span>
    Wings+Horns<br>
    X Kyoto Black
  </span>
</div>

<script id="vertexShader" type="x-shader/x-vertex">
  varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
  varying vec2 vUv; uniform sampler2D texture1; uniform sampler2D texture2; uniform sampler2D disp; uniform float dispPower; uniform float intensity; void main() { vec2 uv = vUv; vec4 disp = texture2D(disp, uv); vec2 dispVec = vec2(disp.x, disp.y); vec2
  distPos1 = uv + (dispVec * intensity * dispPower); vec2 distPos2 = uv + (dispVec * -(intensity * (1.0 - dispPower))); vec4 _texture1 = texture2D(texture1, distPos1); vec4 _texture2 = texture2D(texture2, distPos2); gl_FragColor = mix(_texture1, _texture2,
  dispPower); }
</script>

1 个答案:

答案 0 :(得分:1)

您已经在nextSlide函数中捕获了wheel事件。您现在所要做的就是阅读其event.deltaY value,以确定滚动是向上还是向下。这是一些伪代码:

var prevY = 0;
var newY = 0;

nextSlide(event) {
    newY = event.deltaY;

    if(newY > prevY){
        slideDown();
    }else if(newY < prevY) {
        slideUp();
    }

    // Store deltaY into prevY for comparison on next scroll
    prevY = event.deltaY;
}