Рекомендации
Добавить директиву vue при условии
Обнаруживать элемент внешнего элемента
Я пишу пользовательскую директиву для "click-out senario" для списка элементов.
В основном, когда кнопка нажата на элемент в списке, она переходит в выбранный режим. Теперь, если щелчок происходит где-нибудь еще, мне нужно отменить режим выбора. Для этого мне нужно обнаружить щелчок снаружи. Я определил директиву для этого из-за того, что я придумал
const clickOutside = {
bind: function (el, binding, vnode) {
console.log('bind called')
document.body.addEventListener('click', (event) => {
// check that click was outside the el and his childrens
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call handle method provided in attribute value
console.log('directive working')
vnode.context[binding.expression](event);
}
})
},
unbind: function (el) {
document.body.removeEventListener('click', el.event)
console.log('unbind called')
}
}
export {
clickOutside
}
из ссылки, указанной выше
Теперь я хочу, чтобы каждый элемент списка прослушивал внешние клики, когда этот элемент находится в выбранном режиме.
Поэтому мне нужно выполнить что-то вроде
<div id="list-item" v-on-click-outside="outSideClickHandler" //trigger only when selected>
</div>
<script>
export default{
data:{
selectedState:false;
},
methods:{
outSideClickHandler:{//......}
}
</script>
Почему бы вам просто не сделать выбранную проверку внутри внешнего обработчика кликов? Вам также понадобится способ передачи щелкнутого элемента в обработчик.
<div id="list-item" v-on-click-outside="outSideClickHandler(item)"></div>
outSideClickHandler(item) {
return event => {
if (item.selected) {
// Handle the click outside
}
};
}
Вызовите обработчик в директиве следующим образом:
binding.value(event);
Вы не получаете автоматическую привязку "выражение/утверждение" для настраиваемых директив, например, с помощью v-on
поэтому вам нужно заархивировать функцию обработчика, когда вы хотите передать ему дополнительные аргументы.
Под этим я подразумеваю, что аргумент, переданный в v-on
может быть выражением или выражением, например:
@click="handler" - handler is an expression (the function itself)
@click="handler(item)" - handler(item) is a statement
Но с настраиваемыми директивами вы можете передавать только выражения; вторая строка выше не возможна, если handler()
возвращает другую функцию.
Я думаю, что есть некоторая путаница, потому что кажется, что вы хотите, чтобы иметь настраиваемую директиву, которая используется только в этой конкретной ситуации с вашими элементами списка, но мое решение выше - это больше о том, чтобы написать общую директиву "клик снаружи", которую вы можете использовать в любой ситуации.
Также я думаю, что вы не хотите, чтобы директива регистрировала прослушиватели событий, если элемент списка не выбран (по соображениям производительности?). В этом случае вы можете использовать делегирование делегирования.
Невозможно условно включить/отключить директиву, вам нужно будет сделать что-то наподобие ответа Морти, оба из которых беспорядочны.
Это кажется работоспособным, но весь смысл использования пользовательских директив заключается в написании кода манипуляции с многократным использованием
Вы против написания кода манипуляции DOM вне директив? Угловая 1 имела эту философию. Если вы не хотите повторно использовать директиву в разных ситуациях, то может быть излишним написать директиву для этой ситуации, чтобы "код манипуляции DOM не загрязнял мой компонент". Если я собираюсь написать директиву, я бы хотел, чтобы она была как можно более общей, чтобы я мог использовать ее во многих разных ситуациях.
Мне даже не нужно передавать этот предмет в этом случае. Причина У меня есть компонент внутри v-for, а не div, и я связываю настраиваемую директиву с компонентом, обработчиком которого является метод
Тогда я не уверен, почему вы хотите реализовать это как директиву, которая редко нужна в любом случае. Вы можете просто зарегистрировать событие щелчка тела в mounted
крюке и удалить его в destroyed
крюке. Вся логика "внешний вид клика" может содержаться внутри самого компонента.
Если ваша основная проблема заключается в том, что вам не нужно регистрировать прослушиватель событий нажатия кнопки тела для каждого элемента списка, вы можете сделать что-то вроде этого:
const handlers = new Map();
document.addEventListener('click', e => {
for (const handler of handlers.values()) {
handler(e);
}
});
Vue.directive('click-outside', {
bind(el, binding) {
const handler = e => {
if (el !== e.target && !el.contains(e.target)) {
binding.value(e);
}
};
handlers.set(el, handler);
},
unbind(el) {
handlers.delete(el);
},
});
Вы можете сделать еще один шаг и автоматически добавить слушателя handlers
щелчка тела, когда handlers
непусты и удалить слушателя, когда handlers
пусты. Это вам.
В настоящее время нет простого способа выполнить привязку условной директивы. Вы могли бы использовать v-if
.
<div v-for='item of list'>
<div
v-if='item.selected'
id="list-item"
v-on-click-outside="outSideClickHandler"
/>
<div v-else
id="list-item"
v-on-click-outside="outSideClickHandler"
/>
</div>
Другим подходом было бы изменение вашей директивной реализации, чтобы он принял другой активный логический флаг, чтобы отказаться от внутри eventListener.
<div id="list-item" v-on-click-outside="{handler: outSideClickHandler, active: item.selected}" />
outSideClickHandler(item)
будет вычисляться прямо во время привязки директивы. Я думаю, что это должно бытьv-on-click-outside="() => outSideClickHandler(item)"