我试图让这个光标效果对反应
I'm trying to get this cursor effect on react
我是 React 的新手,我正在尝试在我的登录页面上获得这种光标效果,但我无法在不使用 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>
首先,注意几点:
我假设您使用 Babel 来转换 JSX 并能够使用 ES2015 箭头函数。如果没有,请更新您的问题,我会更新我的答案。
接下来,你不需要游标class的三个元素。该代码建议您只使用两个元素。蓝色的我称之为 mainCursor 和白色的 - trailingCursor.
此外,我没有实现 jQuery 中的 eq 函数,但在这个例子中我们确定 document.getElementByClassName 会 return 2 个元素,所以我不包括 null 检查。
React 实现请求行为的方式是:
- 创建一个 cursor 元素,该元素使用 state 中保存的位置来呈现自身
- 将 onMouseMove 侦听器附加到鼠标在其中移动的父元素
- 当鼠标移动时,它会调用处理函数,在其中我们使用 setState 将鼠标位置保存在 state 中,这使用新的鼠标位置
触发 cursor 元素的重新渲染
话虽如此,这是您问题中功能的移植版本。我提供了一个可运行的片段。
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>
我的解决方案使用 requestAnimationFrame 而不是 setTimeout 和 refs 来实现更短的绘制时间和更流畅的动画,此外,使用变换而不是绝对位置通常会提供更好的 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>
我是 React 的新手,我正在尝试在我的登录页面上获得这种光标效果,但我无法在不使用 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>
首先,注意几点:
我假设您使用 Babel 来转换 JSX 并能够使用 ES2015 箭头函数。如果没有,请更新您的问题,我会更新我的答案。
接下来,你不需要游标class的三个元素。该代码建议您只使用两个元素。蓝色的我称之为 mainCursor 和白色的 - trailingCursor.
此外,我没有实现 jQuery 中的 eq 函数,但在这个例子中我们确定 document.getElementByClassName 会 return 2 个元素,所以我不包括 null 检查。
React 实现请求行为的方式是:
- 创建一个 cursor 元素,该元素使用 state 中保存的位置来呈现自身
- 将 onMouseMove 侦听器附加到鼠标在其中移动的父元素
- 当鼠标移动时,它会调用处理函数,在其中我们使用 setState 将鼠标位置保存在 state 中,这使用新的鼠标位置 触发 cursor 元素的重新渲染
话虽如此,这是您问题中功能的移植版本。我提供了一个可运行的片段。
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>
我的解决方案使用 requestAnimationFrame 而不是 setTimeout 和 refs 来实现更短的绘制时间和更流畅的动画,此外,使用变换而不是绝对位置通常会提供更好的 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>