web-dev-qa-db-ja.com

Vue js 2でコンポーネントサブコンポーネントチェーンのイベントをバブルする方法は?

私はvueアプリケーションを使用しています:

コンポーネントの子で構成されるコンポーネントの親コンポーネント

コンポーネントの親の内部にボタンがあり、誰かがボタンをクリックすると、vueによって処理され、別のコンポーネントに渡されるためにイベントを発行したい

これまでに行ったこと:

    var vm = new Vue({
        el: '#app',

        methods:{

            itemSelectedListener: function(item){
                console.log('itemSelectedListener', item);
            }
        }
    });




 Vue.component('component-child', {

                        template: ' <span  v-on:click="chooseItem(pty )" >Button  </span>'
                        ,
                        methods: {

                            chooseItem: function(pty){
                                console.log(pty);
                                this.$emit('itemSelected', {
                                    'priority' : pty
                                });
                            }
                        }
                    });

Vue.component('component-parent', {
                        template: '<component-child  v-for="q in items" ></component-child>'
                    });

HTML:

<component-parent v-on:itemSelected="itemSelectedListener"  ></component-parent>

Console.log(pty);に到達します。行ですが、this。$ emit( 'itemSelected'は通過しません:

console.log( 'itemSelectedListener'、item); //これは呼び出されません...

ヒント?

child-> parent-> Vue-instanceからイベントをバブルアップする必要がありますか? (私も試してみましたが、成功しませんでした)

14
koalaok

複数の子コンポーネントをレンダリングしようとするため、component-parentテンプレートには1つの問題があります。 Vueは通常、コンポーネント内に単一のルートdivを必要とするため、divまたはその他のタグでラップする必要があります。

<div>
    <component-child  v-for="q in items"></component-child>
</div>

2番目に指摘することは、2レベル下の子コンポーネントからイベントを発行し、ルートでそれをリッスンすることです。

Root //but you listen to the event up here 1 level above
 Component 1 //you should listen to the event here
  Component 2 //your try to emit it from here

ここには2つのオプションがあります。 component-childから発信するか、component-parentでもそれをリッスンしてから、さらに上に伝搬します。 Fiddle https://jsfiddle.net/bjqwh74t/29/

2番目のオプションは、空のvueインスタンスであるbusと呼ばれるグローバルを登録することです。これは、子と親以外のコンポーネント間の通信が必要な場合に使用できます。 Fiddle https://jsfiddle.net/bjqwh74t/30/

通常、親コンポーネントと子コンポーネント間では、v-on:event-name="handler"を使用して子から発信し、親でリッスンすることでイベントを直接使用しますが、コンポーネント間により多くのレベルがある場合は、2番目のアプローチを使用します。

最初のケースのドキュメントリンク: https://vuejs.org/v2/guide/components.html#Using-v-on-with-Custom-Events

2番目のケースのドキュメントリンク: https://vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication

PS:イベント名にkebab-caseを使用することをお勧めします。つまり、大文字ではなく-で記述します。大文字で書くと、イベントがルートで捕捉されないという奇妙な状況になる可能性があります。

14
Cristi Jora

価値があるものについては、ブラウザのイベントAPIを使用できます。 Vueの組み込みのものよりも少しスクリプティングが必要ですが、これらのバブルの問題を回避することもできます(受け入れられた答えのように、「バス」を作成するのとほぼ同じ量のコードです)。

子コンポーネント:

this.$el.dispatchEvent(new CustomEvent('itemSelected', { detail: { 'priority' : pty }, bubbles: true, composed: true });

親コンポーネントのmountedライフサイクル部分:

mounted() {
    this.$el.addListener('itemSelected', e => console.log('itemSelectedListener', e.detail));
}
7
codeMonkey

それは少し遅れていますが、ここに私がそれをした方法があります:

コンポーネントの子:

this.$root.$emit('foobar',{...});

コンポーネント親:

this.$root.$on('foobar')
2
behnam Tehrani

子コンポーネントでは、単に$emitにイベントを送信する$root このような:

v-on:click="$root.$emit('hamburger-click')"

次に、親コンポーネント(例:「App」)で、次のようにVue mountedライフサイクルフックにリスナーを設定します。

  export default {
    <snip...>
    mounted: function() {
      this.$root.$on('hamburger-click', function() {
        console.log(`Hamburger clicked!`);
      });
    }
  }
1
Geek Stocks