简体   繁体   English

使元素内部的按钮可单击,同时元素本身也可单击

[英]Make a button inside an element clickable while the element itself is also clickable

I have a simple sidebar, that has a bunch of list items in it, and a button right next to the list item, like so: 我有一个简单的侧边栏,其中有很多列表项,并且在列表项旁边有一个按钮,如下所示:

在此处输入图片说明

I attached a click handler to the <li> element like in the code below: 我将点击处理程序附加到<li>元素,如下面的代码所示:

<li className="note" onClick={()=> props.selectNote(props.note)} role="button">
    <button className="delete-note" onClick={() => console.log('Fired')}>Delete dis</button>
    <span className="updated-at">2hr</span>
    <div className="note-content">
        <h4 className="note-title">
            {title}
        </h4>
        <p className="note-preview">
            {notePreview.substr(0, 80)}...
        </p>
    </div>
</li>

But as expected, when I click the button next to it, the actual li gets clicked and not the button inside it. 但是正如预期的那样,当我单击旁边的按钮时,实际的li会被单击,而不是其内部的按钮。 I think this is some sort of issue with how the event bubbles, and how it's a bad practice to attach onClick handlers to non-interactive elements (My ESLint says that). 我认为这与事件如何冒泡以及将onClick处理程序附加到非交互式元素(这是我的ESLint所说)的不良做法有关。

What I want instead : 我想要的是

  1. When the list item gets clicked, the attached onClick event fire. 单击列表项后,将触发附加的onClick事件。
  2. When the button gets clicked, fire the onClick event on the button, and not the <li> . 单击按钮后,在按钮上触发onClick事件,而不是<li>
<li data-is-parent className="note" onClick={(e)=> e.target.getAttribute('data-is-parent') && props.selectNote(props.note)} role="button">
    <button className="delete-note" onClick={() => console.log('Foreground Fired')}>Delete dis</button>
    <span className="updated-at">2hr</span>
    <div className="note-content">
        <h4 className="note-title">
            {title}
        </h4>
        <p className="note-preview">
            {notePreview.substr(0, 80)}...
        </p>
    </div>
</li>

Hack incoming! 哈克来了!

I solved this by adding a name attribute to the elements that I didn't want to trigger the main click event: 我通过向不想触发主点击事件的元素添加name属性来解决此问题:

handleClick = (e) => {
    if(e.target.name === 'deleteButton') {
        e.preventDefault();
        e.stopPropagation();
    }else {
        this.props.selectNote(this.props.note)
    }
}


<li className="note" onClick={this.handleClick} role="button">
    <button className="delete-note" name="deleteButton" onClick={() => console.log('Fired')}>Delete dis</button>
    <span className="updated-at">2hr</span>
    <div className="note-content">
        <h4 className="note-title">
            {title}
        </h4>
        <p className="note-preview">
            {notePreview.substr(0, 80)}...
        </p>
    </div>
</li>

You need to check which element triggered the event, and prevent it if it was the button. 您需要检查哪个元素触发了事件,如果是按钮,则阻止它。

For Button onClick the default click parameter event args is passed as 'event'. 对于Button onClick,默认的单击参数事件args作为“事件”传递。 Use the event.stopPropagation() to stop propogate the click event back to li. 使用event.stopPropagation()停止将click事件传播回li。

<li className="note" onClick={()=> props.selectNote(props.note)} role="button">
<button className="delete-note" onClick={(event) => event.stopPropagation(); console.log('Fired')}>Delete dis</button>
<span className="updated-at">2hr</span>
<div className="note-content">
    <h4 className="note-title">
        {title}
    </h4>
    <p className="note-preview">
        {notePreview.substr(0, 80)}...
    </p>
</div>

What you need is to prevent further propagation of the current event (click) in the capturing and bubbling phases . 您需要防止在捕获和冒泡阶段进一步传播当前事件(点击)。

See the example on event propagation: https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation 请参阅事件传播示例: https : //developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model/Examples#Example_5 : _Event_Propagation

you should wrap your li in a div like below 您应该将li包裹在下面的div中

<div>
    <li className="note" onClick={()=> props.selectNote(props.note)} role="button">
        <span className="updated-at">2hr</span>
        <div className="note-content">
            <h4 className="note-title">
                {title}
            </h4>
            <p className="note-preview">
                {notePreview.substr(0, 80)}...
            </p>
        </div>
    </li>
    <button className="delete-note" onClick={() => console.log('Fired')}>Delete dis </button>
</div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM