Rufen Sie eine Vue.js-Komponentenmethode von außerhalb der Komponente auf

227

Angenommen, ich habe eine Haupt-Vue-Instanz mit untergeordneten Komponenten. Gibt es eine Möglichkeit, eine Methode, die zu einer dieser Komponenten gehört, vollständig von außerhalb der Vue-Instanz aufzurufen?

Hier ist ein Beispiel:

var vm = new Vue({
  el: '#app',
  components: {
    'my-component': { 
      template: '#my-template',
      data: function() {
        return {
          count: 1,
        };
      },
      methods: {
        increaseCount: function() {
          this.count++;
        }
      }
    },
  }
});

$('#external-button').click(function()
{
  vm['my-component'].increaseCount(); // This doesn't work
});
<script src="http://vuejs.org/js/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app">
  
  <my-component></my-component>
  <br>
  <button id="external-button">External Button</button>
</div>
  
<template id="my-template">
  <div style="border: 1px solid; padding: 5px;">
  <p>A counter: {{ count }}</p>
  <button @click="increaseCount">Internal Button</button>
    </div>
</template>

Wenn ich also auf die interne Schaltfläche klicke, ist die increaseCount()Methode an ihr Klickereignis gebunden, sodass sie aufgerufen wird. Es gibt keine Möglichkeit, das Ereignis an die externe Schaltfläche zu binden, deren Klickereignis ich mit jQuery abhöre. Daher benötige ich eine andere Möglichkeit zum Aufrufen increaseCount.

BEARBEITEN

Es scheint, dass dies funktioniert:

vm.$children[0].increaseCount();

Dies ist jedoch keine gute Lösung, da ich die Komponente anhand ihres Index im untergeordneten Array referenziere. Bei vielen Komponenten ist es unwahrscheinlich, dass dies konstant bleibt und der Code weniger lesbar ist.

Harryg
quelle
1
Ich habe eine Antwort mit mxins hinzugefügt, wenn Sie es versuchen möchten. Meiner Meinung nach richte ich die App lieber so ein.
Omar Tanti

Antworten:

273

Am Ende habe ich mich für die refAnweisung von Vue entschieden . Dadurch kann eine Komponente vom übergeordneten Element für den direkten Zugriff referenziert werden.

Z.B

Haben Sie eine Komponente in meiner übergeordneten Instanz registriert:

var vm = new Vue({
    el: '#app',
    components: { 'my-component': myComponent }
});

Rendern Sie die Komponente in template / html mit einer Referenz:

<my-component ref="foo"></my-component>

Jetzt kann ich an anderer Stelle extern auf die Komponente zugreifen

<script>
vm.$refs.foo.doSomething(); //assuming my component has a doSomething() method
</script>

Ein Beispiel finden Sie in dieser Geige: https://jsfiddle.net/xmqgnbu3/1/

(altes Beispiel mit Vue 1: https://jsfiddle.net/6v7y6msr/ )

Harryg
quelle
6
Das liegt daran, dass Sie es wahrscheinlich nicht definiert haben. Schau dir die verknüpfte Geige an.
Harryg
29
Wenn Sie ein Webpack verwenden, können Sie vmaufgrund des Umfangs der Module nicht darauf zugreifen . Sie können so etwas wie window.app = vmin Ihrem tun main.js. Quelle: forum.vuejs.org/t/how-to-access-vue-from-chrome-console/3606
tw airball
1
Kann dieser Ansatz als normal angesehen werden? Oder ist das ein Hack?
CENT1PEDE
3
Es gibt eine so offizielle Definition, was ein Hack ist, im Vergleich zu einer "normalen" Codierung, aber anstatt diesen Ansatz als Hack zu bezeichnen (oder nach einem "weniger hackigen" Weg zu suchen, um dasselbe zu erreichen), ist es wahrscheinlich besser zu fragen, warum Sie dies tun müssen Dies. In vielen Fällen ist es möglicherweise eleganter, das Ereignissystem von Vue zu verwenden, um das Verhalten externer Komponenten auszulösen, oder sogar zu fragen, warum Sie Komponenten überhaupt extern auslösen.
Harryg
8
Dies kann auftreten, wenn Sie versuchen, eine Ansichtskomponente in eine bereits vorhandene Seite zu integrieren. Anstatt die Seite komplett neu zu gestalten, ist es manchmal hilfreich, schrittweise zusätzliche Funktionen hinzuzufügen.
Allen Wang
37

Seit Vue2 gilt dies:

var bus = new Vue()

// in der Methode von Komponente A.

bus.$emit('id-selected', 1)

// im erstellten Hook von Komponente B.

bus.$on('id-selected', function (id) {

  // ...
})

Sehen Sie hier für die Vue docs. Und hier erfahren Sie mehr darüber, wie Sie diesen Eventbus genau einrichten.

Weitere Informationen zur Verwendung von Eigenschaften, Ereignissen und / oder zentraler Statusverwaltung finden Sie in diesem Artikel .

Musikformellons
quelle
1
Kurz und bündig! Wenn Sie die globale busVariable nicht mögen , können Sie einen Schritt weiter gehen und den Bus mithilfe von Requisiten in Ihre Komponente einfügen . Ich bin relativ neu in Vue, daher kann ich Ihnen nicht versichern, dass dies idiomatisch ist.
Byxor
31

Sie können das Vue-Ereignissystem verwenden

vm.$broadcast('event-name', args)

und

 vm.$on('event-name', function())

Hier ist die Geige: http://jsfiddle.net/hfalucas/wc1gg5v4/59/

Helder Lucas
quelle
5
@GusDeCooL Das Beispiel wurde bearbeitet. Nicht dass nach Vuejs 2.0 einige dort verwendete Methoden veraltet wären
Helder Lucas
1
Funktioniert gut, wenn es nur eine Instanz der Komponente gibt, aber wenn es viele Instanzen gibt, funktioniert es besser, $ refs.component.method ()
Koronos
22

Eine etwas andere (einfachere) Version der akzeptierten Antwort:

Lassen Sie eine Komponente auf der übergeordneten Instanz registrieren:

export default {
    components: { 'my-component': myComponent }
}

Rendern Sie die Komponente in template / html mit einer Referenz:

<my-component ref="foo"></my-component>

Greifen Sie auf die Komponentenmethode zu:

<script>
    this.$refs.foo.doSomething();
</script>
Sieger
quelle
21

Sie können ref für untergeordnete Komponenten festlegen und dann in parent über $ refs aufrufen:

Ref zur untergeordneten Komponente hinzufügen:

<my-component ref="childref"></my-component>

Klickereignis zum übergeordneten Element hinzufügen:

<button id="external-button" @click="$refs.childref.increaseCount()">External Button</button>

var vm = new Vue({
  el: '#app',
  components: {
    'my-component': { 
      template: '#my-template',
      data: function() {
        return {
          count: 1,
        };
      },
      methods: {
        increaseCount: function() {
          this.count++;
        }
      }
    },
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  
  <my-component ref="childref"></my-component>
  <button id="external-button" @click="$refs.childref.increaseCount()">External Button</button>
</div>
  
<template id="my-template">
  <div style="border: 1px solid; padding: 2px;" ref="childref">
    <p>A counter: {{ count }}</p>
    <button @click="increaseCount">Internal Button</button>
  </div>
</template>

Cong Nguyen
quelle
2
die bisher sauberste Lösung.
Grreeenn
Gute Antwort. Ich werde nur das HTML bearbeiten, um vertikal etwas kleiner zu sein. Derzeit kann ich "Interne Schaltfläche" nur sehen, wenn ich sie ausführe, was verwirrend sein kann.
Jesse Reza Khorasanee
8

Angenommen, Sie haben eine child_method()in der untergeordneten Komponente:

export default {
    methods: {
        child_method () {
            console.log('I got clicked')
        }
    }
}

Jetzt möchten Sie die child_methodübergeordnete Komponente ausführen :

<template>
    <div>
        <button @click="exec">Execute child component</button>
        <child-cmp ref="child"></child_cmp> <!-- note the ref="child" here -->
    </div>
</template>

export default {
    methods: {
        exec () { //accessing the child component instance through $refs
            this.$refs.child.child_method() //execute the method belongs to the child component
        }
    }
}

Wenn Sie eine übergeordnete Komponentenmethode aus einer untergeordneten Komponente ausführen möchten:

this.$parent.name_of_method()

HINWEIS: Es wird nicht empfohlen, auf die untergeordnete und übergeordnete Komponente wie folgt zuzugreifen.

Verwenden Sie stattdessen als Best Practice Props & Events für die Eltern-Kind-Kommunikation.

Wenn Sie zwischen Komponenten kommunizieren möchten, verwenden Sie sicher Vuex oder Event Bus

Bitte lesen Sie diesen sehr hilfreichen Artikel


roli roli
quelle
Ja, Sie können, aber nicht als "Best Practice" betrachtet: Abwärts zu untergeordneten Verwendungseigenschaften, aufwärts zu übergeordneten Verwendungsereignissen. Verwenden Sie benutzerdefinierte Ereignisse oder z. B. vuex, um auch "seitwärts" abzudecken. Weitere Informationen finden Sie in diesem schönen Artikel .
Musikformellons
Ja, dies wird nicht empfohlen.
Roli Roli
3

Dies ist eine einfache Möglichkeit, von einer anderen Komponente aus auf die Methoden einer Komponente zuzugreifen

// This is external shared (reusable) component, so you can call its methods from other components

export default {
   name: 'SharedBase',
   methods: {
      fetchLocalData: function(module, page){
          // .....fetches some data
          return { jsonData }
      }
   }
}

// This is your component where you can call SharedBased component's method(s)
import SharedBase from '[your path to component]';
var sections = [];

export default {
   name: 'History',
   created: function(){
       this.sections = SharedBase.methods['fetchLocalData']('intro', 'history');
   }
}
Dotnetgang
quelle
2

Ich bin mir nicht sicher, ob es der richtige Weg ist, aber dieser funktioniert für mich.
Importieren Sie zuerst die Komponente, die die Methode enthält, die Sie in Ihrer Komponente aufrufen möchten

import myComponent from './MyComponent'

und rufen Sie dann eine beliebige Methode von MyCompenent auf

myComponent.methods.doSomething()
Rohit Kumar
quelle
1

Hier ist eine einfache

this.$children[indexOfComponent].childsMethodName();
Pratik Khadtale
quelle
-7

Ich habe eine sehr einfache Lösung verwendet. Ich habe ein HTML-Element, das die Methode aufruft, in meine Vue-Komponente aufgenommen, die ich mit Vanilla JS auswähle, und ich löse einen Klick aus!

In die Vue-Komponente habe ich Folgendes eingefügt:

<span data-id="btnReload" @click="fetchTaskList()"><i class="fa fa-refresh"></i></span>

Dass ich mit Vanilla JS benutze:

const btnReload = document.querySelector('[data-id="btnReload"]');
btnReload.click();                
Gorbas
quelle
Dies wird im Rahmen der Frage überhaupt nicht als bewährte Praxis angesehen, insbesondere im Zusammenhang mit der Frage von OP.
Hybrid Web Dev