如何将事件传递给 JavaScript class 中的方法?

How to pass event into method in a JavaScript class?

这只是一个示例,我想我已经完成了使用或不使用箭头函数的所有操作,但仍然一无所获。我需要添加到方法 event.altKey,但我如何才能像往常一样将 event 传递给它而无需 class?

HTML:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      .selected {
        background: #0f0;
      }
      li {
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    Кликни на элемент списка, чтобы выделить его.
    <br/>
    <ul id="ul">
      <li>Кристофер Робин</li>
      <li>Винни Пух</li>
      <li>Тигра</li>
      <li>Кенга</li>
      <li>Кролик. Просто Кролик.</li>
    </ul>
  <script src="script.js"></script>
  </body>
</html>

我认为应该有效但无效的方法:

window.addEventListener('load', function(){
  class List{
    constructor(){
      this.lists = document.querySelectorAll('li');

      this.lists.forEach((list) => {
        list.addEventListener('click', (event) => this.click_green);
        list.addEventListener('onmousedown', (event) => this.no_select_text);
      });
    }

    no_select_text(event){
      event.preventDefault;
      return false;
    }

    click_green(event){
      if (event.ctrlKey || event.metaKey)
      {
        this.classList.add('selected');
        return;
      }
      let allLists = this.parentNode.querySelectorAll('li');
      allLists.forEach(function(list){
        list.classList.remove('selected');
      });
      this.classList.add('selected');
    }
  }
  new List;
});

解决你的问题

window.addEventListener('load', function () {
  class List {
    constructor() {
      this.lists = document.querySelectorAll('li');

      this.lists.forEach((list) => {
        list.addEventListener('click', (event) => {
          this.click_green(event)
        });
        list.addEventListener('onmousedown', (event) => {
          this.no_select_text
        });
      });
    }

    no_select_text(event) {
      event.preventDefault;
      return false;
    }

    click_green(event) {
      if (event.ctrlKey || event.metaKey) {
        event.target.classList.add('selected');
        return;
      }
      let allLists = event.target.parentNode.querySelectorAll('li');
      allLists.forEach(function (list) {
        list.classList.remove('selected');
      });
      event.target.classList.add('selected');
    }
  }
  new List;
});
  • 第一个任务是制作代码运行。
  • 第二个任务将详细解释实际发生的情况以及为什么根本不需要 运行 具有 JavaScript class 的方法。

class ListItems{
  constructor(listItemQuery) {
    const listItems = this;

    listItemQuery.forEach((listItem) => {
      listItem.addEventListener('click', listItems.clickGreen, false);
      listItem.addEventListener('onmousedown', listItems.noSelectText, false);
    });
  }
  noSelectText(evt) {
    evt.preventDefault;
    return false;
  }

  clickGreen(evt) {
    const listItem = evt.currentTarget;

    if (evt.ctrlKey || evt.metaKey) {
      listItem.classList.add('selected');
      return;
    }
    const firstLevelListItems = Array.from(listItem.parentNode.children);

    firstLevelListItems.forEach(function(item) {
      item.classList.remove('selected');
    });
    listItem.classList.add('selected');
  }
}

function initializeListItems() {
  new ListItems(document.querySelectorAll('li'));
}
window.addEventListener('load', initializeListItems, false);
.as-console-wrapper { max-height: 100%!important; top: 0; }
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      .selected {
        background: #0f0;
      }
      li {
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    Кликни на элемент списка, чтобы выделить его.
    <br/>
    <ul id="ul">
      <li>Кристофер Робин</li>
      <li>Винни Пух</li>
      <li>Тигра</li>
      <li>Кенга</li>
      <li>Кролик. Просто Кролик.</li>
    </ul>
  </body>
</html>

为了更好地识别 OP 提供的示例的不同部分,现在的可执行代码被分解了。

如果使用 JS classes,最好让构造函数只负责最必要的引导部分。因此我们有一个初始化步骤,将 DOM 查询直接传递给构造函数。

接下来,命名 class List 是一种误导,因为 OP 主要将其用作结构元素,该元素具有专门操作列表项的功能。让我们将其重命名为 ListItems.

然后每个 HTMLLIElement 添加两个自己的事件处理程序。使用 OP 的示例代码,它是两个箭头函数,每个接受一个 event 参数 但不将它 传递给预期的 class方法。

代码可能已经修复了......

list.addEventListener('click', (event) => this.click_green(event));
list.addEventListener('onmousedown', (event) => this.no_select_text(event));

...但更直观的方法是直接将 class 方法分配为事件处理程序,例如 ...

listItem.addEventListener('click', this.clickGreen, false);
listItem.addEventListener('onmousedown', this.noSelectText, false);

由于这两种方法的 this 上下文,已经走到这一步,人们开始与 class 方法作斗争。

click_green(event) { ... this.classList.add('selected') ... } 中的

this 不是 HTMLLIElement,但 this 始终是 OP 的 List class 的唯一实例在加载时创建。

与固定代码示例一样,evt 对象提供了一个 target 和一个 currentTarget 对象。对于给定的 HTML-结构,两者都包含对列表项的引用,例如点击。 只要列表项不再仅包含文本节点,而且还是其他可能作为事件触发目标的 HTML 元素的父元素,evt.currentTarget 就是唯一的真实来源,因为它的两个添加事件处理程序。

现在确定被点击的列表项不希望只查询父列表的所有列表项,因为列表项可能是其他列表的容器等等。相反,一个人想要获得列表项的所有兄弟姐妹。 通过 parentNode 定位他们应该知道 parentNode.childNodes 确实列出了任何节点,包括文本节点,例如来自提供的示例代码的新行。一个总是在 parentNode.children 的保存端,它是一个只列出元素节点的 HTMLCollection。 将这样的集合转换为数组... Array.from(listItem.parentNode.children); ...对于通过数组方法处理其项目是必要的。

关于如何使 OP 的代码 运行 符合预期,没有什么可说的了。

并且希望对代码有更好的理解,甚至可以摆脱 class 语法,用另一种如何构建代码的方法取而代之...

// list item module
//
// - written as immediately invoked function expression ...
// - ... mainly for encapsulation of domain specific code.
//
const ListItems = (function () {

  function preventSelection(evt) {
    evt.preventDefault;
    return false;
  }

  function selectItem(evt) {
    const listItem = evt.currentTarget;

    if (evt.ctrlKey || evt.metaKey) {

      listItem.classList.add('selected');

    } else {
      const firstLevelListItems = Array.from(listItem.parentNode.children);

      firstLevelListItems.forEach((item) => {
        item.classList.remove('selected');
      });
      listItem.classList.add('selected');
    }
  }

  function initializeListItems() {
    document.querySelectorAll('li').forEach((listItem) => {
      listItem.addEventListener('click', selectItem, false);
      listItem.addEventListener('onmousedown', preventSelection, false);
    })
  }

  // the module:
  return {
    initialize: initializeListItems
  };

}());

// another task ... 
window.addEventListener('load', ListItems.initialize, false);
.as-console-wrapper { max-height: 100%!important; top: 0; }
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      .selected {
        background: #0f0;
      }
      li {
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    Кликни на элемент списка, чтобы выделить его.
    <br/>
    <ul id="ul">
      <li>Кристофер Робин</li>
      <li>Винни Пух</li>
      <li>Тигра</li>
      <li>Кенга</li>
      <li>Кролик. Просто Кролик.</li>
    </ul>
  </body>
</html>