我正在制作一个从 Google Places API 绘制搜索结果列表的应用程序,这使用户有机会使用 JavaScript 动态生成的按钮将位置标记为已访问(然后存储在 MongoDB 中)。当我单击该按钮时,我看到该事件已运行大约 20 次(顺便说一句,搜索结果中返回了相同数量的位置)。然后,这会调用服务器端的 API 端点大约 5 次。
我怀疑这与将事件侦听器绑定到每个单独的按钮有关,但我不确定解决方法是什么。非常感谢任何帮助!
客户端功能:
const markVisitedButtons = document.querySelectorAll(".visitor");
markVisitedButtons.forEach((button) => {
button.addEventListener("click", function () {
console.log("eventlistener");
const placeId = this.getAttribute("data-place-id");
const placeName = this.getAttribute("placeName");
const placeAddress = this.getAttribute("placeAddress");
markVisited(placeName);
});
});
function markVisited(placeName) {
console.log("fetch function");
fetch(`/markVisited`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ placeName }),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});
}
以及在获取之后调用的服务器端函数:
router.post("/markVisited", async (req, res, next) =\> {
const placeName = req.body;
try {
const newPlace = await new VisitedPlace({
placeName: req.body.placeName,
userId: req.user._id,
});
newPlace
.save()
.then(
User.updateOne(
{ _id: req.user._id },
{ $push: { visitedPlaces: newPlace._id } }
)
);
} catch (error) {
console.log(error);
}
});
要解决此问题,您可以尝试使用事件委托。事件委托意味着将单个事件侦听器附加到按钮的公共父元素,然后使用事件对象来确定单击了哪个特定按钮。
这是您的客户端功能:
const markVisitedButtonsContainer = document.querySelector(".container"); // Use a common parent element
markVisitedButtonsContainer.addEventListener("click", function (event) {
if (event.target.classList.contains("visitor")) {
const placeId = event.target.getAttribute("data-place-id");
const placeName = event.target.getAttribute("placeName");
const placeAddress = event.target.getAttribute("placeAddress");
markVisited(placeName);
}
});
function markVisited(placeName) {
console.log("fetch function");
fetch(`/markVisited`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ placeName }),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
});
}
我添加了一个容器元素(将 .container 替换为保存按钮的容器的实际类或 id)作为按钮的公共父元素。事件侦听器附加到此容器,并检查单击的元素是否具有类访问者。如果是,则处理该事件。这样,您就可以确保无论有多少按钮,您都只有一个事件侦听器,并且该事件不会多次传播。