Виклик методу компонента Vue.js з-за межі компонента


229

Скажімо, у мене є головний екземпляр Vue, який містить дочірні компоненти. Чи існує спосіб виклику методу, що належить до одного з цих компонентів, поза інстанцією Vue цілком?

Ось приклад:

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>

Отже, коли я натискаю внутрішню кнопку, increaseCount()метод прив'язується до події клацання, щоб його викликали. Немає можливості прив’язати подію до зовнішньої кнопки, чию подію натискання я слухаю за допомогою jQuery, тому мені знадобиться інший спосіб зателефонувати increaseCount.

EDIT

Здається, це працює:

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

Однак це не гарне рішення, тому що я посилаю компонент на його індекс у дитячому масиві, і з багатьма компонентами це навряд чи залишатиметься постійним, а код є менш читабельним.


1
Я додав відповідь за допомогою mxins, якщо ви хочете спробувати. На мою думку, я вважаю за краще налаштувати додаток таким чином.
Омар Танті

Відповіді:


275

Врешті-решт я вирішив використовувати директиву Vueref . Це дозволяє посилатися на компонент від батьків для прямого доступу.

Напр

Зареєструйте компетентного в моєму батьківському екземплярі:

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

Візуалізуйте компонент у шаблоні / html із посиланням:

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

Тепер я в іншому місці можу отримати доступ до компонента зовнішньо

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

Дивіться цей приклад для прикладу: https://jsfiddle.net/xmqgnbu3/1/

(старий приклад за допомогою Vue 1: https://jsfiddle.net/6v7y6msr/ )


6
Це тому, що ви, мабуть, цього не визначили. Подивіться на зв’язану скрипку.
harryg

29
Якщо ви використовуєте веб-пакет, ви не зможете отримати доступ vmчерез те, як він охоплює модулі. Ви можете зробити щось на кшталт window.app = vmсвого main.js. Джерело: forum.vuejs.org/t/how-to-access-vue-from-chrome-console/3606
tw airball

1
Чи можна вважати такий підхід нормальним? Або це хакер?
CENT1PEDE

3
Існує настільки офіційне визначення, що таке хак проти того, що "нормальне" кодування, але замість того, щоб називати такий підхід хак (або шукати "менш хакізний" спосіб досягнення того ж самого), напевно, краще запитати, чому вам потрібно робити це. У багатьох випадках може бути більш елегантним використовувати систему подій Vue, щоб викликати поведінку зовнішніх компонентів, або навіть запитати, чому ви взагалі запускаєте компоненти зовні.
харріг

8
Це може з’явитися, якщо ви намагаєтесь інтегрувати компонент перегляду у вже існуючу сторінку. Замість того, щоб повністю переробляти сторінку, приємно іноді поступово додавати додаткову функціональність.
Аллен Ван

37

Оскільки Vue2 це стосується:

var bus = new Vue()

// у методі компонента A

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

// у компоненті B створений гачок

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

  // ...
})

Ознайомтесь тут із документами Vue. І тут більш докладно про те , як налаштувати цей автобус події точно.

Якщо ви хочете отримати більше інформації про те, коли використовувати властивості, події та / або централізоване управління державою, див цю статтю .


1
Коротке і солодке! Якщо ви не любите глобальну busзмінну, ви можете піти на крок далі та ввести шину у свій компонент за допомогою реквізиту . Я відносно новий для того, щоб визначити, що я не можу запевнити, що це ідіоматично.
byxor

31

Ви можете використовувати систему подій Vue

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

і

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

Ось скрипка: http://jsfiddle.net/hfalucas/wc1gg5v4/59/


5
@GusDeCooL приклад відредаговано. Не те, що після Vuejs 2.0 деякі методи, які використовувались там, були присуджені
Хелдер Лукас

1
Добре працює, якщо є лише 1 екземпляр компонента, але якщо екземплярів багато, для роботи краще використовувати $ refs.component.method ()
Коронос

22

Трохи інша (простіша) версія прийнятої відповіді:

Зареєструйте компонент у батьківському екземплярі:

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

Візуалізуйте компонент у шаблоні / html із посиланням:

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

Доступ до методу компонентів:

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

22

Ви можете встановити ref для дочірніх компонентів, тоді в батьківському телефоні можна зателефонувати через $ refs:

Додати посилання на дочірній компонент:

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

Додати подію кліку до батьків:

<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
найчистішим рішенням поки що.
grreeenn

Чудова відповідь. Я просто збираюся редагувати html, щоб бути трохи меншим по вертикалі. В даний час я бачу "Внутрішню кнопку" лише тоді, коли запускаю її, що може бути заплутано.
Джессі Реза Хорасані

8

Скажіть, у вас є child_method()дочірній компонент:

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

Тепер ви хочете виконати child_methodз батьківського компонента:

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

Якщо ви хочете виконати метод батьківського компонента з дочірнього компонента:

this.$parent.name_of_method()

ПРИМІТКА. Не рекомендується отримувати доступ до дочірніх та батьківських компонентів, як це.

Натомість як найкраща практика використовуйте реквізити та події для спілкування батько-дитина.

Якщо ви хочете спілкуватися між компонентами, обов'язково використовуйте vuex або шину подій

Будь ласка, прочитайте цю дуже корисну статтю



Так, ви можете, але не вважаєтесь «найкращою практикою»: зменшення властивостей до використання для дітей, вгору до подій використання батьків. Щоб також охопити "збоку", використовуйте власні події або, наприклад, vuex. Дивіться цю приємну статтю для отримання додаткової інформації.
musicformellons

Так, це не рекомендується робити.
roli roli

3

Це простий спосіб отримати доступ до методів компонента з іншого компонента

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

Я не впевнений, чи це правильний шлях, але це працює для мене.
Спочатку імпортуйте компонент, який містить метод, який ви хочете викликати у своєму компоненті

import myComponent from './MyComponent'

а потім викликати будь-який метод MyCompenent

myComponent.methods.doSomething()

це не дає вам доступу до будь-яких даних вашого компонента. якщо ви doSomethingвикористовуєте будь-яку річ із даних, цей метод марний.
cyboashu

-7

Я використав дуже просте рішення. Я включив елемент HTML, який викликає метод, у свій Vue Component, який я вибираю, використовуючи Vanilla JS, і запускаю клацання!

У компонент Vue я включив щось таке:

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

Я використовую Vanilla JS:

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

Це взагалі не вважається належною практикою, особливо в контексті питання ОП.
Гібридна веб-
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.