如何始终在聚焦的 Material-UI Button 组件上应用 focusVisible 样式?

use*_*553 4 css focus button reactjs material-ui

对于 Material-UI Button 组件,我希望“焦点”样式看起来与“focusVisible”样式相同。这意味着如果按钮以编程方式聚焦或使用鼠标聚焦,我希望它具有相同的可见涟漪效果,就像按钮通过 Tab 键聚焦一样。

我发现的一种解决方法是dispatchEvent(new window.Event("keydown"))在元素聚焦之前调用该元素,从而使键盘成为最后使用的输入类型。这将使按钮看起来像我想要的那样,直到 onMouseLeave 事件(来自 MUI <ButtonBase/>)或另一个鼠标事件被触发,导致可见焦点消失。

我已经弄清楚如何更改组件的焦点样式,如下所示:

import React from "react"
import { withStyles } from "@material-ui/core/styles"
import Button from "@material-ui/core/Button"

const styles = {
  root: {
    '&:focus': {
      border: "3px solid #000000"
    }
  }
}

const CustomButtonRaw = React.forwardRef((props, ref) => {
  const { classes, ...rest } = props
  return <Button classes={{root: classes.root}} {...rest} ref={ref}/>
}

const CustomButton = withStyles(styles, { name: "CustomButton" })(CustomButtonRaw)

export default CustomButton
Run Code Online (Sandbox Code Playgroud)

因此,当按钮处于“焦点”状态时,我可以对其应用某种样式。(例如,我应用了边框)。但我缺少如何应用样式。我尝试将 className 'Mui-visibleFocus' 放在按钮上,但这似乎没有效果。如果按钮处于可见焦点状态,是否有某种方法可以获取将应用的样式?

Rya*_*ell 5

ButtonBaseButton 委托给)有一个action 属性,它提供了设置按钮的焦点可见状态 的能力。

ButtonBase为此利用useImperativeHandle 挂钩。为了利用它,您可以将 ref 传递到actionprop 中,然后您可以稍后调用actionRef.current.focusVisible().

但是,这本身还不够,因为ButtonBase 会侦听多个鼠标和触摸事件以启动/停止波纹。如果您使用该disableTouchRipple属性,它会阻止 ButtonBase 尝试根据这些事件启动/停止波纹

不幸的是,disableTouchRipple它阻止了按钮上的单击和触摸动画。这些可以通过TouchRipple显式添加您控制的另一个元素来恢复。我下面的示例显示了处理onMouseDownonMouseUp作为概念验证,但理想的解决方案将处理所ButtonBase处理的所有不同事件。

这是一个工作示例:

import React from "react";
import Button from "@material-ui/core/Button";
import TouchRipple from "@material-ui/core/ButtonBase/TouchRipple";

const FocusRippleButton = React.forwardRef(function FocusRippleButton(
  { onFocus, onMouseDown, onMouseUp, children, ...other },
  ref
) {
  const actionRef = React.useRef();
  const rippleRef = React.useRef();
  const handleFocus = (event) => {
    actionRef.current.focusVisible();
    if (onFocus) {
      onFocus(event);
    }
  };
  const handleMouseUp = (event) => {
    rippleRef.current.stop(event);
    if (onMouseUp) {
      onMouseUp(event);
    }
  };
  const handleMouseDown = (event) => {
    rippleRef.current.start(event);
    if (onMouseDown) {
      onMouseDown(event);
    }
  };
  return (
    <Button
      ref={ref}
      action={actionRef}
      disableTouchRipple
      onFocus={handleFocus}
      onMouseDown={handleMouseDown}
      onMouseUp={handleMouseUp}
      {...other}
    >
      {children}
      <TouchRipple ref={rippleRef} />
    </Button>
  );
});
export default function App() {
  return (
    <div className="App">
      <FocusRippleButton variant="contained" color="primary">
        Button 1
      </FocusRippleButton>
      <br />
      <br />
      <FocusRippleButton
        variant="contained"
        color="primary"
        onFocus={() => console.log("Some extra onFocus functionality")}
      >
        Button 2
      </FocusRippleButton>
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

编辑无条件焦点波纹