Javascript 带有动态子组件的自定义游标
我有一个基于Codrops的自定义游标组件 我在每个页面上都能很好地工作,除了一个页面,它是一个基于当前状态动态显示/隐藏内容的公文包页面 如果更改状态(显示未初始加载的组件+隐藏初始组件或隐藏未初始加载的组件+显示初始加载的内容),自定义光标将不再对类名作出反应 我根据组件的当前状态显示/隐藏内容 我试图重新“初始化”光标,但这会导致自定义光标的大小/位置出现问题 我知道Cursor.js不知道在状态更改后什么时候“查找”新类,但我不知道如何让它“监视”更改,而且由于重新初始化游标不起作用,我不确定应该尝试什么。我是否应该尝试使用eventListener强制光标再次查看类 理想情况下,自定义游标将与动态和非动态元素交互,但我怀疑这是否可行 如有任何建议,将不胜感激。或者,如果有人有一个在这个场景中工作的React自定义游标的示例,我很乐意查看它 Portfolio.jsJavascript 带有动态子组件的自定义游标,javascript,reactjs,code-splitting,Javascript,Reactjs,Code Splitting,我有一个基于Codrops的自定义游标组件 我在每个页面上都能很好地工作,除了一个页面,它是一个基于当前状态动态显示/隐藏内容的公文包页面 如果更改状态(显示未初始加载的组件+隐藏初始组件或隐藏未初始加载的组件+显示初始加载的内容),自定义光标将不再对类名作出反应 我根据组件的当前状态显示/隐藏内容 我试图重新“初始化”光标,但这会导致自定义光标的大小/位置出现问题 我知道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>
);
}
render(){
返回(
//光标
//显示状态更改时的所有项目
{this.state.showAllItems?
{list.map(项=>(
{item.itemTitle}{item.itemSubtitle}
))}
:null}
//在状态更改时显示项目
{this.state.currentProject?
:null}
);
}
Cursor.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;
import React,{Component}来自'React';
从“/utils/Util”导入Util;
导入“./styles/cursor.scss”;
从“gsap”进口TweenMax;
类CustomCursor扩展组件{
建造师(道具){
超级(道具);
this.state={isOn:this.props.isOn};
}
componentDidMount(){
如果(this.state.isOn==“true”){
this.inithover();
}
否则{
this.initCursor();
this.initCanvas();
this.inithover();
}
}
initCursor(){
this.clientX=-100;
this.clientY=-100;
this.innerCursor=document.querySelector(“.circle cursor--inner”);
this.outerCursor=document.querySelector(“.custom cursor--outer”);
此.outerCursorSpeed=1;
这个.lastX=0;
此.lastY=0;
this.isStuck=false;
this.showCursor=false;
const{paper}=窗口;
常数=e=>{
this.group.position=新纸张点(e.clientX,e.clientY);
设置超时(()=>{
该速度为0.2;
}, 100);
this.showCursor=true;
};
文件。添加的文件列表器(“鼠标移动”,光标);
document.addEventListener(“mousemove”,e=>{
this.clientX=e.clientX;
this.clientY=e.clientY;
});
常量渲染=()=>{
TweenMax.set(此.innerCursor{
x:这个,clientX,
y:这个,克利提
});
if(this.showCursor){
document.removeEventListener(“mousemove”,鼠标指针);
}
请求动画帧(渲染);
};
请求动画帧(渲染);
}
initCanvas(){
const{paper,SimplexNoise}=窗口;
const canvas=document.querySelector(“.circle cursor--outer”);
常量形状块={
宽度:75,
身高:75
};
纸。设置(画布);
const strokeColor=“rgba(255,0,0,0.5)”;
常数冲程宽度=1;
常数段=8;
常数半径=25;
const noiseScale=150;//速度
const noiseRange=4;//失真范围
让isnoise=false;
常量多边形=新的paper.Path.RegularPolygon(
新纸点(0,0),
部分,
半径
);
polygon.strokeColor=strokeColor;
polygon.strokeWidth=strokeWidth;
多边形平滑();
this.group=new paper.group([polygon]);
this.group.applyMatrix=false;
const noiseObjects=polygon.segments.map(()=>new SimplexNoise());
设bigCoordinates=[];
paper.view.onFrame=事件=>{
如果(!this.isStuck){
//正常地转一圈
this.lastX=Util.lerp(this.lastX、this.clientX、this.outerCursorSpeed);
this.lastY=Util.lerp(this.lastY,this.clientY,this.outerCursorSpeed);
this.group.position=新纸张.Point(this.lastX,this.lastY);
}else if(this.isStuck){
//导航设备上的固定位置
this.lastX=Util.lerp(this.lastX,this.stuckX,this.outerCursorSpeed);
this.lastY=Util.lerp(this.lastY,this.stuckY,this.outercurspeed);
this.group.position=新纸张.Point(this.lastX,this.lastY);
}
if(this.isStuck&&polygon.bounds.width30),则为else{
//消除噪音
如果(有噪音){
多边形.segments.forEach((段,i)=>{
segment.point.set(bigCoordinates[i][0],bigCoordinates[i][1]);
});
isnoised=假;
大坐标=[];
}
//缩小形状
常数scaleDown=0.92;
多边形。缩放(缩放向下);
}
//卡住时和较大时,是否有柏林噪音
if(this.isStuck&&polygon.bounds.width>=shapeBounds.width){
isnoise=true;
//首先得到大圆的坐标
if(bigCoordinates.length==0){
多边形.segments.forEach((段,i)=>{
BigCoordinations[i]=[段.点.x,段.点.y];
});
}
//计算该帧上每个点的噪波值
多边形.segments.forEach((段,i)=>{
const noiseX=noiseObjects[i].noise2D(event.count/noiseScale,0);
const noiseY=noiseObjects[i].noise2D(event.count/noiseS