Cách truy cập vào một phương thức con từ cha mẹ trong vue.js


92

Tôi có hai thành phần lồng nhau, cách thích hợp để truy cập vào các phương thức con từ cha mẹ là gì?

this.$children[0].myMethod() có vẻ như thực hiện thủ thuật nhưng nó khá xấu, phải không, còn cách nào tốt hơn:

<script>
import child from './my-child'

export default {
  components: {
   child
  },
  mounted () {
    this.$children[0].myMethod()
  }
}
</script>

Trước tiên, hãy tự hỏi bản thân bạn có thực sự cần thiết không. Nếu tất cả trạng thái trang của bạn là trong một cửa hàng, như lẽ phải, thì không cần giao tiếp giữa phụ huynh và con cái.
bbsimonbb

7
@bbsimonbb Trạng thái khác với các sự kiện. Điều này đặc biệt về việc kích hoạt các sự kiện con từ cha mẹ. Bạn cũng có thể làm bất cứ điều gì bạn đang sử dụng Vuex bằng cách chuyển một phần tử hỗ trợ xuống dòng nhưng điều này yêu cầu thành phần con phải theo dõi phần hỗ trợ / lưu trữ các thay đổi để bạn mô phỏng RPC một cách hiệu quả với các thay đổi dữ liệu, điều này hoàn toàn sai khi tất cả những gì bạn muốn là kích hoạt một hành động trong thành phần.
Bojan Markovic

Câu trả lời:


244

Bạn có thể sử dụng ref .

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {}
  },
  template: `
  <div>
     <ChildForm :item="item" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.$refs.form.submit()
    }
  },
  components: { ChildForm },
})

Nếu bạn không thích khớp nối chặt chẽ, bạn có thể sử dụng Xe buýt sự kiện như được hiển thị bởi @Yosvel Quintero. Dưới đây là một ví dụ khác về việc sử dụng bus sự kiện bằng cách đi qua bus làm đạo cụ.

import ChildForm from './components/ChildForm'

new Vue({
  el: '#app',
  data: {
    item: {},
    bus: new Vue(),
  },
  template: `
  <div>
     <ChildForm :item="item" :bus="bus" ref="form" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.bus.$emit('submit')
    }
  },
  components: { ChildForm },
})

Mã thành phần.

<template>
 ...
</template>

<script>
export default {
  name: 'NowForm',
  props: ['item', 'bus'],
  methods: {
    submit() {
        ...
    }
  },
  mounted() {
    this.bus.$on('submit', this.submit)
  },  
}
</script>

https://code.luasoftware.com/tutorials/vuejs/parent-call-child-component-method/


38
Đây là câu trả lời chính xác, thực sự đọc câu hỏi thực tế. Câu trả lời được chọn thực sự trả lời câu hỏi ngược lại (cách kích hoạt một phương thức trên cha từ thành phần con).
Bojan Markovic

1
Liên kết cho Xe buýt sự kiện mà câu trả lời này đang liên kết, đang chuyển hướng đến Quản lý nhà nước , sau khi đọc bình luận @bbsimonbb , nó có lý.
Eido95

2
Điều đáng nói là nếu bạn sử dụng this.$refs., bạn không nên tải động thành phần con.
1_bug

cảm ơn ngài! Bạn đã cứu tôi rất nhiều rắc rối. Tôi đang khắc phục sự cố sản xuất và đang tìm kiếm câu trả lời trong tuyệt vọng! <3
Osama Ibrahim

this.$ref.refdường như trả về một mảng. Vì vậy, đối với tôi this.$refs.ref[0].autofocus();đã làm việc
Jozef Plata

27

Giao tiếp giữa cha mẹ và con cái trong VueJS

Với một cá thể Vue gốc có thể được truy cập bởi tất cả các this.$rootthành phần con thông qua , một thành phần cha có thể truy cập các thành phần con thông qua this.$childrenmảng và một thành phần con có thể truy cập vào nó thông qua cha mẹ this.$parent, bản năng đầu tiên của bạn có thể là truy cập trực tiếp vào các thành phần này.

Tài liệu VueJS cảnh báo cụ thể chống lại điều này vì hai lý do rất tốt:

  • Nó kết hợp chặt chẽ giữa cha mẹ với con cái (và ngược lại)
  • Bạn không thể dựa vào trạng thái của cha mẹ, vì nó có thể được sửa đổi bởi một thành phần con.

Giải pháp là sử dụng giao diện sự kiện tùy chỉnh của Vue

Giao diện sự kiện được thực hiện bởi Vue cho phép bạn giao tiếp lên và xuống cây thành phần. Tận dụng giao diện sự kiện tùy chỉnh cho phép bạn truy cập vào bốn phương pháp:

  1. $on() - cho phép bạn khai báo một trình lắng nghe trên phiên bản Vue của bạn để lắng nghe các sự kiện
  2. $emit() - cho phép bạn kích hoạt các sự kiện trên cùng một trường hợp (bản thân)

Ví dụ sử dụng $on()$emit():

const events = new Vue({}),
    parentComponent = new Vue({
      el: '#parent',
      ready() {
        events.$on('eventGreet', () => {
          this.parentMsg = `I heard the greeting event from Child component ${++this.counter} times..`;
        });
      },
      data: {
        parentMsg: 'I am listening for an event..',
        counter: 0
      }
    }),
    childComponent = new Vue({
      el: '#child',
      methods: {
      greet: function () {
        events.$emit('eventGreet');
        this.childMsg = `I am firing greeting event ${++this.counter} times..`;
      }
    },
    data: {
      childMsg: 'I am getting ready to fire an event.',
      counter: 0
    }
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>

<div id="parent">
  <h2>Parent Component</h2>
  <p>{{parentMsg}}</p>
</div>

<div id="child">
  <h2>Child Component</h2>
  <p>{{childMsg}}</p>
  <button v-on:click="greet">Greet</button>
</div>

Câu trả lời lấy từ bài gốc: Giao tiếp giữa các thành phần trong VueJS


1
Cảm ơn bạn, vì vậy tôi sẽ cố gắng tương tác mã của mình thông qua các sự kiện!
al3x

5
khi sao chép / dán nội dung, bạn cũng nên đề cập đến nguồn.
Mihai Vilcu

17
Điều này rất hữu ích trong việc giao tiếp giữa con cái với cha mẹ. Nhưng có cách nào tương tự để làm điều đó từ cha mẹ sang con cái không? Ví dụ: trước khi cho phép người dùng thêm con mới, tôi muốn tất cả những cái hiện có được xác thực - logic xác thực nằm trong con, vì vậy tôi muốn xem qua tất cả chúng và thực thi phương thức ví dụ: validate ().
Mateusz Bartkowiak

66
Điều này trả lời câu hỏi ngược lại với những gì đã thực sự được hỏi. Câu trả lời của Desmond Lua trả lời câu hỏi thực tế.
Bojan Markovic

4
Xe buýt sự kiện là # 1 trong danh sách phản vật chất vue của Chris Fritz . Bất kỳ thứ gì có thể được mô hình hóa với các sự kiện và trạng thái phân tán đều có thể được mô hình hóa với trạng thái toàn cục và ràng buộc hai chiều, và nói chung, bạn sẽ tốt hơn nhiều.
bbsimonbb

1

Xe buýt tham chiếu và sự kiện đều có vấn đề khi kết xuất điều khiển của bạn bị ảnh hưởng v-if. Vì vậy, tôi quyết định chọn một phương pháp đơn giản hơn.

Ý tưởng là sử dụng một mảng làm hàng đợi để gửi các phương thức cần được gọi đến thành phần con. Khi thành phần được gắn kết, nó sẽ xử lý hàng đợi này. Nó theo dõi hàng đợi để thực thi các phương thức mới.

(Mượn một số mã từ câu trả lời của Desmond Lua)

Mã thành phần chính:

import ChildComponent from './components/ChildComponent'

new Vue({
  el: '#app',
  data: {
    item: {},
    childMethodsQueue: [],
  },
  template: `
  <div>
     <ChildComponent :item="item" :methods-queue="childMethodsQueue" />
     <button type="submit" @click.prevent="submit">Post</button>
  </div>
  `,
  methods: {
    submit() {
      this.childMethodsQueue.push({name: ChildComponent.methods.save.name, params: {}})
    }
  },
  components: { ChildComponent },
})

Đây là mã cho ChildComponent

<template>
 ...
</template>

<script>
export default {
  name: 'ChildComponent',
  props: {
    methodsQueue: { type: Array },
  },
  watch: {
    methodsQueue: function () {
      this.processMethodsQueue()
    },
  },
  mounted() {
    this.processMethodsQueue()
  },
  methods: {
    save() {
        console.log("Child saved...")
    },
    processMethodsQueue() {
      if (!this.methodsQueue) return
      let len = this.methodsQueue.length
      for (let i = 0; i < len; i++) {
        let method = this.methodsQueue.shift()
        this[method.name](method.params)
      }
    },
  },
}
</script>

Và có rất nhiều chỗ để cải thiện như chuyển processMethodsQueuesang mixin ...


0

Để giao tiếp một thành phần con với một thành phần con khác, tôi đã tạo một phương thức trong cha gọi một phương thức trong một thành phần con với:

this.$refs.childMethod()

Và từ một phần tử con khác, tôi đã gọi là phương thức gốc:

this.$root.theRootMethod()

Nó đã làm việc cho tôi.


Câu trả lời này thiếu rất nhiều lời giải thích
vsync
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.