Vue stopPropagation 不起作用 - 子级到父级

Pet*_*sko 6 javascript event-handling dom-events vue.js vue-events

我正在努力处理事件传播。任务是在未保存数据的情况下防止单击其他任何内容。因此,左侧 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
Run Code Online (Sandbox Code Playgroud)

vue-outside-events包用于检测div外部的点击。效果很好。问题是,这段代码没有做任何事情:

        checkIfSaved : function (event, el)
        {
            event.stopPropagation();
            event.preventDefault();
        },
Run Code Online (Sandbox Code Playgroud)

无论如何,点击都会传播到父级。如果我将一个事件发送@click给父级,则所有点击都会触发该事件。

停止传播只能从父级到子级起作用吗?

Dec*_*oon 5

我不熟悉实现v-click-outside,但“单击外部”事件通常是通过在文档/正文元素上使用事件委托来实现的,因此到那时该事件已经传播并且无法停止。

这是正在发生的事情的一个小例子:

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.`);
    },
  },
});
Run Code Online (Sandbox Code Playgroud)
.box { padding: 20px; }
.red { background-color: red; }
.yellow { background-color: yellow; }
.blue { background-color: blue; }
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  1. 单击蓝色框。蓝色框首先接收单击事件,然后如预期的那样向上冒泡到黄色框,然后是红色框。
  2. 单击黄色框。黄色然后红色的框接收点击事件,然后一旦它冒泡到文档元素(指令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.`);
    },
  },
});
Run Code Online (Sandbox Code Playgroud)
.box { padding: 20px; }
.red { background-color: red; }
.yellow { background-color: yellow; }
.blue { background-color: blue; }
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

为什么不向vue-outside-events提交拉取请求来支持此功能?