简体   繁体   English

如何始终在焦点 Material-UI 按钮组件上应用 focusVisible 样式?

[英]How to always apply focusVisible styling on a focused Material-UI Button component?

For a Material-UI Button component, I would like to have the "focus" styling look the same as "focusVisible" styling.对于 Material-UI Button 组件,我希望“focus”样式看起来与“focusVisible”样式相同。 Meaning I want it to have the same ripple effect visible if the button was focused programatically or with the mouse as if the button was focused with the tab key.这意味着如果按钮以编程方式或使用鼠标聚焦,我希望它具有相同的涟漪效果,就像按钮通过 tab 键聚焦一样。

A sort-of workaround I have found is to call dispatchEvent(new window.Event("keydown")) on the element before it is focused, causing keyboard to be the last input type used.我发现的一种解决方法是在元素获得焦点之前调用dispatchEvent(new window.Event("keydown")) ,导致键盘成为最后使用的输入类型。 This will have the effect of making the button look the way I want UNTIL the onMouseLeave event (from MUI <ButtonBase/>) or another mouse event is fired, causing the visible focus to disappear.这将使按钮看起来像我想要的那样,直到 onMouseLeave 事件(来自 MUI <ButtonBase/>)或另一个鼠标事件被触发,导致可见焦点消失。

I have figured out how to change the focus styling of the component like this:我已经想出了如何改变组件的焦点样式,如下所示:

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

So, I can apply some style to the button when it is in "focus" state.因此,当按钮处于“焦点”state 时,我可以对按钮应用一些样式。 (For ex. I applied a border). (例如,我应用了边框)。 But I am missing how to get the styles to apply.但我错过了如何让 styles 申请。 I have tried putting the className 'Mui-visibleFocus' on the Button but that did not seem to have an effect.我尝试将 className 'Mui-visibleFocus' 放在 Button 上,但这似乎没有效果。 Is there some way to get the styles that would be applied if the Button was in visibleFocus state?如果按钮位于可见焦点 state 中,是否有某种方法可以获得 styles?

ButtonBase (which Button delegates to ) has an action prop which provides the ability to set the button's focus-visible state . ButtonBaseButton 委托给)有一个action属性,可以设置按钮的焦点可见 state

ButtonBase leverages the useImperativeHandle hook for this. ButtonBase为此利用了useImperativeHandle 钩子 To leverage it, you pass a ref into the action prop and then you can later call actionRef.current.focusVisible() .为了利用它,你将一个 ref 传递给action prop,然后你可以稍后调用actionRef.current.focusVisible()

However, this by itself is not sufficient, because there are several mouse and touch events that ButtonBase listens to in order to start/stop the ripple.然而,这本身是不够的,因为有几个鼠标和触摸事件ButtonBase 监听以启动/停止涟漪。 If you use the disableTouchRipple prop, it prevents ButtonBase from trying to start/stop the ripple based on those events .如果您使用disableTouchRipple道具,它会阻止 ButtonBase 根据这些事件尝试启动/停止波纹

Unfortunately disableTouchRipple prevents click and touch animations on the button.不幸的是disableTouchRipple阻止了按钮上的点击和触摸动画。 These can be restored by adding another TouchRipple element explicitly that you control.这些可以通过显式添加您控制的另一个TouchRipple元素来恢复。 My example below shows handling onMouseDown and onMouseUp as a proof-of-concept, but an ideal solution would deal with all the different events that ButtonBase handles.下面的示例显示了将onMouseDownonMouseUp处理为概念验证,但理想的解决方案将处理ButtonBase处理的所有不同事件。

Here's a working example:这是一个工作示例:

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>
  );
}

编辑无条件焦点波纹

We can create a reference to the action of the material-ui Button component and use the action reference within useLayoutEffect to achieve the ripple effect我们可以创建一个对 material-ui Button组件的action的引用,并使用useLayoutEffect中的动作引用来实现波纹效果

import React, { createRef, useLayoutEffect } from "react";
import Button from "@material-ui/core/Button";

function FocusButton(props) {
  const { handleClose } = props;

  const actionRef = createRef();

  useLayoutEffect(() => {
    if (actionRef.current) {
      actionRef.current.focusVisible();
    }
  }, []);

  return (
    <Button action={actionRef} onClick={handleClose}>
      Ok
    </Button>
  );
}

The above FocusButton can be used as a replacement to Button or simply you can add a reference and call the focusVisible() in the trigger method上面的FocusButton可以用作Button的替代品,或者您可以简单地添加引用并在触发方法中调用focusVisible()

Eg:例如:

const buttonRef = createRef();

const handleButton2Click = () => {
    buttonRef.current.focusVisible();
};

.
.
.
.

<Button action={buttonRef} variant="outlined">
        Button 1
</Button>

<Button variant="outlined" color="primary" onClick={handleButton2Click}>
        Button 2
</Button>

You can find the demo in this link您可以在此链接中找到演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM