最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Vue stopPropagation not working - child to parent - Stack Overflow

programmeradmin1浏览0评论

I am struggling with events propagation. The task is to prevent clicking on anything alse, if the data is not saved. So, The left div contains a tree of options. After clicking on an item, a setting in the right div is showed. I want to warn the user, when he tries to click outside the settings div, that the data is not saved.

The code looks like this:

   <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 package is used to detect clicks outside div. It works fine. The problem is, that this code, doesn't do anything:

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

The click gets propagated to the parent anyway. If I put an event @click to the parent, it is fired an all clicks.

Does stop propagation work only from parent to children?

I am struggling with events propagation. The task is to prevent clicking on anything alse, if the data is not saved. So, The left div contains a tree of options. After clicking on an item, a setting in the right div is showed. I want to warn the user, when he tries to click outside the settings div, that the data is not saved.

The code looks like this:

   <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 package is used to detect clicks outside div. It works fine. The problem is, that this code, doesn't do anything:

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

The click gets propagated to the parent anyway. If I put an event @click to the parent, it is fired an all clicks.

Does stop propagation work only from parent to children?

Share Improve this question edited Nov 29, 2020 at 13:38 Brian Tompsett - 汤莱恩 5,89372 gold badges61 silver badges133 bronze badges asked Sep 3, 2018 at 18:47 Peter MatiskoPeter Matisko 2,2531 gold badge27 silver badges50 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

I'm not familiar with the v-click-outside implementation, but "click outside" events are typically implemented by using event delegation on the document/body element, and so by that time the event has already propagated and cannot be stopped.

Here's a small example of what's going on:

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./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. Click the blue box. The blue box receives the click event first, then it bubbles up to the yellow then red boxes, as expected.
  2. Click the yellow box. The yellow then red boxes receive the click event, then once it bubbles to the document element (of which the click-outside directive has attached an event listener to) the click-outside handler is called. Calling stopPropagation() at this moment does nothing because the event has already bubbled to the top.

I don't believe the .stop modifier does anything in your example because v-click-outside doesn't support this modifier (.stop is only supported by v-on; v-click-outside would need to support it).

So to solve your problem you need to change the order of events: v-click-outside needs to be handled first before @click.

You can achieve this by changing the v-click-outside implementation by using event capturing as follows:

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./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>

Why not submit a pull request to vue-outside-events to support this feature?

发布评论

评论列表(0)

  1. 暂无评论