写在前面:让普通组件,通过高阶函数的包裹,变为高阶组件,拿到鼠标的坐标值
import React, { useState, useEffect, CSSProperties } from 'react';
interface Iprops extends React.ReactElement {
mouseX: number,
mouseY: number,
[key: string]: any
}
interface StyleFunc {
(x: number, y: number): CSSProperties
}
/**
* @desciption 被复用的高阶组件都是同名,修改组件名字后便于调试
* @param WrappedComponent 组件
* @param defualtName 默认名
* @return WrappedComponent.displayName 组件的修改名 ||
* WrappedComponent.name 组件名 ||
* defaultName 默认名
*/
function getDisplayName(WrappedComponent: React.FC<Iprops>, defualtName?: string) {
return WrappedComponent.displayName || WrappedComponent.name || defualtName;
}
/**
* @desciption 高阶组件函数
* @param WrappedComponent 被包裹的组件
* @return 可以复用的逻辑组件
*/
const withMouse = (WrappedComponent: React.FC<Iprops>) => {
const Mouse = (props: any) => {
const [mouseXY, setMouseXY] = useState<Pick<Iprops, 'mouseX' | 'mouseY'>>({
mouseX: 0,
mouseY: 0
});
// 调试高阶组件传过来的props, 并传给组件WrappedComponent
useEffect(() => {
console.log(props); // { a: 1 } {}
}, []);
const handleMouseMove = (e: MouseEvent) => {
console.log(e.clientX, e.clientY);
setMouseXY({
mouseX: e.clientX,
mouseY: e.clientY
})
}
// 添加鼠标移动事件
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove)
return () => {
window.removeEventListener('mousemove', handleMouseMove);
}
}, [])
return <WrappedComponent {...mouseXY} {...props} />
}
// 修改组件名
Mouse.displayName = `withMouse${getDisplayName(WrappedComponent, 'Mouse')}`
return Mouse;
}
// 普通组件PositionShow
const PositionShow: React.FC<Iprops> = (props) => {
return (
<p>横坐标为:{props.mouseX},纵坐标为{props.mouseY}</p>
)
}
// 普通组件RecMove:跟随鼠标移动的盒子
const RecMove: React.FC<Iprops> = (props) => {
const style: StyleFunc = (x, y) => ({
width: 100,
height: 100,
backgroundColor: '#f00',
position: 'fixed',
zIndex: 100,
left: x,
top: y,
marginLeft: -50,
marginTop: -50,
// 点击穿透:自动冒泡到父级元素
pointerEvents: 'none'
})
return (
<div style={style(props.mouseX, props.mouseY)}></div>
)
}
// 高阶组件
const HighPositionShow = withMouse(PositionShow);
const HighRecMove = withMouse(RecMove);
// 路由页面组件
const HighComponentPages = () => {
return <>
{/* 在调试中默认显示的组件名都为
<Mouse/>
<Mouse/>
在修改displayName之后,显示的组件名为
<withPositionShow/>
<withMouseRecMove/>
*/}
<HighPositionShow a="1" />
<HighRecMove />
</>
}
export default HighComponentPages;