ReactJS Пользовательский курсор с Dynami c Дочерний компонент - PullRequest
0 голосов
/ 01 марта 2020

У меня есть пользовательский компонент курсора, основанный на Codrops https://tympanus.net/codrops/2019/01/31/custom-cursor-effects/.

У меня хорошо работает на каждой странице, кроме одной, которая является страницей портфолио, которая динамически показывает / скрывает содержимое на основании текущего состояния.

Если я меняю состояния (показать компонент, который изначально не загружен + скрыть исходный компонент ИЛИ скрыть компонент, который не был загружен изначально + показать изначально загруженный контент), пользовательский курсор больше не реагирует на имя класса.

Я показываю / скрываю содержимое в зависимости от текущего состояния компонента.

Я пытался повторно «инициализировать» курсор, но это вызывает проблемы с размером / положением пользовательский курсор.

Я понимаю Курсор. js не знает, когда «искать» новые классы после изменения состояния, но я не могу понять, как заставить его «наблюдать» за изменениями, и поскольку повторная инициализация курсора не работает, я не уверен, что мне следует попробовать. Должен ли я попробовать eventListener, который заставляет курсор снова смотреть на классы?

В идеале пользовательский курсор будет взаимодействовать как с динамическими c, так и с не динамическими c элементами, но я сейчас спрашиваю, возможно ли это.

Любой Совет будет принята с благодарностью. Или, если у кого-нибудь есть пример React Custom Cursor, который работает в этом сценарии, я хотел бы проверить его.

Портфолио. js

render() {
return (
  <div>
    <div className="cursor">
      <div className="circle-cursor circle-cursor--inner"></div>
    </div>
    <canvas
      className="circle-cursor circle-cursor--outer"
      resize="true"
    ></canvas>
    //CURSOR
    <CustomCursor />
    //SHOW ALL PROJECTS ON STATE CHANGE
    { this.state.showAllItems ? 
    <div className={styles.grid}>
      {list.map(item => (
        <div key={item.index} className={styles.grid__item}>
          <a href="#/a" key={item.index} value={item.index} onClick={e => this.onClick(e, item)} >
            <div key={item.index}  className={styles.glitch + " portfolioLinkHover " + styles.glitchStyle1}>
              <div className={styles.glitch__img + " img"} style={{background: 'url('+ item.imgSrc + ') no-repeat 50% 0'}}></div>
              <div className={styles.glitch__img + " img"} style={{background: 'url('+ item.imgSrc + ') no-repeat 50% 0'}}></div>
            </div>
          </a>
          <h2>{item.itemTitle} <span>{item.itemSubtitle}</span></h2>
            </a>
          </p>
        </div>
      ))}
    </div>
    : null }
    //SHOW PROJECT ON STATE CHANGE
    { this.state.currentProject ? 
      <div className={styles.projectContainer + " portfolioLinkHover"}>
        <Project />
      </div>  : null }
  </div>
);
}

Курсор. js

import React, {Component} from 'react';
import Util from "./utils/util";
import './styles/cursor.scss';
import TweenMax from 'gsap';

class CustomCursor extends Component{
  constructor(props) {
    super(props);
    this.state = { isOn: this.props.isOn };
  }

  componentDidMount(){
    if(this.state.isOn == "true"){
      this.initHovers();
    }
    else{
      this.initCursor();
      this.initCanvas();
      this.initHovers();
    }
  }

  initCursor() {
    this.clientX = -100;
    this.clientY = -100;
    this.innerCursor = document.querySelector(".circle-cursor--inner");
    this.outerCursor = document.querySelector(".custom-cursor--outer");
    this.outerCursorSpeed = 1;
    this.lastX = 0;
    this.lastY = 0;
    this.isStuck = false;
    this.showCursor = false;
    const { paper } = window;

    const unveilCursor = e => {
      this.group.position = new paper.Point(e.clientX, e.clientY);
      setTimeout(() => {
        this.outerCursorSpeed = 0.2;
      }, 100);
      this.showCursor = true;
    };
    document.addEventListener("mousemove", unveilCursor);

    document.addEventListener("mousemove", e => {
      this.clientX = e.clientX;
      this.clientY = e.clientY;
    });

    const render = () => {
      TweenMax.set(this.innerCursor, {
        x: this.clientX,
        y: this.clientY
      });
      if (this.showCursor) {
        document.removeEventListener("mousemove", unveilCursor);
      }
      requestAnimationFrame(render);
    };
    requestAnimationFrame(render);
  }

  initCanvas() {
    const { paper, SimplexNoise } = window;
    const canvas = document.querySelector(".circle-cursor--outer");
    const shapeBounds = {
      width: 75,
      height: 75
    };
    paper.setup(canvas);

    const strokeColor = "rgba(255, 0, 0, 0.5)";
    const strokeWidth = 1;
    const segments = 8;
    const radius = 25;
    const noiseScale = 150; // speed
    const noiseRange = 4; // range of distortion
    let isNoisy = false;

    const polygon = new paper.Path.RegularPolygon(
      new paper.Point(0, 0),
      segments,
      radius
    );
    polygon.strokeColor = strokeColor;
    polygon.strokeWidth = strokeWidth;
    polygon.smooth();

    this.group = new paper.Group([polygon]);
    this.group.applyMatrix = false;

    const noiseObjects = polygon.segments.map(() => new SimplexNoise());
    let bigCoordinates = [];

    paper.view.onFrame = event => {
      if (!this.isStuck) {
        // move circle around normally
        this.lastX = Util.lerp(this.lastX, this.clientX, this.outerCursorSpeed);
        this.lastY = Util.lerp(this.lastY, this.clientY, this.outerCursorSpeed);
        this.group.position = new paper.Point(this.lastX, this.lastY);
      } else if (this.isStuck) {
        // fixed position on a nav item
        this.lastX = Util.lerp(this.lastX, this.stuckX, this.outerCursorSpeed);
        this.lastY = Util.lerp(this.lastY, this.stuckY, this.outerCursorSpeed);
        this.group.position = new paper.Point(this.lastX, this.lastY);
      }

      if (this.isStuck && polygon.bounds.width < shapeBounds.width) {
        // scale up the shape
        polygon.scale(1.08);
      } else if (!this.isStuck && polygon.bounds.width > 30) {
        // remove noise
        if (isNoisy) {
          polygon.segments.forEach((segment, i) => {
            segment.point.set(bigCoordinates[i][0], bigCoordinates[i][1]);
          });
          isNoisy = false;
          bigCoordinates = [];
        }

        // scale down the shape
        const scaleDown = 0.92;
        polygon.scale(scaleDown);
      }

      // while stuck and when big, do perlin noise
      if (this.isStuck && polygon.bounds.width >= shapeBounds.width) {
        isNoisy = true;

        // first get coordinates of large circle
        if (bigCoordinates.length === 0) {
          polygon.segments.forEach((segment, i) => {
            bigCoordinates[i] = [segment.point.x, segment.point.y];
          });
        }

        // calculate noise value for each point at that frame
        polygon.segments.forEach((segment, i) => {
          const noiseX = noiseObjects[i].noise2D(event.count / noiseScale, 0);
          const noiseY = noiseObjects[i].noise2D(event.count / noiseScale, 1);

          const distortionX = Util.map(noiseX, -1, 1, -noiseRange, noiseRange);
          const distortionY = Util.map(noiseY, -1, 1, -noiseRange, noiseRange);

          const newX = bigCoordinates[i][0] + distortionX;
          const newY = bigCoordinates[i][1] + distortionY;

          segment.point.set(newX, newY);
        });
      }

      // hover state for main nav items
      if (this.fillOuterCursor && polygon.fillColor !== strokeColor) {
        polygon.fillColor = strokeColor;
        polygon.strokeColor = "transparent";
      } else if (!this.fillOuterCursor && polygon.fillColor !== "transparent") {
        polygon.strokeColor = "rgba(255, 0, 0, 0.5)";
        polygon.fillColor = "transparent";
      }

      // hover state for portfolio nav items
      if (this.isOnPortfolioItem) {
        polygon.fillColor = strokeColor;
        polygon.strokeColor = "rgba(255, 226, 0, 0.5)";
        // scale up the shape
        polygon.bounds.width = 45;
        polygon.bounds.height = 45;
      } else if (!this.fillOuterCursor) {
        polygon.strokeColor = "rgba(255, 0, 0, 0.5)";
        polygon.fillColor = "transparent";
      }
      polygon.smooth();
    };
  }

  initHovers() {
    const handleMouseEnter = e => {
      const navItem = e.currentTarget;
      const navItemBox = navItem.getBoundingClientRect();
      this.stuckX = Math.round(navItemBox.left + navItemBox.width / 2);
      this.stuckY = Math.round(navItemBox.top + navItemBox.height / 2);
      this.isStuck = true;
    };

    const handleMouseLeave = () => {
      this.isStuck = false;
    };

    const linkItems = document.querySelectorAll(".browser-window__link");
    linkItems.forEach(item => {
      item.addEventListener("mouseenter", handleMouseEnter);
      item.addEventListener("mouseleave", handleMouseLeave);
    });

    const mainNavItemMouseEnter = () => {
      this.outerCursorSpeed = 0.8;
      this.fillOuterCursor = true;
    };
    const mainNavItemMouseLeave = () => {
      this.outerCursorSpeed = 0.2;
      this.fillOuterCursor = false;
    };
    const portfolioItems = document.querySelectorAll(".portfolioLinkHover");
    portfolioItems.forEach(item => {
      item.addEventListener("mouseenter", handleLinkEnter);
      item.addEventListener("mouseleave", handleLinkLeave);
    });
  }
  render() {
    return (
      <div></div>
    );
  }
}

export default CustomCursor;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...