Виклик методу компонента 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.