Проблема, которую я хочу решить, заключается в:
Мне нужно поймать моменты, когда я нажимаю за пределы какого -то элемента
Почему?
Это может быть полезно для компонентов пользовательского интерфейса, таких как выпадающие, дату, модальные окна – чтобы назначить некоторую логику для этого определенного поведения
Как стартер, я скажу, что принятое значение для директивы будет просто функцией, и в коде это будет выглядеть:
В конце текста будет раздел «Рефакторинг» с расширением логики для большего использования способами использования
Ссылки используются
Текст и код в статье являются результатом анализа с открытым исходным кодом и прохождения существующих решений, написанных выше
Решение
Я собираюсь использовать Vue в качестве структуры пользовательского интерфейса здесь. Почему? Я просто использую Vue в качестве своей нынешней бизнес -рамки, так что для меня это был бы хороший шанс погрузиться в него глубже.
Прежде всего, давайте просто определим функцию, которая ловит внешние клики, без каких-либо обертка, почти псевдокод
Определите, когда мы можем сказать, что мы щелкнули вне элемента
Для этого нам нужно знать, где мы щелкнули, и какова наш элемент с назначенным слушателем, поэтому функция начнется так:
function onClickOutside(event, el) {
const isClickOutside =
event.target !== el
&& !el.contains(event.target);
}
Теперь, если флаг правда, нам нужно вызвать какого -то обработчика:
function onClickOutside(event, el, handler) {
const isClickOutside =
event.target !== el
&& !el.contains(event.target);
return isClickOutside ? handler(event, el) : null;
}
Для меня это выглядит немного тяжело только, что я должен следовать заказу аргументов, поэтому вместо этого я буду использовать один параметр объекта; Функция Onclickoutside ({Event, El, Handler})
Начните слушать функцию
Логически, нам нужно найти место, где мы можем использовать это:
document.addEventListener(
'click',
(event) => onClickOutside({ event })
)
Здесь – без изобретения, просто собираюсь вветь док и увидеть о Пользовательские директивы
По сути, нам нужно всего три стадии жизненного цикла:
- привязать – назначить директивную логику элементу и создать слушателей
- разгибай – когда элемент больше нет в доме И нам нужно удалить наших слушателей
Чтобы иметь возможность поймать слушателей, приписывающих элементу, я создам их карту – для хранения и быстрого достижения их:
const map ();
Прежде чем написать свои крючки, я напишу функцию для повторного использования кода – вот я буду манипулировать своим событием:
function toggleEventListeners(action, eventHandler) {
document[`${action}EventListener`]('click', eventHandler, true);
}
(«Истинный» третий парамет, который я использовал для вызова обработчика на фазе захвата, чуть раньше, чем при пузырчах)
Функция связывания будет выглядеть как:
function bind(el, { value: handler }) {
const eventHandler = event => onClickOutside({ el, event, handler});
toggleEventListeners('add', eventHandler);
instances.set(
el,
eventHandler
);
}
Function Function сделает простую логику для удаления наших слушателей из системы:
function unbind(el) {
const eventHandler = instances.get(el);
toggleEventListeners('remove', eventHandler);
instances.delete(el);
}
В конце нам просто нужно правильно экспортировать эту директиву и связаться с нашим экземпляром Vue в файле ‘main.js:
const directive = {
bind,
unbind,
};
export default directive;
‘main.js’:
import Vue from 'vue'
import App from './App.vue'
import clickOutside from './directives/clickOutside';
Vue.config.productionTip = false
Vue.directive('click-outside', clickOutside);
new Vue({
render: h => h(App),
}).$mount('#app')
Вот и все как минимум, теперь идет следующий раздел
Рефакторинг
Я хотел бы справиться не только как значение как значение, но и объект
//Validator function
function processArgs(value) {
const isFunction = typeof value === 'function';
if (!isFunction && typeof value !== 'object') {
throw new Error(`v-click-outside: Binding value should be a function or an object, ${typeof bindingValue} given`)
}
return {
handler: isFunction ? value : value.handler,
}
}
//Handler goes from the processing function
function bind(el, { value }) {
const { handler } = processArgs(value);
//...function body
}
Я хочу добавить функцию промежуточного программного обеспечения для определения условий, когда я хочу или не хочу вызывать свой обработчик
Расширить результат обработки с помощью метода промежуточного программного обеспечения
return {
handler: isFunction ? value : value.handler,
middleware: value.middleware || (() => true),
};
Расширить логику функции ClickOutside
function onClickOutside({ event, el, handler, middleware }) {
const isClickOutside =
event.target !== el
&& !el.contains(event.target);
if (!isClickOutside || !middleware(event, el)) {
return null;
}
return handler(event, el);
}
Тогда везде, где бы вы ни использовали обработчик, не забудьте также также разрушить промежуточное программное обеспечение и добавить в качестве параметров для привязки и адаптера функции
Ну, вот и все, полный пример можно найти здесь, в моих Gists – https://gist.github.com/disgusting-dev/8d45aebff8a536af1cba39b0fcd203e3
Спасибо за чтение, дальше будет все больше и больше, поэтому не стесняйтесь подписаться, чтобы не пропустить никакого анализа!
Оригинал: “https://dev.to/disgustingdev/vue-directive-click-outside-37nc”