#javascript #html #reactjs #firefox #dom
#javascript #HTML #reactjs #firefox #dom
Вопрос:
Следующее работает в Firefox 80.0 и Chromium 84.0.4147.89.
const fieldset = document.getElementById("fieldset");
const toggle = document.getElementById("toggle");
toggle.addEventListener("change", () => {
if (fieldset.hasAttribute("disabled")) {
fieldset.removeAttribute("disabled");
} else {
fieldset.setAttribute("disabled", true);
}
});
<form action="#">
<fieldset id="fieldset">
<legend>
<label>toggle <input id="toggle" type="checkbox" /></label>
</legend>
<input />
</fieldset>
</form>
Однако, когда я пытаюсь сделать что-то подобное в React, это не работает в Firefox. Событие onChange, по-видимому, не срабатывает, как только набор полей отключен.
function App() {
const [disabled, setDisabled] = React.useState(false);
const toggleDisabled = React.useCallback(() => {
setDisabled((disabled) => !disabled);
}, []);
return (
<form action="#">
<fieldset disabled={disabled}>
<legend>
<label>
toggle <input onChange={toggleDisabled} type="checkbox" />
</label>
</legend>
<input />
</fieldset>
</form>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
В статье MDN fieldset говорится:
[когда элемент fieldset отключен] Обратите внимание, что элементы формы внутри
<legend>
элемента не будут отключены.
W3C (пример B) и WHATWG также упоминают, что содержимое <legend>
не должно быть отключено.
Поэтому я считаю, что две части кода должны вести себя одинаково: я должен иметь возможность переключать disabled
атрибут с помощью флажка.
Как я могу добиться такого же эффекта в React на Firefox 80.0 ?
Ответ №1:
Такое поведение, похоже, ожидается браузером в соответствии с 2 строками ранее в этом абзаце.
disabled
Если этот логический атрибут установлен, все элементы управления формой, которые являются потомками<fieldset>
, отключены, что означает, что они недоступны для редактирования и не будут отправлены вместе с . Они не будут получать никаких событий просмотра, таких как щелчки мыши или события, связанные с фокусом. По умолчанию браузеры отображают такие элементы управления серым цветом. Обратите внимание, что элементы формы внутри элемента не будут отключены. — MDN
Кажется, что Firefox делает именно то, что он описывает, что он должен делать.
Решением здесь было бы просто поместить <input>
вне набора полей, чтобы на него не повлияло disabled
свойство.
Редактировать
Ваш комментарий о прослушивании событий выше в DOM заставил меня задуматься. Как насчет того, чтобы обойти это, связав свой собственный прослушиватель событий с good ol addEventListener
, в сочетании с useRef
и useEffect
крючками. Создайте ссылку на флажок и прослушайте событие изменения после первого рендеринга. Теперь событие прослушивает сам ввод.
Этот «обходной путь», похоже, работает в FF.
function App() {
const [disabled, setDisabled] = React.useState(false);
const toggleElement = React.useRef(null)
const toggleDisabled = React.useCallback(() => {
setDisabled(disabled => !disabled);
}, []);
React.useEffect(() => {
toggleElement.current.addEventListener('change', toggleDisabled);
}, []);
return (
<form action="#">
<fieldset disabled={disabled}>
<legend>
<label>
toggle <input ref={toggleElement} type="checkbox" />
</label>
</legend>
<input />
</fieldset>
</form>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Комментарии:
1. Спасибо за ваш ответ, но я не согласен с вашей интерпретацией статьи MDN. Я добавил еще пару ссылок на мой вопрос (W3C и WHATWG), обе из которых показывают, что спецификация определяет, что содержимое
<legend>
не отключено.2. @TomFenech любопытно. Я просмотрел ваши примеры. Второй пример W3C действительно работает в Firefox, но реализация с React.js сбой. Может ли быть какая-то добавленная логика из React.js что касается событий в формах?
3. Я думаю, что проблема в том, что React подключает прослушиватели событий выше в DOM, а Firefox предотвращает всплывание событий из отключенного набора полей. У меня такое ощущение, что «ответом» на мой вопрос будет то, что «вы не можете сделать это в Firefox», к сожалению.
4. @TomFenech отличная командная работа! Ваш комментарий заставил меня кое о чем задуматься. Проверьте отредактированную версию в FF.
5. Да, это работает! Я собираюсь немного оставить этот вопрос открытым, чтобы посмотреть, есть ли у кого-нибудь другие идеи, но это достойный обходной путь, спасибо.