单击其他位置时触发组件方法

Tha*_*ric 2 javascript events vue.js

我有一个HeaderSubmenu组件,如果单击一个按钮,它可以显示/隐藏下拉菜单。好的,但是现在我尝试找到一个好的解决方案,使用户单击应用程序中的任意位置而不单击此下拉菜单时,它就会隐藏。

我正在将Vue 2.3.3与Vuex和VueRouter一起使用。

我的应用程序入口点:

'use strict';

import Vue from 'vue';
import VueRouter from 'vue-router';
import Vuex from 'vuex';

Vue.use(VueRouter);
Vue.use(Vuex);

import store_data from 'store';
import {router} from 'routes';

import App from 'app.vue';

var store = new Vuex.Store(store_data);

new Vue({
  el: '#app',
  store,
  router: router,
  render: function (createElement) {
    return createElement(App)
  }
})
Run Code Online (Sandbox Code Playgroud)

HeaderSubmenu组件模板:

<template>
  <li class="header-submenu">
    <!-- button to show/hide the drop-down menu -->
    <header-link v-bind="$props" :href="to ? false : '#'" @click.native="toggleMenu()">
      <slot name="item"></slot>
    </header-link>
    <!-- drop-down menu -->
    <ul class="submenu-list" :class="{'open': open, 'animated': animated}" @animationend="displaynone()">
      <slot></slot>
    </ul>
  </li>
</template>
Run Code Online (Sandbox Code Playgroud)

该组件在我的应用程序中的某个位置,toggleMenu()当用户单击上的其他位置时,我想调用他的方法<ul class="submenu-list">

我想到了一个全局事件总线,其中的下拉菜单应该被“注册”并在我的应用程序上检测到全局@click事件。如果注册的菜单不是单击的元素,toggleMenu()否则将调用他的方法。(理想情况下,我可以注册其他具有相同行为的元素。)

...但是我根本不掌握vue事件系统。如何检查事件是否不在某个元素上?我不知道如何实现这一目标。你能帮助我吗 ?谢谢 !

======编辑======

在Bert Evans的帮助下,我使用了以下自定义指令:

// directive-clickoutside.js
export default {
  bind(el, binding, vnode) {
    el.event = function (event) {
      // here I check that click was outside the el and his childrens
      if (!(el == event.target || el.contains(event.target))) {
        // and if it did, call method provided in attribute value
        vnode.context[binding.expression](event);
      }
    };
    document.body.addEventListener('click', el.event)
  },
  unbind(el) {
    document.body.removeEventListener('click', el.event)
  },
};

// main.js
import clickout from 'utils/directive-clickoutside';
Vue.directive('clickout', clickout);
Run Code Online (Sandbox Code Playgroud)

我在组件模板中使用了它:

// HeaderSubmenu component
<template>
  <li class="header-submenu">
    <!-- élément du header servant à ouvrir le sous-menu -->
    <header-link v-bind="$props" :href="to ? false : '#'" @click.native="toggle()">
      <slot name="item"></slot>
    </header-link>
    <!-- sous-menu -->
    <ul class="submenu-list" :class="{'open': open, 'animated': animated}" @animationend="displaynone()" v-clickout="hide()">
      <slot></slot>
    </ul>
  </li>
</template>
Run Code Online (Sandbox Code Playgroud)

但是,当我单击页面上的任意位置时,此代码将失败:

Uncaught TypeError: n.context[e.expression] is not a function
    at HTMLBodyElement.t.event (directive-clickoutside.js:7)
Run Code Online (Sandbox Code Playgroud)

问题出在哪里 ?

Ber*_*ert 6

问题在这里。

v-clickout="hide()"
Run Code Online (Sandbox Code Playgroud)

实际上,您正在做的是设置v-clickout为的结果hide()。相反,只需将其传递给hide方法即可。

v-clickout="hide"
Run Code Online (Sandbox Code Playgroud)

通常,对于Vue,在模板中,如果只希望模板调用函数而不执行任何特殊操作,只需将其名称传递给函数即可。