css 带有onBlur事件的React - ul阻止onClick在li上触发

xqkwcwgp  于 2024-01-09  发布在  React
关注(0)|答案(5)|浏览(183)

我已经创建了一个移动的菜单,根据状态切换打开和关闭。一旦它打开,我希望用户能够通过点击ul外的任何地方关闭菜单。
我将ul上的tabIndex属性设置为0,这使ul具有“焦点”。我还向ul添加了一个onBlur事件,它触发隐藏ul的状态更改(dropdownExpanded = false)。

  1. <ul tabIndex="0" onBlur={this.hideDropdownMenu}>
  2. <li onClick={this.handlePageNavigation}>Page 1</li>
  3. <li onClick={this.handlePageNavigation}>Page 2</li>
  4. <li onClick={this.handlePageNavigation}>Page 3</li>
  5. </ul>

字符串
然而,当我实现这个修复时,我在每个li元素上的onClick事件都无法触发。
我知道事件冒泡时发生了一些事情,但我不知道如何修复它。有人能帮忙吗?
注意事项:
我知道你可以在ul下面创建一个透明的div,它跨越整个视口,然后只需要添加一个onClick even到那个div就可以改变状态,但是我读到了这个tabIndex/focus解决方案on Stack Overflow,我真的很想让它工作。
以下是代码的更完整视图(用户可以选择自己的国家,这会更新ui):

  1. const mapStateToProps = (state) => {
  2. return {
  3. lang: state.lang
  4. }
  5. }
  6. const mapDispatchToProps = (dispatch) => {
  7. return { actions: bindActionCreators({ changeLang }, dispatch) };
  8. }
  9. class Header extends Component {
  10. constructor() {
  11. super();
  12. this.state = {
  13. langListExpanded: false
  14. }
  15. this.handleLangChange = this.handleLangChange.bind(this);
  16. this.toggleLangMenu = this.toggleLangMenu.bind(this);
  17. this.hideLangMenu = this.hideLangMenu.bind(this);
  18. }
  19. toggleLangMenu (){
  20. this.setState({
  21. langListExpanded: !this.state.langListExpanded
  22. });
  23. }
  24. hideLangMenu (){
  25. this.setState({
  26. langListExpanded: false
  27. });
  28. }
  29. handleLangChange(e) {
  30. let newLang = e.target.attributes['0'].value;
  31. let urlSegment = window.location.pathname.substr(7);
  32. // blast it to shared state
  33. this.props.actions.changeLang( newLang );
  34. // update browser route to change locale, but stay where they are at
  35. browserHistory.push(`/${ newLang }/${ urlSegment }`);
  36. //close dropdown menu
  37. this.hideLangMenu();
  38. }
  39. compileAvailableLocales() {
  40. let locales = availableLangs;
  41. let selectedLang = this.props.lang;
  42. let markup = _.map(locales, (loc) => {
  43. let readableName = language[ selectedLang ].navigation.locales[ loc ];
  44. return (
  45. <li
  46. key={ loc }
  47. value={ loc }
  48. onMouseDown={ this.handleLangChange }>
  49. { readableName }
  50. </li>
  51. );
  52. });
  53. return markup;
  54. }
  55. render() {
  56. let localeMarkup = this.compileAvailableLocales();
  57. return (
  58. <section className="header row expanded">
  59. < Navigation />
  60. <section className="locale_selection">
  61. <button
  62. className="btn-locale"
  63. onClick={this.toggleLangMenu}>
  64. {this.props.lang}
  65. </button>
  66. <ul
  67. className={this.state.langListExpanded ? "mobile_open" : " "}
  68. value={ this.props.lang }
  69. tabIndex="0"
  70. onBlur={this.hideLangMenu}>
  71. >
  72. { localeMarkup }
  73. </ul>
  74. </section>
  75. </section>
  76. )
  77. }
  78. }

kqhtkvqz

kqhtkvqz1#

尝试使用onMouseDown而不是onClick。

zzwlnbp8

zzwlnbp82#

关键是onBlur正在触发重新渲染,这似乎会导致浏览器不跟进onClick:https://github.com/facebook/react/issues/4210
但是如果你检查onBlur事件,你可以找到一些关于发生了什么的信息,event.relatedTarget被填充,你可以使用这些信息来检测onBlur何时被onClick触发,并链接你需要做的任何事情。

qlzsbp2j

qlzsbp2j3#

我刚刚在一个面包屑链接数组中遇到了这个问题,其中onBlur处理程序导致重新渲染,阻止链接点击工作。实际问题是react每次都会重新生成链接元素,所以当它重新渲染时,它会从鼠标下交换链接,这导致浏览器忽略点击。
修复方法是将key属性添加到我的链接中,以便react可以重用相同的DOM元素。

  1. <ol>
  2. {props.breadcrumbs.map(crumb => (
  3. <li key={crumb.url}>
  4. <Link to={crumb.url} >
  5. {crumb.label}
  6. </Link>
  7. </li>
  8. ))}
  9. </ol>

字符串

krcsximq

krcsximq4#

我也遇到了这个问题。对我有效的是这个弗兰肯斯坦式的解决方案:

  1. onBlur={e => {
  2. // regular onBlur code
  3. onBlurHandler(); // replace with your own onBlur event code handling
  4. // code to trigger button click event
  5. if(e.relatedTarget?.className.includes('save-button'){ // have to add a class to your save button like "save-button"
  6. const target = e.relatedTarget ? (e.relatedTarget as HTMLButtonElement): null; // can omit 'as HTMLButtonElement' if not in typescript
  7. target?.click(); // can omit the '?' if not in typescript
  8. }
  9. }}

字符串
相当丑陋,但它的工作!希望它有助于其他一些可怜的灵魂困惑这一点。

i34xakig

i34xakig5#

我也有类似的问题,这里的建议都不太合适,所以我最终使用了setTimeout来稍微延迟blur事件。
在我的例子中,我使用的是一个输入组件,它在右边有一个可点击的“提交”按钮。只有当父对象被悬停在其中,和/或输入本身接收到焦点时,输入和按钮才会呈现。点击按钮会导致输入的onBlur触发,从而停止点击处理程序的运行。添加一个小的setTimeout解决了这个问题。

  1. import { Fragment,useState } from "react";
  2. import { FaArrowCircleRight, } from "react-icons/fa";
  3. import {
  4. InputGroup,
  5. InputRightElement,
  6. Input,
  7. Box,
  8. } from "@chakra-ui/react";
  9. const HoverInput = props => {
  10. const [st_hovering,sst_hovering] = useState(false);
  11. const [st_focused,sst_focused] = useState(false);
  12. const [st_value,sst_value] = useState(props.savedValue || "");
  13. let handleChange = event=>{
  14. sst_value(event.target.value);
  15. };
  16. let handleSubmit = async (event)=>{
  17. event.preventDefault();
  18. // do stuff
  19. }; // handleSubmit
  20. return (
  21. <Box
  22. onMouseEnter={event=>sst_hovering(true)}
  23. onMouseLeave={event=>{
  24. if ( !st_focused ) {
  25. sst_hovering(false);
  26. }
  27. }}
  28. >
  29. {
  30. !st_hovering ? (
  31. <Fragment>{st_value}</Fragment>
  32. ) : (
  33. <Box>
  34. <InputGroup>
  35. <Input
  36. value={st_value}
  37. onChange={handleChange}
  38. onFocus={event=>sst_focused(true)}
  39. onBlur={event=>{
  40. setTimeout(()=>{
  41. sst_focused(false);
  42. }, 100);
  43. }}
  44. />
  45. <InputRightElement>
  46. <FaArrowCircleRight
  47. cursor="pointer"
  48. onClick={handleSubmit}
  49. />
  50. </InputRightElement>
  51. </InputGroup>
  52. </Box>
  53. )
  54. }
  55. </Box>
  56. );
  57. }
  58. export default HoverInput;

字符串

展开查看全部

相关问题