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

Ссылки

Добавление директивы vue при условии

Обнаружение щелчка вне элемента

Я пишу пользовательскую директиву для'click-outside 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>

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

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

<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() не возвращает другую функцию.


Я думаю, что есть некоторая путаница, потому что кажется, что вам нужно иметь пользовательскую директиву, которая используется только в этой конкретной ситуациис вашими элементами списка, но мое решение, приведенное выше, больше касается написания общей директивы "click outside", которую вы можете использовать в любой ситуации.

Также я думаю, что вы не хотите, чтобы директива регистрировала слушателей событий, еслиэлемент списка не выбран (по причинам производительности?).Если это так, то вместо этого вы можете использовать делегирование событий.

Нет способа условно включить / отключить директиву, вам придется сделать что-то вроде ответ Морти , оба из которыхэто немного грязно.

Это кажется работоспособным, но весь смысл использования пользовательских директив состоит в том, чтобы писать повторно используемый код манипуляции dom

Вы против написания кода манипуляции DOM внедирективы?Angular 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 пусто.Вам решать.

0 голосов
/ 11 мая 2018

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