【问题标题】:Javascript - How to Remove DOM elements using click events and classes?Javascript - 如何使用点击事件和类删除 DOM 元素?
【发布时间】:2016-05-05 11:12:28
【问题描述】:

我在使用parentNode.removeChild() 时遇到了一些困难。我在无序列表中有一个“项目”列表,每个项目都有自己的删除按钮。我正在尝试将单击事件绑定到每个单独的按钮,该按钮将删除它各自的父“项目”。

到目前为止我的代码:

<ul class="list">
  <h2>This is a list</h2>
  <li class="item">
    <h3>Some Item</h3>
    <button class="delete">Delete</div>
  </li>
  <li class="item">
    <h3>Some Item</h3>
    <button class="delete">Delete</div>
  </li>
  <li class="item">
    <h3>Some Item</h3>
    <button class="delete">Delete</div>
  </li> 
</ul>

var childElements = document.getElementsByClassName('item');
var buttonElement = document.getElementsByClassName('delete');

function deleteItem(buttonsClass, childClass) {
  for (var i=0;i<buttonsClass.length;i++) {
    var child = childClass[i];
    buttonsClass[i].addEventListener('click', function(child) {
       childClass[i].parentNode.removeChild(childClass[i]);
    }, false);
  }    
}

deleteItem(buttonElement, childElements);

我知道使用 jQuery 有一种更简单的方法可以做到这一点,但我真的想用普通的 javascript 来解决这个问题。感谢您的所有帮助。

【问题讨论】:

  • 您能描述一下您遇到的错误或意外行为吗?
  • 如果给元素分配ID,不使用for循环删除元素会更容易;也for循环删除所有元素。

标签: javascript for-loop addeventlistener removechild


【解决方案1】:

这是event delegation 的完美案例。根本不需要 jQuery:

(function(window, htmlElement) {

    'use strict';

    htmlElement.addEventListener("click", handleClick, false);

    function handleClick(event) {
        if (event.target.classList.contains("delete")) {
            event.preventDefault();
            removeItem(event.target);
        }
    }

    function removeItem(button) {
        var item = getItem(button),
            confirmMessage;

        if (item) {
            confirmMessage = item.getAttribute("data-confirm");

            if (!confirmMessage || window.confirm(confirmMessage)) {
                item.parentNode.removeChild(item);
            }
        }
        else {
            throw new Error("No item found");
        }
    }

    function getItem(button) {
        var element = button.parentNode,
            item = null;

        while (element) {
            if (element.nodeName === "LI" || element.nodeName === "TR") {
                item = element;
                break;
            }

            element = element.parentNode;
        }

        return item;
    }

})(this, this.document.documentElement);

无论您有多少个删除按钮,您都拥有整个页面的一键式处理程序。这也适用于列表项或表格行,通过在按钮上指定 data-confirm 属性,它会在删除之前弹出一个确认框。

<button type="button" class="delete"
        data-confirm="Are you sure you want to delete this item?">
    Delete
</button>

您也可以轻松更改此设置,使其使用另一个属性来查找删除按钮:

<button type="button" class="delete"
        data-delete
        data-confirm="...">
    Delete
</button>

只需将handleClick函数中if语句的条件改为:

if (event.target.hasAttribute("data-delete")) {
    event.preventDefault();
    removeItem(event.target);
}

这将您的行为与样式分离。您可以使用 delete 类名来设置样式,并使用 data-delete 属性来设置 JavaScript 行为。如果您出于任何原因需要更改 CSS 删除类的名称,或者使用不同的类,因为您决定使用像 Bootstrap 这样的第三方 CSS 框架,那么您不需要更改一行 JavaScript。

这里的最后一个优点是单击处理程序附加到document.documentElement 对象,该对象在JavaScript 开始执行时可用并表示&lt;html&gt; 元素。不需要 jQuery 的文档就绪事件处理程序。只需附加点击处理程序并在页面上的任意位置导入脚本即可。

【讨论】:

  • 谢谢,这是一个非常优雅的解决方案,完全符合我的要求。复杂性略高于我的技能水平,但现在我知道它有效,我可以剖析它的组成部分,直到我理解它的作用。然后我将它作为对象方法尝试。
  • 附录,关于事件委托的文章真的很有帮助。谢谢!
  • 我找不到对您在 classList 对象上使用的“包含”方法的任何引用。这个方法从何而来?
  • 请参阅来自 Mozilla 开发者网络的 Element.classList
  • You Might Not Need jQuery 是确定浏览器对许多新 HTML5/CSS3 功能(包括 JavaScript API)的兼容性的有用资源。
【解决方案2】:

问题是您在单击元素时调用的childClass[i] 并不是您在定义函数时所期望的。 你应该使用event.target 来捕捉被点击的元素

var childElements = document.getElementsByClassName('item');
var buttonElement = document.getElementsByClassName('delete');

var _handler = function(e) {
     e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}

function deleteItem(buttonsClass, childClass) {
  for (var i=0;i<buttonsClass.length;i++) {
    buttonsClass[i].addEventListener('click', _handler, false);
  }    
}

deleteItem(buttonElement, childElements);

-- 编辑--

如果你想使用原来的方法,那么你可以这样解决:

function deleteItem(buttonsClass, childClass) {
  for (var i=0;i<buttonsClass.length;i++) {
    (function(child) {
        buttonsClass[i].addEventListener('click', function(e) {
           child.parentNode.removeChild(child);
        }, false);
    })(childClass[i]);
  }    
}

通过封装(function(encapsulatedChild) { })(child),您可以将 child 的值存储在一个在下一个周期中不会改变的上下文中。

【讨论】:

  • 问题,使用你封装的方法。 “child”参数引用了什么?
  • 您使用(function(arg) { ... }) 创建一个函数,然后立即执行它并传递您想要的参数(childClass[i])。通过这种方式,您的 childClass[i] 引用被复制到 child var 中。这个var只存在于函数上下文中,所以不会在下一个循环中被覆盖
【解决方案3】:

看起来您想将单击事件绑定到删除按钮,并在该事件上删除该项目。

您需要获取子类的单个 buttonsClass 元素。

function deleteItem( childElements ) 
{
   Array.prototype.slice.call( childElements ).forEach( function( item ){
      var deleteChildren = item.getElementsByClassName( "delete" );
      Array.prototype.slice.call( deleteChildren ).forEach( function( deleteBtn ){
        deleteBtn.addEventListener('click', function() 
        {
            this.parentNode.removeChild( this );
        }, false);        
      });
   });
}

或者更简单,只需在单击哪个父 item 将被删除时传递按钮列表

function deleteItem( buttonElement ) 
{
   Array.prototype.slice.call( buttonElement ).forEach( function( button ){
        button.addEventListener('click', function() 
        {
            this.parentNode.removeChild( this );
        }, false);        
   });
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-31
    • 1970-01-01
    • 2020-07-01
    • 2018-02-18
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    相关资源
    最近更新 更多