如何始终在聚焦的 Material-UI 按钮组件上应用 focusVisible 样式?
How to always apply focusVisible styling on a focused Material-UI Button component?
对于 Material-UI 按钮组件,我希望“focus”样式看起来与“focusVisible”样式相同。这意味着如果按钮以编程方式聚焦或使用鼠标聚焦,我希望它具有与使用 tab 键聚焦按钮相同的波纹效果。
我发现的一种解决方法是在元素获得焦点之前调用 dispatchEvent(new window.Event("keydown"))
,从而使键盘成为最后使用的输入类型。这将使按钮看起来像我想要的那样,直到 onMouseLeave 事件(来自 MUI )或另一个鼠标事件被触发,导致可见焦点消失。
我已经想出如何像这样更改组件的焦点样式:
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
因此,当按钮处于“焦点”状态时,我可以对其应用一些样式。 (例如,我应用了边框)。但我缺少如何应用样式。我试过将 className 'Mui-visibleFocus' 放在 Button 上,但这似乎没有效果。如果 Button 处于 visibleFocus 状态,是否有一些方法可以应用样式?
ButtonBase
(其中 Button
delegates to) has an action prop which provides the ability to set the button's focus-visible state.
ButtonBase
为此利用了 useImperativeHandle hook。为了利用它,您将 ref 传递到 action
属性中,然后您可以稍后调用 actionRef.current.focusVisible()
.
然而,这本身是不够的,因为有几个鼠标和触摸事件ButtonBase listens to in order to start/stop the ripple. If you use the disableTouchRipple
prop, it prevents ButtonBase from trying to start/stop the ripple based on those events。
不幸的是,disableTouchRipple
阻止了按钮上的点击和触摸动画。这些可以通过添加另一个您明确控制的 TouchRipple
元素来恢复。我下面的示例显示了处理 onMouseDown
和 onMouseUp
作为概念验证,但理想的解决方案将处理 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>
);
}
我们可以创建对material-uiButton
组件的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>
);
}
上面的FocusButton
可以用来替代Button
,或者你可以简单地添加一个引用并在触发方法中调用focusVisible()
例如:
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>
您可以在此找到演示 link
对于 Material-UI 按钮组件,我希望“focus”样式看起来与“focusVisible”样式相同。这意味着如果按钮以编程方式聚焦或使用鼠标聚焦,我希望它具有与使用 tab 键聚焦按钮相同的波纹效果。
我发现的一种解决方法是在元素获得焦点之前调用 dispatchEvent(new window.Event("keydown"))
,从而使键盘成为最后使用的输入类型。这将使按钮看起来像我想要的那样,直到 onMouseLeave 事件(来自 MUI
我已经想出如何像这样更改组件的焦点样式:
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
因此,当按钮处于“焦点”状态时,我可以对其应用一些样式。 (例如,我应用了边框)。但我缺少如何应用样式。我试过将 className 'Mui-visibleFocus' 放在 Button 上,但这似乎没有效果。如果 Button 处于 visibleFocus 状态,是否有一些方法可以应用样式?
ButtonBase
(其中 Button
delegates to) has an action prop which provides the ability to set the button's focus-visible state.
ButtonBase
为此利用了 useImperativeHandle hook。为了利用它,您将 ref 传递到 action
属性中,然后您可以稍后调用 actionRef.current.focusVisible()
.
然而,这本身是不够的,因为有几个鼠标和触摸事件ButtonBase listens to in order to start/stop the ripple. If you use the disableTouchRipple
prop, it prevents ButtonBase from trying to start/stop the ripple based on those events。
不幸的是,disableTouchRipple
阻止了按钮上的点击和触摸动画。这些可以通过添加另一个您明确控制的 TouchRipple
元素来恢复。我下面的示例显示了处理 onMouseDown
和 onMouseUp
作为概念验证,但理想的解决方案将处理 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>
);
}
我们可以创建对material-uiButton
组件的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>
);
}
上面的FocusButton
可以用来替代Button
,或者你可以简单地添加一个引用并在触发方法中调用focusVisible()
例如:
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>
您可以在此找到演示 link