2017-06-17 5 views
1

ボタンをクリックするとドロップダウンメニューを表示/非表示できるHeaderSubmenuコンポーネントがあります。さて、ユーザーがアプリ内のどこかをクリックしてもこのドロップダウンメニューではクリックしないと、それを隠すための良い解決策を見つけようとしています。他の場所をクリックしたときのコンポーネントのトリガー方法

私はVuexとVueRouterでVue 2.3.3を使用しています。

私のアプリのエントリポイント:

'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) 
    } 
}) 

テンプレートの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> 

このコンポーネントは、私のアプリのどこかで、ユーザーが他の場所よりもクリックしたときに、私は彼のtoggleMenu()メソッドを呼び出したいです<ul class="submenu-list">にあります。

私はドロップダウンメニューを「登録」し、自分のアプリケーション上のグローバル@clickイベントを検出するグローバルイベントバスを考えました。登録されたメニューがクリックされた要素でない場合、私たちはtoggleMenu()メソッドを呼び出すでしょう。 (理想的には、同じ動作をする他の要素を登録することができます)

...しかし、私はvueイベントシステムをまったくマスターしません。 イベントが一部の要素にないかどうかを確認する方法はありますか? これを達成する方法はわかりません。手伝って頂けますか ?ありがとうございました !

====== ====== EDIT

バート・エヴァンスの助けを借りて、私はこのカスタムディレクティブを使用:

// 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); 

私は私のコンポーネントテンプレートでこれを使用:

// 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> 
しかし、私はページ上の任意の場所をクリックすると、このコードは失敗します。

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

どこに問題がありますか?

+1

[外部の要素を検出する]の複製があります。(https://stackoverflow.com/questions/36170425/detect-click-outside-element) – Bert

+0

ありがとう、私はカスタムディレクティブを使用しようとしましたが、無限で終了しますループを更新する。私はあなたにそれを示すために投稿を編集しました。 – Thaledric

+0

'toggleMenu'は何をしますか? – Bert

答えて

2

問題はこちらです。あなたは何をしているかを効果的

v-clickout="hide()" 

hide()の結果にv-clickoutを設定することです。代わりに、hideメソッドに渡してください。あなただけの関数を呼び出すと、何か特別なことをしないために、テンプレートを欠けている場合は、テンプレート内のVueと一般に

v-clickout="hide" 

は、ちょうどその関数の名前を渡します。

+0

ああ、イベントディレクティブのようなものではない!私は 'stop'修飾子をclickイベントに追加しました。 ありがとうございました! 私は最後の質問をしています。サブメニューが2つある場合、最初のメニューを開き、もう1つを開くと、最初のメニューは閉じません(確かに、切り替えボタンの停止修飾子のためです)。どうすればこれを達成できますか? – Thaledric

+0

@Thaledricまず、イベント指令は同じです。あなたは括弧なしで名前に等しく設定することができます。私は2番目のケースで状況を想像するのに困っている。これらの真のサブメニュー(メニューの子ども)はありますか?多分あなたにすべての詳細を与えることができる新しい質問。 – Bert

+0

ありがとうございます!私はここに新しい質問を投稿しました:https://stackoverflow.com/questions/44613980/close-all-popups-when-the-user-click-to-open-a-new-one – Thaledric

関連する問題