Условно свяжите пользовательские директивы в vue js для «щелчка вне события элемента»

1

Рекомендации

Добавить директиву 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>
Теги:
vue.js
click
vue-component
directive

2 ответа

3
Лучший ответ

Почему бы вам просто не сделать выбранную проверку внутри внешнего обработчика кликов? Вам также понадобится способ передачи щелкнутого элемента в обработчик.

<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 пусты. Это вам.

  • 0
    Похоже, что outSideClickHandler(item) будет вычисляться прямо во время привязки директивы. Я думаю, что это должно быть v-on-click-outside="() => outSideClickHandler(item)"
  • 0
    @MortyChoi Да, будет, но возвращает другую функцию .
Показать ещё 7 комментариев
0

В настоящее время нет простого способа выполнить привязку условной директивы. Вы могли бы использовать 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}"  />

Ещё вопросы

Сообщество Overcoder
Наверх
Меню