使用回调函数和参数添加和删除eventListeners

时间:2020-03-27 09:07:27

标签: javascript

我有一个导航,其中包含多个事件侦听器:clickhover。此事件侦听器可以更改,例如在浏览器上调整大小。我将事件侦听器添加到我自己的方法中,如果应重新初始化侦听器,则会调用该方法。我在以下课程中遇到的问题:removeEventListener无法正常工作。因此,重新初始化会同时触发clickhover

class Navigation {
	constructor(element) {
		this.element = element;
		this.changeButton = this.element.querySelector("button");
		this.version = "hover";
		this.navItemElements = Array.from(this.element.querySelectorAll(".nav-item"));
		this.navItems = this.createNavItems(this.navItemElements);
		this.clickHandler = (event) => this.navItemHoverHandler(event);
		this.changeButton.addEventListener("click", () => {
			this.isHoverVersion = !(this.isHoverVersion);
			console.log("Change trigger. Is hover version --> " + this.isHoverVersion);
			this.initListeners();
		});
		this.clickHandler = (event, navItem) => this.navItemClickHandler(event, navItem);
		this.hoverHandler = (event, navItem) => this.navItemHoverHandler(event, navItem);
		this.initListeners();
	}

	initListeners() {

		console.log("Init listeners");
		console.log(this.navItems);

		if (this.isHoverVersion) {
			this.navItems.forEach((navItem) => {
				console.log(navItem);
				navItem.link.addEventListener('mouseover', e => this.hoverHandler(e, navItem));
				navItem.link.addEventListener('mouseout', e => this.hoverHandler(e, navItem));
				navItem.link.removeEventListener('click',this.clickHandler);
			})
		} else {
			this.navItems.forEach((navItem) => {
				navItem.link.addEventListener('click', e => this.clickHandler(e, navItem));
				navItem.link.removeEventListener('mouseover', this.hoverHandler);
				navItem.link.removeEventListener('mouseout', this.hoverHandler);
			})
		}
	}

	navItemClickHandler(event, navItem) {
		event.preventDefault();
		console.log('Click handler executed');
		console.log(navItem);
	}

	navItemHoverHandler(event, navItem) {
		event.preventDefault();
		console.log('Hover handler executed');
		console.log(navItem);
	}

	createNavItems(navItemElements) {
		let navItems = [];
		navItemElements.forEach((itemElement) => {
			navItems.push(this.createNavItemObject(itemElement));
		});
		return navItems;
	}

	createNavItemObject(navItem) {
		let container = navItem;
		let link = navItem.querySelector("a");
		return  {
			container: container,
			link: link,
		};
	}
}

let navigationElement = document.querySelector(".navigation");

new Navigation(navigationElement);
.navigation {
  display: flex;
  flex-flow: row nowrap;
  width: 100%;
  justify-content: space-between;
  width: 100%;
  max-width: 280px;
}

ul {
  display: flex;
  flex-flow: row nowrap;
  list-style: none;
  margin: 0;
  padding: 0;
}

li {
  margin-right: 20px;
}
<div class="navigation">
  <button id="changeButton">Change trigger</button>
  <ul>
    <li class="nav-item">
      <a href="">Link 1</a>
    </li>
    <li class="nav-item">
      <a href="">Link 2</a>
    </li>
  </ul>
</div>

navItem是我之前创建的对象。 navItem.link是HTML锚元素。

问题:

如何将侦听器绑定到特定对象? 我需要调用相同的方法,但是要使用特定的navItem对象...

更新:

添加了工作代码示例。 导航通过点击触发器进行初始化。点击按钮将切换点击/悬停。在此示例中,从单击切换到悬停后,两个侦听器均被执行。

1 个答案:

答案 0 :(得分:1)

您需要使用在addEventListener中使用的确切功能,请检查explanation on MDN

因此在您的示例中,您定义了一个新的匿名函数:

navItem.link.addEventListener('mouseout', e =>
    this.hoverHandler(e, navItem)
);

箭头功能是新的匿名功能:e => ...。因此,代替使用此匿名函数,您需要使用完全相同的函数。

要在事件处理程序中获取navItem,可以使用bind()。 bind的第一个参数定义事件处理程序中的上下文(this),而所有其他参数在提供的所有参数之前(在本例中为event参数)。但是您应该注意,bind()创建了一个新的function reference every time,因此您需要保存删除引用。一种实现方法是将函数保存在navItem上。对于hover事件,它将是:

if (this.isHoverVersion) {
    this.navItems.forEach(navItem => {
        // save function
        navItem.hoverHandler = this.navItemHoverHandler.bind(null, navItem);

        navItem.link.addEventListener('mouseover', navItem.hoverHandler);
        navItem.link.addEventListener('mouseout', navItem.hoverHandler);
    });
} else {
    this.navItems.forEach(navItem => {
        navItem.link.removeEventListener('mouseover', navItem.hoverHandler);
        navItem.link.removeEventListener('mouseout', navItem.hoverHandler);
    });
}

另外,您需要将navItemHoverHandler更改为此:

navItemHoverHandler(navItem, event) { // reversed order
    event.preventDefault();
    console.log('Hover handler executed');
    console.log(navItem);
}
相关问题