Как всегда применять стиль focusVisible к сфокусированному компоненту кнопки Material-UI?

Для компонента кнопки Material-UI я хотел бы, чтобы стиль «фокус» выглядел так же, как стиль «focusVisible». Это означает, что я хочу, чтобы он имел такой же видимый волновой эффект, если кнопка была сфокусирована программно или с помощью мыши, как если бы кнопка была сфокусирована с помощью клавиши табуляции.

Обходной путь, который я нашел, заключается в вызове 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

Итак, я могу применить некоторый стиль к кнопке, когда она находится в состоянии «фокус». (Например, я применил границу). Но мне не хватает того, как применить стили. Я попытался поместить className 'Mui-visibleFocus' на кнопку, но это, похоже, не дало эффекта. Есть ли способ получить стили, которые применялись бы, если бы кнопка находилась в состоянии visibleFocus?

Я столкнулся с той же проблемой, жаль, что все еще не работает

stackoverflow 26.03.2021 19:06
5 способов использования оповещений, предупреждений, ошибок, сообщений об успехе в Bootstrap
5 способов использования оповещений, предупреждений, ошибок, сообщений об успехе в Bootstrap
Bootstrap - это популярный front-end фреймворк, который делает веб-разработку проще и быстрее. Использование Bootstrap растет по мере того, как все...
Как сделать меню гамбургера только на CSS
Как сделать меню гамбургера только на CSS
Недавно я делал небольшие изменения на своем сайте , когда я вновь обнаружил меню гамбургера, которое я сделал для него. В нем нет ничего особенного,...
Полеты по миру фронтенда, том 9
Полеты по миру фронтенда, том 9
Мир фронтенда снова растет быстрее, чем население Земли. За всеми новостями и тенденциями в нем становится почти так же трудно уследить, как за...
Создание фильтров для вашего сайта
Создание фильтров для вашего сайта
Фильтры - удобный инструмент в арсенале веб-дизайнера. Они позволяют изменять элементы на странице с помощью всего нескольких строк кода. Эти...
Библиотека Bootstrap
Библиотека Bootstrap
Bootstrap - это бесплатный набор инструментов для разработки веб-приложений с открытым исходным кодом, разработанный компанией Twitter. Написанный на...
Уроки CSS 28
Уроки CSS 28
Здравствуйте, дорогие читатели, я Ферди Сефа Дюзгюн, сегодня мы продолжим с вами уроки css.
2
2
8 215
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

ButtonBase (который Button делегирует ) имеет свойство действия , которое предоставляет возможность установить видимость фокуса для кнопки.

ButtonBase использует для этого хук useImperativeHandle. Чтобы использовать его, вы передаете ссылку в реквизит action, а затем можете позже вызвать actionRef.current.focusVisible().

Однако этого самого по себе недостаточно, потому что есть несколько событий мыши и касания, которые ButtonBase прослушивает , чтобы запустить/остановить пульсацию. Если вы используете реквизит disableTouchRipple, он предотвращает попытки ButtonBase запустить/остановить пульсацию на основе этих событий.

К сожалению, 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.info("Some extra onFocus functionality")}
      >
        Button 2
      </FocusRippleButton>
    </div>
  );
}

Привет Райан, это отлично и делает именно то, что я просил. Но есть одна проблема с использованием этого решения с применением свойства «disableTouchRipple»: теперь у кнопки больше нет анимации кликов. Знаете ли вы, как мне получить доступ к «rippleRef» из ButtonBase, чтобы я мог сам вызвать пульсацию? Или есть обходной путь, чтобы заставить анимацию кликов снова работать?

user3044553 18.12.2020 22:15

Вы получаете анимацию щелчка в том смысле, что рябь фокуса сразу же начинается, когда вы щелкаете; хотя я понимаю, что это не то же самое - нажатие на кнопку, которая уже находится в фокусе, не дает никакой обратной связи. Я не смог найти способ заставить пульсацию фокуса работать на клики без disableTouchRipple (перепробовал несколько способов).

Ryan Cogswell 18.12.2020 22:28

Material-UI не предоставляет никакого доступа к rippleRef. Если вы попытаетесь передать его через TouchRippleProps, он сломается ButtonBase, так как потеряет доступ к rippleRef. Я не вижу способа сделать это без изменений в Material-UI.

Ryan Cogswell 18.12.2020 22:50

Кажется, ты прав. Я пытался найти способ получить доступ к rippleRef, но я не думаю, что он есть... К сожалению. Теперь мне интересно, можно ли использовать отдельный элемент <TouchRipple/> для самостоятельного создания анимации?

user3044553 18.12.2020 23:02

@user3044553 user3044553 Да, можно добавить отдельный элемент <TouchRipple> для анимации щелчка. Я обновил свой ответ, включив в него чрезмерно упрощенную (не учитывающую все события, которые обрабатывает ButtonBase) версию этого.

Ryan Cogswell 18.12.2020 23:39

Мы можем создать ссылку на action компонента material-ui Button и использовать ссылку на действие внутри 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>

Вы можете найти демо по этой ссылке

Другие вопросы по теме