Gọi một phương thức thành phần Vue.js từ bên ngoài thành phần


229

Giả sử tôi có một ví dụ Vue chính có các thành phần con. Có cách nào gọi một phương thức thuộc một trong các thành phần này từ bên ngoài thể hiện Vue không?

Đây là một ví dụ:

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>

Vì vậy, khi tôi nhấp vào nút bên trong, increaseCount()phương thức được liên kết với sự kiện nhấp của nó để nó được gọi. Không có cách nào để liên kết sự kiện với nút bên ngoài, sự kiện nhấp mà tôi đang nghe với jQuery, vì vậy tôi sẽ cần một số cách khác để gọi increaseCount.

BIÊN TẬP

Có vẻ như điều này hoạt động:

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

Tuy nhiên, đây không phải là một giải pháp tốt vì tôi đang tham chiếu thành phần theo chỉ số của nó trong mảng con và với nhiều thành phần, điều này khó có thể giữ nguyên và mã ít đọc hơn.


1
Tôi đã thêm một câu trả lời bằng mxins nếu bạn muốn dùng thử. Theo ý kiến ​​của tôi, tôi thích thiết lập ứng dụng theo cách này.
Omar Tanti

Câu trả lời:


275

Cuối cùng, tôi đã chọn sử dụng chỉ thị của Vueref . Điều này cho phép một thành phần được tham chiếu từ cha mẹ để truy cập trực tiếp.

Ví dụ

Có một thành viên đã đăng ký trên ví dụ cha mẹ của tôi:

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

Kết xuất thành phần trong mẫu / html với một tham chiếu:

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

Bây giờ, ở nơi khác tôi có thể truy cập thành phần bên ngoài

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

Xem fiddle này cho một ví dụ: https://jsfiddle.net/xmqgnbu3/1/

(ví dụ cũ sử dụng Vue 1: https://jsfiddle.net/6v7y6msr/ )


6
Đó là bởi vì bạn có thể đã không định nghĩa nó. Nhìn vào fiddle liên kết.
harryg

29
Nếu bạn đang sử dụng gói web thì bạn sẽ không thể truy cập vmdo cách nó phạm vi các mô-đun. Bạn có thể làm một cái gì đó như window.app = vmtrong của bạn main.js. Nguồn: forum.vuejs.org/t/how-to-access-vue-from-chrome-console/3606
tw airball

1
Cách tiếp cận này có thể được coi là bình thường? Hay đây là một hack?
CENT1PEDE

3
Có định nghĩa chính thức về việc hack là gì so với mã hóa "thông thường", nhưng thay vì gọi phương pháp này là hack (hoặc tìm cách "ít hack" hơn để đạt được điều tương tự) có lẽ tốt hơn nên hỏi tại sao bạn cần phải làm điều này. Trong nhiều trường hợp, có thể thanh lịch hơn khi sử dụng hệ thống sự kiện của Vue để kích hoạt hành vi thành phần bên ngoài hoặc thậm chí hỏi tại sao bạn lại kích hoạt các thành phần bên ngoài.
harryg

8
Điều này có thể xuất hiện nếu bạn đang cố gắng tích hợp một thành phần xem vào một trang đã có sẵn. Thay vì thiết kế lại toàn bộ trang, đôi khi thật tốt khi thêm chức năng bổ sung.
Allen Wang

37

Vì Vue2 nên điều này áp dụng:

var bus = new Vue()

// trong phương thức của thành phần A

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

// trong hook hook của thành phần B

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

  // ...
})

Xem ở đây cho các tài liệu Vue. Và đây là chi tiết hơn về cách thiết lập chính xác xe buýt sự kiện này.

Nếu bạn muốn biết thêm thông tin về thời điểm sử dụng các thuộc tính, sự kiện và / hoặc quản lý nhà nước tập trung, hãy xem bài viết này .


1
Ngắn và ngọt! Nếu bạn không thích busbiến toàn cục, bạn có thể tiến thêm một bước và đưa xe buýt vào thành phần của mình bằng các đạo cụ . Tôi còn khá mới với vue nên tôi không thể đảm bảo với bạn rằng đây là thành ngữ.
byxor

31

Bạn có thể sử dụng hệ thống sự kiện Vue

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

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

Đây là câu đố: http://jsfiddle.net/hfalucas/wc1gg5v4/59/


5
@GusDeCooL ví dụ đã được chỉnh sửa. Không phải là sau Vuejs 2.0, một số phương thức được sử dụng đã bị phản đối
Helder Lucas

1
Hoạt động tốt nếu chỉ có 1 phiên bản thành phần, nhưng nếu có nhiều phiên bản, hoạt động tốt hơn sử dụng $ refs.component.method ()
Koronos 22/12/17

22

Một phiên bản hơi khác (đơn giản hơn) của câu trả lời được chấp nhận:

Có một thành phần được đăng ký trên ví dụ cha:

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

Kết xuất thành phần trong mẫu / html với một tham chiếu:

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

Truy cập phương thức thành phần:

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

22

Bạn có thể đặt ref cho các thành phần con, sau đó, cha mẹ có thể gọi qua $ refs:

Thêm ref vào thành phần con:

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

Thêm sự kiện nhấp vào cha mẹ:

<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
giải pháp sạch nhất cho đến nay.
grreeenn

Câu trả lời chính xác. Tôi sẽ chỉnh sửa html để nhỏ hơn một chút theo chiều dọc. Hiện tại tôi chỉ có thể thấy 'Nút nội bộ' khi tôi chạy nó có thể gây nhầm lẫn.
Jesse Reza Khorasanee

8

Giả sử bạn có một child_method()thành phần con:

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

Bây giờ bạn muốn thực thi child_methodthành phần cha mẹ:

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

Nếu bạn muốn thực thi một phương thức thành phần cha mẹ từ thành phần con:

this.$parent.name_of_method()

LƯU Ý: Không nên truy cập thành phần con và cha mẹ như thế này.

Thay vào đó, cách tốt nhất là sử dụng Đạo cụ & Sự kiện để liên lạc giữa cha mẹ và con cái.

Nếu bạn muốn liên lạc giữa các thành phần chắc chắn sử dụng vuex hoặc xe buýt sự kiện

Xin vui lòng đọc bài viết rất hữu ích này



Có, bạn có thể, nhưng không được coi là 'cách thực hành tốt nhất': hướng xuống các thuộc tính sử dụng của Trẻ em, hướng lên các sự kiện sử dụng của Phụ huynh. Để cũng bao gồm 'các bên', hãy sử dụng các sự kiện tùy chỉnh, hoặc ví dụ vuex. Xem bài viết tốt đẹp này để biết thêm.
nhạc nền

Có nó không nên làm như vậy.
roli roli

3

Đây là một cách đơn giản để truy cập các phương thức của thành phần từ thành phần khác

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

Tôi không chắc chắn đó là cách đúng đắn nhưng điều này làm việc cho tôi.
Trước tiên, nhập thành phần có chứa phương thức bạn muốn gọi trong thành phần của bạn

import myComponent from './MyComponent'

và sau đó gọi bất kỳ phương thức nào của MyCompenent

myComponent.methods.doSomething()

điều này không cung cấp cho bạn quyền truy cập vào bất kỳ dữ liệu nào trong thành phần của bạn. nếu bạn doSomethingđang sử dụng bất cứ thứ gì từ dữ liệu, phương pháp này là vô ích.
cyboashu

-7

Tôi đã sử dụng một giải pháp rất đơn giản. Tôi đã bao gồm một phần tử HTML, gọi phương thức đó, trong Thành phần Vue mà tôi chọn, sử dụng Vanilla JS và tôi kích hoạt nhấp chuột!

Trong Thành phần Vue, tôi đã bao gồm một cái gì đó như sau:

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

Tôi sử dụng Vanilla JS:

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

Đây không được coi là thực hành tốt trong tất cả các vue, đặc biệt là trong bối cảnh câu hỏi của OP.
Lai web dev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.