我有两个脚本(下面非常简单的例子)-第一个控制显示指定的导航菜单在一个页面和我们在几个地方使用的不同类型的菜单。
const NavMenu = function(selector) {
this.menuItems = document.querySelectorAll(`${selector} li > a`);
let This = this;
This.menuItems.forEach(item => {
item.addEventListener('click', e => {
item.classList.toggle('selected');
});
});
}
const myNavMenu = new NavMenu('.menu-wrap'); 另一个用于特定页面上的一个特定目的,该页面包含一个由第一个脚本控制的菜单。
(function () {
const menuItems = document.querySelectorAll('.menu-wrap li > a');
menuItems.forEach(item => {
item.addEventListener('click', e => {
const selectedItems = document.querySelectorAll('.menu-wrap li > a.selected');
let str = '';
if(selectedItems.length) {
selectedItems.forEach((item, i) => {
str += `${item.textContent} `;
});
document.querySelector('#results').innerText = `Selected: ${str}`;
}
});
});
})();如您所见,第二个脚本有一个单击处理程序,它根据每个菜单项的状态执行一个操作("selected“与否)。因为该状态是由第一个脚本设置的,所以只有当第一个脚本的单击处理程序在第二个脚本之前运行时,这个状态才能工作。
我创建了一个版本,强制第二个脚本的单击处理程序首先运行(通过setTimeout)。单击项目,可以看到结果文本不匹配。https://codepen.io/daveh0/pen/GROXmrq
因为第一个脚本在许多其他地方使用,所以它需要独立于任何其他脚本运行,否则我只需要组合2。
我认为一个定制的事件就是答案。我在这里实现了一个:https://codepen.io/daveh0/pen/xxPaqzJ是从我找到的一个例子中实现的,但我不知道这是否是正确的方法。很管用,但这并不意味着一吨.
我认为事件应该以某种方式绑定到NavMenu对象,但是除了window、document或其他DOM元素之外,我无法让它进行分派。有人能为我指明正确的方向吗?我可以这样做:myMenu.addEventListener('done', e => //do some stuff)而不是把它附加到window上?或者如果我开始的时候,也可以让我知道很多事情。
我知道这是内置在jQuery,但这需要保持香草JavaScript -谢谢!
发布于 2022-02-26 17:59:52
最后,我使用了一个事件发射器类,我在这篇文章中找到了这个类(并从中学到了很多东西)。正如@Bergi在关于OP的评论中指出的那样,事件不能附加到普通对象上。因为脚本1可以在所有不同的情况下在任何地方使用,这在我看来是最标准和最符合逻辑的。
非常简单..。
This.emitter = new MyEventEmitter();This.emitter.emit("done", item);NavMenu.emitter.on("done", menuItem => {...});
下面是在这个科德芬中工作的全部内容。
class MyEventEmitter {
constructor() {
this._events = {};
}
on(name, listener) {
if (!this._events[name]) {
this._events[name] = [];
}
this._events[name].push(listener);
}
removeListener(name, listenerToRemove) {
if (!this._events[name]) {
throw new Error(
`Can't remove a listener. Event "${name}" doesn't exits.`
);
}
const filterListeners = (listener) => listener !== listenerToRemove;
this._events[name] = this._events[name].filter(filterListeners);
}
emit(name, data) {
if (!this._events[name]) {
throw new Error(`Can't emit an event. Event "${name}" doesn't exits.`);
}
const fireCallbacks = (callback) => {
callback(data);
};
this._events[name].forEach(fireCallbacks);
}
}
const NavMenu = function (selector) {
this.menuItems = document.querySelectorAll(`${selector} li > a`);
let This = this;
This.emitter = new MyEventEmitter();
This.menuItems.forEach((item) => {
item.addEventListener("click", (e) => {
item.classList.toggle("selected");
This.emitter.emit("done", item);
});
});
};
const myNavMenu = new NavMenu(".menu-wrap");
(function (NavMenu) {
const menuItems = document.querySelectorAll(".menu-wrap li > a");
menuItems.forEach((item) => {
item.addEventListener("click", (e) => {
NavMenu.emitter.on("done", (menuItem) => {
const selectedItems = document.querySelectorAll(
".menu-wrap li > a.selected"
);
let str = "Selected: ";
if (selectedItems.length) {
selectedItems.forEach((item, i) => {
str += `${item.textContent} `;
});
} else {
str += `none`;
}
document.querySelector("#results").innerText = `${str}`;
});
});
});
})(myNavMenu);https://stackoverflow.com/questions/71272883
复制相似问题