我正在尝试使此光标效果发生反应

时间:2019-03-03 18:18:08

标签: jquery reactjs mouseevent

我是新来的反应者,我正在尝试在我的登录页面上获得此光标效果,但是如果不使用jquery我就无法做到这一点...我已经看过反应SyntheticEvents ,但我不知道如何正确使用它们。

这是我想要实现的效果,但是在反应中:

$(document)
  .mousemove(function(e) {
    $('.cursor')
      .eq(0)
      .css({
        left: e.pageX,
        top: e.pageY
      });
    setTimeout(function() {
      $('.cursor')
        .eq(1)
        .css({
          left: e.pageX,
          top: e.pageY
        });
    }, 100);
  })
body{
  background:black;
}

h1{
  color:white;
}

* {
    cursor: none;
}

.cursor {
    position: fixed;
    height: 10px;
    width: 10px;
    border-radius: 50%;
    transform: translateX(-50%) translateY(-50%);
    pointer-events:none;
}
.cursors .cursor:nth-child(1) {
    background-color: #3a26fd;
    z-index: 100002;
}
.cursors .cursor:nth-child(2) {
    background-color: #f3f3f3;
    z-index: 100001;
    height: 9px;
    width: 9px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="cursors">
<div class='cursor'></div>
<div class='cursor'></div>
<div class='cursor'></div>
</div>
<h1>Custom cursor</h1>

2 个答案:

答案 0 :(得分:1)

以前的解决方案对于不需要性能的人来说效果很好。

我的解决方案是使用requestAnimationFrame而不是setTimeout和ref来缩短绘制时间和使动画更流畅,此外,使用转换代替绝对位置通常会提供更好的FPS。

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      mouseX: 0,
      mouseY: 0,
      trailingX: 0,
      trailingY: 0,
    };
    this.cursor = React.createRef();
    this.cursorTrailing = React.createRef();
    this.animationFrame = null;
  }
  
  componentDidMount() {
    document.addEventListener('mousemove', this.onMouseMove);
    this.moveCursor();
  }
  
  componentWillUnmount() {
    document.removeEventListener('mousemove', this.onMouseMove)
    cancelAnimationFrame(this.animationFrame);
  }
  
  onMouseMove = (evt) => {
    const { clientX, clientY } = evt;
    this.setState({
      mouseX: clientX,
      mouseY: clientY,
    });
  }
  
  moveCursor = () => {
    const { mouseX, mouseY, trailingX, trailingY } = this.state;
    const diffX = mouseX - trailingX;
    const diffY = mouseY - trailingY;
    //  Number in expression is coeficient of the delay. 10 for example. You can play with it. 
    this.setState({
      trailingX: trailingX + diffX / 10,
      trailingY: trailingY + diffY / 10,
    },
    () => {
    // Using refs and transform for better performance.
      this.cursor.current.style.transform = `translate3d(${mouseX}px, ${mouseY}px, 0)`;
      this.cursorTrailing.current.style.transform = `translate3d(${trailingX}px, ${trailingY}px, 0)`;
      this.animationFrame = requestAnimationFrame(this.moveCursor);
    });
  }
  
  render = () => {
    return (
      <div className="container">
        <div className="cursors">
          <div 
            className="cursor"
            ref={this.cursor}
          />
          <div 
            className='cursor'
            ref={this.cursorTrailing}
          />
        </div>
      </div>
    );
  };
}

ReactDOM.render(<App />, document.getElementById('root'));
* {
    cursor: none;
}

.container {
  background: black;
  min-height: 800px;
}

.cursor {
    position: fixed;
    height: 10px;
    width: 10px;
    border-radius: 50%;
    transform: translateX(-50%) translateY(-50%);
    pointer-events:none;
}

.cursors .cursor:nth-child(1) {
    background-color: #3a26fd;
    z-index: 100002;
}
.cursors .cursor:nth-child(2) {
    background-color: #f3f3f3;
    z-index: 100001;
    height: 9px;
    width: 9px;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>    
  </head>
  
  <body>
    <div id="root"></div>
  </body>
</html>

答案 1 :(得分:0)

首先,请注意以下几点:

我假设您使用Babel来转译JSX并能够使用ES2015箭头功能。如果没有,请更新您的问题,我会更新我的答案。

接下来,您不需要 cursor 类的三个元素。该代码建议您仅使用两个元素。我称之为蓝色的 mainCursor 和白色的 trailingCursor

此外,我没有实现jQuery的eq函数,但是在此示例中,我们确定 document.getElementByClassName 将返回2个元素,因此我不包括对null的检查。


实现请求的行为的React方法是:

  1. 创建一个 cursor 元素,该元素使用保存在状态中的位置来呈现自己
  2. 将onMouseMove侦听器附加到在其中移动鼠标的父元素
  3. 移动鼠标时,它将调用处理程序函数,在其中我们使用 setState 将鼠标位置保存为 state ,这会触发的重新渲染使用新的鼠标位置的光标元素

话虽这么说,这是您问题中功能的移植版本。我提供了一个可运行的代码段。

class App extends React.Component {
  // we keep track of x and y coordinates for the blue circle - the main one
  // and the trailing circle - the white one
  // for simplicity, they are initialzed to (0, 0), the top left corner of the viewport
  state = {
    xMain: 0,
    yMain: 0,
    xTrailing: 0,
    yTrailing: 0,
  }
  
  handleMouseMove = (e) => {
    // Using pageX and pageY will cause glitching when you scroll the window down
    // because it measures the distance from the top left rendered corner, not
    // top left visible corner
    const { clientX, clientY } = e;

    // we set the main circle coordinates as soon as the mouse is moved
    this.setState({
      xMain: clientX,
      yMain: clientY,
    }, () => {
      // this callback is invoked after the first setState finishes
      // 
      // here we schedule saving the trailing coordinates in state 100ms  
      // after the main coordinates have been set to simulate the trailing
      setTimeout(() => {
        this.setState({
          xTrailing: clientX,
          yTrailing: clientY,
        })
      }, 100);
    })
  }

  render = () => {
    // we retrieve coordinates from state
    const {
      xMain,
      yMain,
      xTrailing,
      yTrailing
    } = this.state;

    return (
      // we need a container that has a definite height, 800px in my example
      // this is to make sure it leaves enough room for mouse movement to happen and trigger the event handler
      // 
      // also, you don't need the event listener on both your cursor elements, only on the container
      <div
        className='container'
        onMouseMove={e => this.handleMouseMove(e)}
      >
        <div className='cursors'>
          // this below is the main cursor
          // we set its style inline with coordinates from state
          <div 
            className='cursor'
            style={{ 
              left: xMain, 
              top: yMain,
            }}
          />
          
          // this below is the trailing cursor
          <div 
            className='cursor'
            style={{ 
              left: xTrailing, 
              top: yTrailing,
            }}
          />
        </div>
      </div>
      )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
* {
    cursor: none;
}

.container {
  background: black;
  min-height: 800px;
}

.cursor {
    position: fixed;
    height: 10px;
    width: 10px;
    border-radius: 50%;
    transform: translateX(-50%) translateY(-50%);
    pointer-events:none;
}

.cursors .cursor:nth-child(1) {
    background-color: #3a26fd;
    z-index: 100002;
}
.cursors .cursor:nth-child(2) {
    background-color: #f3f3f3;
    z-index: 100001;
    height: 9px;
    width: 9px;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>    
  </head>
  
  <body>
    <div id="root"></div>
  </body>
</html>

相关问题