Vue stopPropagation не работает - дочерний элемент к родительскому элементу - PullRequest
0 голосов
/ 03 сентября 2018

Я борюсь с распространением событий. Задача состоит в том, чтобы не нажимать на что-либо еще, если данные не сохранены. Итак, левый div содержит дерево опций. После нажатия на элемент отображается настройка в правом div. Я хочу предупредить пользователя, когда он пытается щелкнуть за пределами настроек div, что данные не сохраняются.

Код выглядит так:

   <div class="row">
       <div class="col-sm-6">
           <tree
               :data="treeData">
               .. some tree data
           </tree>
       </div>
       <div class="col-sm-6">
               <div class="treeOptionEdit" v-if="showEditBox" v-click-outside.stop="checkIfSaved">

           ... setting input fields

vue-outside-events пакет используется для обнаружения кликов за пределами div. Работает нормально. Проблема в том, что этот код ничего не делает:

        checkIfSaved : function (event, el)
        {
            event.stopPropagation();
            event.preventDefault();
        },

Клик все равно распространяется на родителя. Если я помещаю событие @click в родительское событие, оно запускается всеми щелчками.

Останавливает ли распространение работает только от родителей к детям?

1 Ответ

0 голосов
/ 04 сентября 2018

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

Вот небольшой пример того, что происходит:

Vue.directive('click-outside', {
  bind(el, { value }) {
    el._handler = e => {
      if (!el.contains(e.target)) {
        value(e);
      }
    };
    
    document.addEventListener('click', el._handler);
  },
  
  unbind(el) {
    document.removeEventListener('click', el._handler);
  },
});

new Vue({
  el: '#app',
  methods: {
    onClick(e, color) {
      alert(`Clicked the ${color} box.`);
    },
    
    onClickOutside(e, color) {
      e.stopPropagation();
      alert(`Clicked outside of ${color} box.`);
    },
  },
});
.box { padding: 20px; }
.red { background-color: red; }
.yellow { background-color: yellow; }
.blue { background-color: blue; }
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <div class="box red" @click="onClick($event, 'red')">
    <div class="box yellow" @click="onClick($event, 'yellow')">
      <div class="box blue" @click="onClick($event, 'blue')" v-click-outside="e => onClickOutside(e, 'blue')">
      </div>
    </div>
  </div>
</div>
  1. Нажмите синюю коробку. Синее поле сначала получает событие щелчка, затем оно всплывает до желтого, а затем красного поля, как и ожидалось.
  2. Нажмите на желтое поле. Желтые, а затем красные прямоугольники получают событие click, а затем, когда оно всплывает на элемент документа (к которому директива click-outside прикрепила слушатель события), вызывается обработчик click-outside. Вызов stopPropagation() в данный момент ничего не делает, потому что событие уже достигло вершины.

Я не верю, что модификатор .stop что-то делает в вашем примере, потому что v-click-outside не поддерживает этот модификатор (.stop поддерживается только v-on; v-click-outside потребуется его поддержка).

Таким образом, чтобы решить вашу проблему, вам нужно изменить порядок событий: сначала нужно обработать v-click-outside, прежде чем @click.

Этого можно добиться, изменив реализацию v-click-outside, используя захват событий следующим образом:

Vue.directive('click-outside', {
  bind(el, { value }) {
    el._handler = e => {
      if (!el.contains(e.target)) {
        value(e);
      }
    };
    
    // *** Using capturing ***
    document.addEventListener('click', el._handler, { capture: true });
  },
  
  unbind(el) {
    document.removeEventListener('click', el._handler, { capture: true });
  },
});

new Vue({
  el: '#app',
  methods: {
    onClick(e, color) {
      alert(`Clicked the ${color} box.`);
    },
    
    onClickOutside(e, color) {
      e.stopPropagation();
      alert(`Clicked outside of ${color} box.`);
    },
  },
});
.box { padding: 20px; }
.red { background-color: red; }
.yellow { background-color: yellow; }
.blue { background-color: blue; }
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <div class="box red" @click="onClick($event, 'red')">
    <div class="box yellow" @click="onClick($event, 'yellow')">
      <div class="box blue" @click="onClick($event, 'blue')" v-click-outside="e => onClickOutside(e, 'blue')">
      </div>
    </div>
  </div>
</div>

Почему бы не отправить запрос на получение vue-outside-events для поддержки этой функции?

...