簡體   English   中英

如何始終在焦點 Material-UI 按鈕組件上應用 focusVisible 樣式?

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

對於 Material-UI Button 組件,我希望“focus”樣式看起來與“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

因此,當按鈕處於“焦點”state 時,我可以對按鈕應用一些樣式。 (例如,我應用了邊框)。 但我錯過了如何讓 styles 申請。 我嘗試將 className 'Mui-visibleFocus' 放在 Button 上,但這似乎沒有效果。 如果按鈕位於可見焦點 state 中,是否有某種方法可以獲得 styles?

ButtonBaseButton 委托給)有一個action屬性,可以設置按鈕的焦點可見 state

ButtonBase為此利用了useImperativeHandle 鈎子 為了利用它,你將一個 ref 傳遞給action prop,然后你可以稍后調用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>
  );
}

編輯無條件焦點波紋

我們可以創建一個對 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>
  );
}

上面的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>

您可以在此鏈接中找到演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM