Wywołaj metodę komponentu Vue.js spoza komponentu


229

Załóżmy, że mam główną instancję Vue, która zawiera elementy potomne. Czy istnieje sposób wywołania metody należącej do jednego z tych komponentów spoza instancji Vue?

Oto przykład:

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>

Kiedy klikam przycisk wewnętrzny, increaseCount()metoda jest powiązana ze zdarzeniem kliknięcia, więc zostaje wywołana. Nie ma możliwości powiązania zdarzenia z zewnętrznym przyciskiem, którego zdarzenia kliknięcia oczekuję za pomocą jQuery, więc będę potrzebować innego sposobu wywołania increaseCount.

EDYTOWAĆ

Wygląda na to, że działa:

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

Nie jest to jednak dobre rozwiązanie, ponieważ odwołuję się do komponentu według jego indeksu w tablicy potomnej, a przy wielu komponentach jest mało prawdopodobne, aby pozostał on stały, a kod jest mniej czytelny.


1
Dodałem odpowiedź za pomocą mxins, jeśli chcesz spróbować. Moim zdaniem wolę tak skonfigurować aplikację.
— Omar Tanti

Odpowiedzi:


275

W końcu zdecydowałem się na stosowanie dyrektywy Vueref . Umożliwia to odwołanie do komponentu od rodzica w celu uzyskania bezpośredniego dostępu.

Na przykład

Poproś o zarejestrowanie komponentu w mojej instancji nadrzędnej:

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

Renderuj komponent w szablonie / HTML z referencją:

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

Teraz gdzie indziej mogę uzyskać dostęp do komponentu na zewnątrz

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

Zobacz to skrzypce na przykład: https://jsfiddle.net/xmqgnbu3/1/

(stary przykład z wykorzystaniem Vue 1: https://jsfiddle.net/6v7y6msr/ )


6
To dlatego, że prawdopodobnie go nie zdefiniowałeś. Spójrz na połączone skrzypce.
— harryg

29
Jeśli używasz pakietu webpack, nie będziesz mieć dostępu vmdo niego ze względu na sposób, w jaki obejmuje on moduły. Możesz zrobić coś takiego window.app = vmw swoim main.js. Źródło: forum.vuejs.org/t/how-to-access-vue-from-chrome-console/3606
— tw airball

1
Czy to podejście można uznać za normalne? Czy to hack?
— CENT1PEDE

3
Istnieje tak oficjalna definicja tego, co jest hackiem, a czym jest „normalne” kodowanie, ale zamiast nazwać to podejście hackem (lub poszukać „mniej hackerskiego” sposobu osiągnięcia tego samego), prawdopodobnie lepiej jest zapytać, dlaczego należy to zrobić to. W wielu przypadkach bardziej eleganckie może być użycie systemu zdarzeń Vue do wyzwalania zachowania komponentów zewnętrznych, a nawet pytanie, dlaczego w ogóle wywołujesz komponenty.
— harryg

8
Może się to pojawić, jeśli próbujesz zintegrować komponent widoku z już istniejącą stroną. Zamiast całkowicie przeprojektowywać stronę, czasem miło jest stopniowo dodawać dodatkową funkcjonalność.
— Allen Wang

37

Od wersji Vue2 dotyczy to:

var bus = new Vue()

// w metodzie komponentu A.

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

// w utworzonym haku komponentu B.

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

  // ...
})

Zobacz tutaj dokumenty Vue. A oto więcej szczegółów na temat tego, jak dokładnie skonfigurować tę magistralę zdarzeń.

Jeśli chcesz uzyskać więcej informacji o tym, kiedy korzystać z właściwości, zdarzeń i / lub scentralizowanego zarządzania stanem, przeczytaj ten artykuł .


1
Krótkie i słodkie! Jeśli nie podoba ci się buszmienna globalna , możesz pójść o krok dalej i wstrzyknąć magistralę do swojego komponentu za pomocą rekwizytów . Jestem stosunkowo nowy, aby vue, więc nie mogę cię zapewnić, że to idiomatyczne.
— byxor

31

Możesz użyć systemu zdarzeń Vue

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

i

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

Oto skrzypce: http://jsfiddle.net/hfalucas/wc1gg5v4/59/


5
@GusDeCooL przykład został edytowany. Nie, że po Vuejs 2.0 niektóre stosowane tam metody zostały przestarzałe
— Helder Lucas

1
Działa dobrze, jeśli jest tylko 1 instancja składnika, ale jeśli jest wiele instancji, lepiej użyć $ refs.component.method ()
— Koronos

22

Nieco inna (prostsza) wersja zaakceptowanej odpowiedzi:

Poproś o zarejestrowanie komponentu w instancji nadrzędnej:

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

Renderuj komponent w szablonie / HTML z referencją:

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

Uzyskaj dostęp do metody komponentu:

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

22

Możesz ustawić ref dla komponentów potomnych, a następnie w rodzicu możesz wywoływać za pomocą $ refs:

Dodaj odwołanie do komponentu potomnego:

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

Dodaj zdarzenie kliknięcia do elementu nadrzędnego:

<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>


2
najczystsze jak dotąd rozwiązanie.
— grreeenn

Świetna odpowiedź. Zamierzam edytować HTML, aby był nieco mniejszy w pionie. Obecnie widzę „wewnętrzny przycisk” tylko po uruchomieniu, co może być mylące.
— Jesse Reza Khorasanee

8

Załóżmy, że masz element child_method()podrzędny:

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

Teraz chcesz uruchomić child_methodkomponent nadrzędny:

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

Jeśli chcesz wykonać metodę komponentu nadrzędnego z komponentu podrzędnego:

this.$parent.name_of_method()

UWAGA: Nie jest zalecane uzyskiwanie dostępu do elementu podrzędnego i nadrzędnego w ten sposób.

Zamiast tego, jako najlepszą praktykę, używaj Rekwizytów i wydarzeń do komunikacji rodzic-dziecko.

Jeśli chcesz komunikować się między komponentami, z pewnością użyj vuex lub magistrali zdarzeń

Przeczytaj ten bardzo pomocny artykuł



Tak, możesz, ale nie uznaje się za „najlepszą praktykę”: w dół do właściwości użycia Dziecko, w górę do zdarzeń użycia Rodzic. Aby objąć również „boczne”, użyj niestandardowych zdarzeń lub np. Vuex. Zobacz ten miły artykuł, aby uzyskać więcej informacji.
— musicformellons,

Tak, nie jest to zalecane.
— roli roli

3

Jest to prosty sposób na uzyskanie dostępu do metod komponentu z innego komponentu

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


1

Nie jestem pewien, czy to właściwa droga, ale ta działa dla mnie.
Najpierw zaimportuj komponent zawierający metodę, którą chcesz wywołać w komponencie

import myComponent from './MyComponent'

a następnie wywołać dowolną metodę MyCompenent

myComponent.methods.doSomething()

nie daje to dostępu do żadnych danych w komponencie. jeśli doSomethingużywasz czegoś z danych, ta metoda jest bezużyteczna.
— cyboashu

-7

Użyłem bardzo prostego rozwiązania. W wybranym przeze mnie komponencie Vue umieściłem element HTML, który wywołuje tę metodę, używając Vanilla JS i uruchamiam kliknięcie!

W komponencie Vue zamieściłem coś takiego:

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

Korzystam z Vanilla JS:

const btnReload = document.querySelector('[data-id="btnReload"]');
btnReload.click();                

W ogóle nie jest to uważane za dobrą praktykę, szczególnie w kontekście pytania PO.
— Hybrid web dev
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.