Преобразовать код под Vue.js
У меня есть функция на JQuery:
$('.dropdown-toggle').click(function(e){
e.preventDefault();
$(this).parent().toggleClass('open');
$(document).mouseup(function(e){
let item = $(".dropdown.open");
if (item.has(e.target).length === 0){
item.removeClass('open');
}
})
});
Можно ли ее как-то преобразовать чтобы она работала на Vue.js 3 ?
Я думал в верстке на каждый div[.dropdown-toggle] сделать типа
<div class="dropdown-toggle" @click="function...">...
На так как таких блоков много, я думаю это не лучшее решение.
Буду очень благодарен за помощь!
UPD. Вот что у меня получилось:
mounted() {
let dropdowns = this.$el.querySelectorAll('.dropdown-toggle');
dropdowns.forEach(dropdown => {
dropdown.addEventListener('click', function(event) {
let parent = event.target.closest('.dropdown');
parent.classList.toggle("open");
});
});
}
Но не могу понять как сделать чтобы класс open удалялся если кликнуть в любом другом месте страницы...
UPD. получилось сделать таким образом
window.addEventListener('mouseup', event => {
const opened_dropdown = this.$el.querySelector('.dropdown.open');
if (opened_dropdown) {
if ( !opened_dropdown.contains(event.target) ) {
opened_dropdown.classList.remove("open");
}
}
}, false);
Огромная просьба - если видите какие-то недостатки такого решения, или есть более изящный вариант, напишите в ответ.
Ответы (1 шт):
В вашем коде нет слушателя события клика на document, чтобы закрыть все выпадающие списки при клике в любом месте страницы, и потому выпадающие списки оставались открытыми после того, как их открыли.
mounted() {
// Add click listener to document
document.addEventListener('click', this.closeDropdowns);
// Add click listener to each .dropdown-toggle
let dropdowns = this.$el.querySelectorAll('.dropdown-toggle');
dropdowns.forEach(dropdown => {
dropdown.addEventListener('click', event => {
let parent = event.target.closest('.dropdown');
parent.classList.toggle("open");
});
});
},
methods: {
closeDropdowns(event) {
// Check if click was inside a dropdown
let dropdowns = this.$el.querySelectorAll('.dropdown');
dropdowns.forEach(dropdown => {
if (!dropdown.contains(event.target)) {
dropdown.classList.remove('open');
}
});
}
},
beforeUnmount() {
// Remove click listener from document when component is removed
document.removeEventListener('click', this.closeDropdowns);
}
Что касаемо вашего обновленного кода - лучше использовать document вместо window, потому что document является родительским элементом всех элементов на странице, что обеспечивает более точную проверку клика вне списка. Ну и лучше использовать mousedown вместо mouseup, потому что mousedown происходит раньше, чем mouseup, что в свою очередь может снизить мерцание интерфейса.
Используя стрелочные функции:
mounted() {
let dropdowns = document.querySelectorAll('.dropdown-toggle');
dropdowns.forEach(dropdown => {
let clickHandler = event => {
let parent = event.target.closest('.dropdown');
parent.classList.toggle("open");
};
dropdown.addEventListener('click', clickHandler);
});
},
beforeUnmount() {
let dropdowns = document.querySelectorAll('.dropdown-toggle');
dropdowns.forEach(dropdown => {
let clickHandler = event => {
let parent = event.target.closest('.dropdown');
parent.classList.toggle("open");
};
dropdown.removeEventListener('click', clickHandler);
});
}
Сохраняем ссылку на анонимную функцию, переданную в addEventListener в переменной, чтобы далее использовать ее в removeEventListener.