Codepen为例.我有一个悬停效果,渐变跟随鼠标光标.

我有两个CSS变量,分别为--x--y,用于跟踪鼠标在按钮上的位置.

background: radial-gradient(circle closest-side, pink, transparent)时,它会在正确的位置创建渐变.

Document.querySelector()EventTarget.addEventListener()'mousemove'事件注册处理程序.

Element.getBoundingClientRect()CSSStyleDeclaration.setProperty()更新--x--y个CSS变量的值.

现在,我try 在带有MUI按钮的React Typescript中将其重新创建为样式化组件.

Button.tsx

import React from 'react';
import { styled, Theme } from '@mui/material/styles';
import { Button, SxProps } from '@mui/material';

const HoverButton = styled(Button)(({ theme }) => ({
    borderRadius: 100,
    ".mouse-cursor-gradient-tracking": {
        position: "relative",
        background: "#7983ff",
        padding: "0.5rem 1rem",
        fontSize: "1.2rem",
        border: "none",
        color: theme.palette.secondary.contrastText,
        cursor: "pointer",
        outline: "none",
        overflow: "hidden",
      },
      
      ".mouse-cursor-gradient-tracking span": {
        position: "relative",
      },
      
      ".mouse-cursor-gradient-tracking:before": {
        --size: 0,
        content: '',
        position: "absolute",
        left: "var(--x)",
        top: "var(--y)",
        width: "var(--size)",
        height: "var(--size)",
        background: "radial-gradient(circle closest-side, pink, transparent)",
        transform: "translate(-50%, -50%)",
        transition: "width 0.2s ease, height 0.2s ease",
      },
      
      ".mouse-cursor-gradient-tracking:hover:before": {
        "--size": "200px"
      },
}));

export function SubmitButton(props: { children: React.ReactNode; sx?: SxProps<Theme> }) {
    let button:<Element | null> = document.querySelector('.mouse-cursor-gradient-tracking');
    button.addEventListener('mousemove', e => {
        let rect = e.target.getBoundingClientRect();
        let x = e.clientX - rect.left;
        let y = e.clientY - rect.top;
        button.style.setProperty('--x', x + 'px');
        button.style.setProperty('--y', y + 'px');
    });

    return (
        <HoverButton type="submit" variant="contained" sx={props.sx}>
            {props.children}<span>Hover me</span>
        </HoverButton>
    );
}

推荐答案

这是一个有效的codesandbox.

让我来解释一下你的方法的一些缺点.

  1. 强制查询 Select 带有类的按钮并添加事件处理程序.如下所示:
    let button:<Element | null> = document.querySelector('.mouse-cursor-gradient-tracking');
    button.addEventListener('mousemove', e => {
        let rect = e.target.getBoundingClientRect();
        let x = e.clientX - rect.left;
        let y = e.clientY - rect.top;
        button.style.setProperty('--x', x + 'px');
        button.style.setProperty('--y', y + 'px');
    });

相反,您可以将事件处理程序直接添加到React中的按钮组件.因此,React要注意如何将事件添加到组件中.

const Component = () => {

  const mouseDownHandler = (e) => {
    // logic here
  }
  
 return (<button onMouseDown={mouseDownHandler}>Click me</button>);
};
  1. 使用与styledcss-in-js混合的类.
const HoverButton = styled(Button)(({ theme }) => ({
    ".mouse-cursor-gradient-tracking": {
        position: "relative",
        background: "#7983ff",
      },
    ".mouse-cursor-gradient-tracking span": {
        position: "relative",
      },
      
      ".mouse-cursor-gradient-tracking:before": {
        --size: 0,
        content: '',
      },
      
      ".mouse-cursor-gradient-tracking:hover:before": {
        "--size": "200px"
      },
}));

相反,您可以简单地执行以下操作:

const HoverButton = styled(Button)`  
  position: relative;
  background: #7983ff;

  & > span {
    ... your code here
  }

  &:before {
   ... your code here
  }
  
  &:hover:before {
   ... your code here
  } 
`;

const SubmitButton = () => {
 return <HoverButton>Text</HoverButton>
}

该样式将直接应用于带有伪类的按钮.除非您试图覆盖另一个库中的现有类,否则不需要单独的自定义类(js引擎中的css将创建一个自己带有哈希的类).

  1. 动态更新样式.
button.addEventListener('mousemove', e => {
  ...other codes
  button.style.setProperty('--x', x + 'px');
  button.style.setProperty('--y', y + 'px');
});

这不会动态更新按钮的样式.我们可以使用一个状态,该状态可以使用第1点中提到的处理程序进行更新,并将其作为props 传递给样式化按钮,并使用它更改css值.

这是完整的工作代码.

import { useState } from "react";
import { styled, Theme } from "@mui/material/styles";
import { Button, SxProps } from "@mui/material";
import "./styles.css";

const StyledButton = styled(Button)<{ left: number; top: number }>`
  position: relative;
  background: #7983ff;
  padding: 0.5rem 1rem;
  font-size: 1.2rem;
  border: none;
  color: white;
  cursor: pointer;
  outline: none;
  overflow: hidden;

  &:before {
    content: "";
    left: ${({ left }) => left}px;
    top: ${({ top }) => top}px;
    position: absolute;
    width: 0;
    height: 0;
    background: radial-gradient(circle closest-side, pink, transparent);
    transform: translate(-50%, -50%);
    transition: width 0.2s ease, height 0.2s ease;
  }

  &:hover:before {
    color: red;
    width: 200px;
    height: 200px;
  }
`;

const SubmitButton = (props: {
  children?: React.ReactNode;
  sx?: SxProps<Theme>;
}) => {
  const [hoverStyle, setHoverStyle] = useState({
    left: 0,
    top: 0
  });

  const handleMouseMove: React.MouseEventHandler<HTMLButtonElement> = (e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const left = e.clientX - rect.left;
    const top = e.clientY - rect.top;

    setHoverStyle({ left, top });
  };

  return (
    <StyledButton
      left={hoverStyle.left}
      top={hoverStyle.top}
      type="submit"
      variant="contained"
      sx={props.sx}
      onMouseMove={handleMouseMove}
    >
      <span>Hover me</span>
    </StyledButton>
  );
};

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <SubmitButton />
    </div>
  );
}

资源链接:

Javascript相关问答推荐

我不知道为什么我的JavaScript没有验证我的表单

使用json文件字符串来enum显示类型字符串无法按照计算的enum成员值的要求分配给类型号

在贝塞尔曲线的直线上找不到交叉点:(使用@Pomax的bezier.js)

深嵌套的ng-container元素仍然可以在Angular 布局组件中正确渲染内容吗?

如何在Javascript中的控制台上以一行形式打印循环的结果

Chrome是否忽略WebAuthentication userVerification设置?""

使用javascript将Plotly Expandable Sparkline转换为HighCharter Plot在bslib卡中

React Code不在装载上渲染数据,但在渲染上工作

如何使覆盖div与可水平滚动的父div相关?

Eval vs函数()返回语义

<;img>;标记无法呈现图像

FireBase云函数-函数外部的ENV变量

判断函数参数的类型

Reaction即使在重新呈现后也会在方法内部保留局部值

本地损坏的Java脚本

通过解构/功能组件接收props-prop验证中缺少错误"

如何在Java脚本中并行运行for或任意循环的每次迭代

找不到处于状态的联系人

使用jQuery每隔几秒钟突出显示列表中的不同单词

JS/css:将数字输入的S函数和可调整大小的元素S函数绑定在一起