vue.jsの親から子メソッドにアクセスする方法


95

ネストされたコンポーネントが2つありますが、親から子メソッドにアクセスする適切な方法は何ですか?

this.$children[0].myMethod() トリックをしているように見えますが、それはかなり醜いですよね、もっと良い方法は何ですか?

<script>
import child from './my-child'

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>

まず、本当に必要かどうかを自問してください。すべてのページの状態がストア内にある場合は、当然のことながら、親子の通信は必要ありません。
bbsimonbb 2017年

7
@bbsimonbb状態はイベントとは異なります。これは特に、親から子イベントをトリガーすることに関するものです。小道具をダウンストリームに渡すことでVuexを使用することもできますが、これには子コンポーネントが小道具/ストアの変更を監視する必要があります。これにより、データの変更でRPCを効果的にエミュレートできます。これは、必要なときにまったく間違っています。コンポーネントでアクションをトリガーします。
ボヤンマルコビッチ2018

回答:


251

refを使用できます。

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {}
  },
  template: `
  <div>
     <ChildForm :item="item" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.$refs.form.submit()
    }
  },
  components: { ChildForm },
})

密結合が嫌いな場合は、@ YosvelQuinteroに示されているイベントバスを使用できます。以下は、バスを小道具として渡すことによってイベントバスを使用する別の例です。

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {},
    bus: new Vue(),
  },
  template: `
  <div>
     <ChildForm :item="item" :bus="bus" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.bus.$emit('submit')
    }
  },
  components: { ChildForm },
})

コンポーネントのコード。

<template>
 ...
</template>

<script>
export default {
  name: 'NowForm',
  props: ['item', 'bus'],
  methods: {
    submit() {
        ...
    }
  },
  mounted() {
    this.bus.$on('submit', this.submit)
  },  
}
</script>

https://code.luasoftware.com/tutorials/vuejs/parent-call-child-component-method/


39
これは正解であり、実際に実際の質問を読んでいます。選択した回答は、実際には反対の質問(子コンポーネントから親でメソッドをトリガーする方法)に回答します。
ボヤンマルコビッチ2018

1
この回答がリンクしているイベントバスのリンクは、@ bbsimonbbコメントを読んだ後、状態管理にリダイレクトされています。
Eido 9519年

2
を使用する場合はthis.$refs.、子コンポーネントを動的にロードしないでください。
1_bug

ありがとうございます!あなたは私に多くのトラブルを救った。私は制作の問題を修正していて、必死に答えを探していました!<3
オサマイブラヒム

this.$ref.ref配列を返すようです。だから私this.$refs.ref[0].autofocus();は働いた
JozefPlata20年

27

VueJSでの親子コミュニケーション

ルートVueインスタンスはthis.$root、を介してすべての子孫からアクセス可能であり、親コンポーネントはthis.$children配列を介して子コンポーネントにアクセスでき、子コンポーネントはを介してその親にアクセスできる場合this.$parent、最初の本能はこれらのコンポーネントに直接アクセスすることかもしれません。

VueJSのドキュメントは、特に2つの非常に良い理由でこれに対して警告しています。

  • 親と子を緊密に結合します(またはその逆)。
  • 親の状態は子コンポーネントによって変更できるため、親の状態に依存することはできません。

解決策は、Vueのカスタムイベントインターフェイスを使用することです

Vueによって実装されたイベントインターフェイスを使用すると、コンポーネントツリーを上下に通信できます。カスタムイベントインターフェイスを活用すると、次の4つの方法にアクセスできます。

  1. $on() -イベントをリッスンするVueインスタンスでリスナーを宣言できます
  2. $emit() -同じインスタンス(自己)でイベントをトリガーできます

$on()およびを使用した例$emit()

const events = new Vue({}),
    parentComponent = new Vue({
      el: '#parent',
      ready() {
        events.$on('eventGreet', () => {
          this.parentMsg = `I heard the greeting event from Child component ${++this.counter} times..`;
        });
      },
      data: {
        parentMsg: 'I am listening for an event..',
        counter: 0
      }
    }),
    childComponent = new Vue({
      el: '#child',
      methods: {
      greet: function () {
        events.$emit('eventGreet');
        this.childMsg = `I am firing greeting event ${++this.counter} times..`;
      }
    },
    data: {
      childMsg: 'I am getting ready to fire an event.',
      counter: 0
    }
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>

<div id="parent">
  <h2>Parent Component</h2>
  <p>{{parentMsg}}</p>
</div>

<div id="child">
  <h2>Child Component</h2>
  <p>{{childMsg}}</p>
  <button v-on:click="greet">Greet</button>
</div>

元の投稿からの回答:VueJSのコンポーネント間の通信


1
ありがとうございます。イベントを介してコードを相互化してみます。
al3x 2016

5
ものをコピーして貼り付けるときは、ソースについても言及するとよいでしょう。
Mihai Vilcu 2016

17
これは、子供から親へのコミュニケーションに役立ちます。しかし、親から子へそれを行う同様の方法はありますか?たとえば、ユーザーに新しい子の追加を許可する前に、既存のすべての子を検証する必要があります。検証ロジックは子にあるため、すべてを調べて、validate()メソッドなどを実行します。
Mateusz Bartkowiak 2017

67
これは、実際に尋ねられたものとは反対の質問に答えます。Desmond Luaの答えは、実際の質問に答えます。
ボヤンマルコビッチ2018

4
イベントバスは、ChrisFritzのvueアンチパターンのリストで1位です。イベントと分散状態でモデル化できるものはすべて、グローバル状態と双方向バインディングでモデル化できます。一般的に、はるかに優れています。
bbsimonbb 2018

1

コントロールレンダリングがの影響を受ける場合、参照バスとイベントバスの両方に問題がありますv-if。そこで、もっと簡単な方法で行くことにしました。

アイデアは、子コンポーネントに呼び出す必要のあるメソッドを送信するためのキューとして配列を使用することです。コンポーネントがマウントされると、このキューを処理します。キューを監視して新しいメソッドを実行します。

(Desmond Luaの回答からいくつかのコードを借りています)

親コンポーネントコード:

import ChildComponent from './components/ChildComponent'

new Vue({
  el: '#app',
  data: {
    item: {},
    childMethodsQueue: [],
  },
  template: `
  <div>
     <ChildComponent :item="item" :methods-queue="childMethodsQueue" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.childMethodsQueue.push({name: ChildComponent.methods.save.name, params: {}})
    }
  },
  components: { ChildComponent },
})

これはChildComponentのコードです

<template>
 ...
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    methodsQueue: { type: Array },
  },
  watch: {
    methodsQueue: function () {
      this.processMethodsQueue()
    },
  },
  mounted() {
    this.processMethodsQueue()
  },
  methods: {
    save() {
        console.log("Child saved...")
    },
    processMethodsQueue() {
      if (!this.methodsQueue) return
      let len = this.methodsQueue.length
      for (let i = 0; i < len; i++) {
        let method = this.methodsQueue.shift()
        this[method.name](method.params)
      }
    },
  },
}
</script>

そしてprocessMethodsQueue、ミックスインに移行するなど、改善の余地はたくさんあります...


0

子コンポーネントを別の子コンポーネントと通信するために、次の子のメソッドを呼び出す親のメソッドを作成しました。

this.$refs.childMethod()

そして、私がルートメソッドと呼んだ別の子から:

this.$root.theRootMethod()

それは私のために働いた。


この答えは欠けている多くの説明のを
VSYNC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.