부모 이벤트의 자식 구성 요소에서 함수를 호출하는 방법


164

문맥

Vue 2.0에서 문서와 기타 문서 는 부모와 자식 사이의 커뮤니케이션이 소품을 통해 이루어짐을 분명히 나타냅니다.

질문

부모는 자녀에게 소품을 통해 사건이 발생했음을 어떻게 알립니 까?

이벤트라는 소품을 볼까요? 그것은 옳지 않거나 대안이 아닙니다 ( $emit/ $on는 어린이에서 부모로, 허브 모델은 먼 요소를 위해).

부모 컨테이너가 있으며 API에 대해 특정 작업을 수행해도된다는 것을 자식 컨테이너에 알려 주어야합니다. 기능을 트리거 할 수 있어야합니다.

답변:


234

자식 구성 요소를 제공 ref하고 사용하십시오$refs 대한 메서드를 직접 호출하는 데 합니다.

html :

<div id="app">
  <child-component ref="childComponent"></child-component>
  <button @click="click">Click</button>  
</div>

자바 스크립트 :

var ChildComponent = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
    setValue: function(value) {
        this.value = value;
    }
  }
}

new Vue({
  el: '#app',
  components: {
    'child-component': ChildComponent
  },
  methods: {
    click: function() {
        this.$refs.childComponent.setValue(2.0);
    }
  }
})

자세한 내용 은 심판에 대한 Vue 설명서를 참조하십시오 .


13
이런 식으로 부모와 자식 구성 요소가 결합됩니다. 실제 이벤트의 경우 액션을 트리거하기 위해 소품을 변경할 수 없을 때 @Roy J가 제안한 버스 솔루션을 사용합니다.
Jared

3
워드 프로세서에 대한 심판은 도움이 aswell의 것 vuejs.org/v2/guide/...
ctf0

내 자식 구성 요소에서 특별한 이유로 v-once를 사용하여 반응성을 종료해야했습니다. 따라서 소품을 부모에서 자식으로 전달하는 것은 선택 사항이 아니므 로이 솔루션은 트릭을 수행했습니다!
John

1
초보자 질문 : 소품ref만드는 대신 사용 하는 이유 는 값을보고 부모의 다른 기능으로 방출합니까? 할 일이 많지만 ref안전한 것을 사용 하고 있습니까? 감사합니다
Irfandy Jip

5
@IrfandyJip-예, ref안전합니다. 일반적으로 Vue 커뮤니티는 상태를 어린이에게 전달하고 이벤트를 부모에게 전달하는 것을 선호하기 때문에 권장하지 않습니다. 일반적으로, 이것은보다 고립되고 내부적으로 일관성있는 구성 요소 (good thing ™)로 이어집니다. 그러나 자녀에게 전달하는 정보가 실제로 이벤트 (또는 명령) 인 경우 상태 수정이 올바른 패턴이 아닙니다. 이 경우 a를 사용하여 메소드를 호출하면 ref완전히 괜찮으며 충돌하지 않습니다.
joerick

76

당신이 설명하는 것은 부모의 상태 변화입니다. 당신은 소품을 통해 아이에게 전달합니다. 당신이 제안한대로, 당신은 watch그 소품 을 것 입니다. 자식이 조치를 취하면을 통해 부모에게 알리고 emit부모는 다시 상태를 변경할 수 있습니다.

실제로 어린이에게 이벤트를 전달하려면 버스 (Vue 인스턴스 일뿐)를 만들고이를 자식으로 소품으로 전달하면됩니다 .


2
공식 Vue.JS 스타일 가이드 및 모범 사례와 일치하는 유일한 답변이라고 생각합니다. v-model구성 요소에 속기를 사용하면 적은 코드로 해당 이벤트를 생성하여 값을 쉽게 재설정 할 수도 있습니다.
Falco

예를 들어 사용자가 버튼을 클릭하면 경고를 표시하려고합니다. 예를 들면 다음과 같이 제안합니까?-깃발을보고-클릭이 발생할 때이 깃발을 0에서 1로 설정하십시오.-무언가를 수행하십시오.-깃발 재설정
Sinan Erdem

9
그것은 매우 불편 prop합니다. 자식에서 여분의 속성 data을 만들고에 속성 을 추가 한 다음 추가해야합니다 watch... 어떻게 부모에서 자식으로 이벤트를 전송하는 기본 지원이 있다면 편안합니다. 이 상황은 자주 발생합니다.
Илья Зеленько

1
@ ИльяЗеленько의 상태로, 그것은 꽤 자주 발생하며, 지금은 신의 선물이 될 것입니다.
Craig

1
@RoyJ에게 감사드립니다. 아이가 가입 할 때 버스 소품이 있어야한다고 생각합니다. 아이들에게 이벤트를 보내는 것에 대한 모든 아이디어는 Vue에서 권장하지 않습니다.
벤 와인딩

35

$emit및 을 사용할 수 있습니다 $on. @RoyJ 코드 사용 :

html :

<div id="app">
  <my-component></my-component>
  <button @click="click">Click</button>  
</div>

자바 스크립트 :

var Child = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
    setValue: function(value) {
        this.value = value;
    }
  },
  created: function() {
    this.$parent.$on('update', this.setValue);
  }
}

new Vue({
  el: '#app',
  components: {
    'my-component': Child
  },
  methods: {
    click: function() {
        this.$emit('update', 7);
    }
  }
})

실행 예 : https://jsfiddle.net/rjurado/m2spy60r/1/


6
나는 그것이 작동하는 것에 놀랐습니다. 나는 아이에게 방출하는 것이 반 패턴이거나, 의도는 아이에서 부모로만 방출되는 것이라고 생각했다. 다른 방향으로가는 데 잠재적 인 문제가 있습니까?
jbodily

2
이것은 최선의 방법으로 간주되지 않을 수도 있지만, 잘 모르겠습니다. 무엇을하고 있는지 알고 있다면 문제가 아닙니다. 다른 방법은 중앙 버스를 사용하는 것입니다 : vuejs.org/v2/guide/…
drinor

14
이것은 아동과 부모 사이의 커플 링을 만들고 나쁜 관행으로 간주됩니다
morrislaptop

5
이것은 부모가 구성 요소가 아니라 실제로 vue 앱이기 때문에 작동합니다. 실제로 이것은 vue 인스턴스를 버스로 사용합니다.
Julio Rodrigues

2
@Bsienn이 this. $ parent를 호출하면이 구성 요소가 부모에 종속됩니다. $ emit to 및 props를 사용하므로 Vue의 통신 시스템을 통한 유일한 종속성입니다. 이 방법을 사용하면 구성 요소 계층의 어느 곳에서나 동일한 구성 요소를 사용할 수 있습니다.
morrislaptop

6

시간이 있으면 Vuex 스토어를 사용하여 변수 (일명 상태)를 보거나 작업을 직접 트리거 (일명 디스패치)하십시오.


2
가장 좋은 방법 인 vuejs / vuex의 반응성으로 인해 부모는 vuex 속성 값을 변경하는 동작 / 변경을 수행하고 자식은 동일한 vuex $ store.state.property.value 또는 "watch "뭔가를 할 방법 때 vuex"$ store.state.property.value "변화
FabianSilva

6

동안 아이에서 바인딩을 사용 하는 이벤트 버스 접근 방식이 마음에 들지 않았습니다 . 왜? 후속 통화 (사용중인$oncreatecreatevue-router )은 메시지 처리기를 두 번 이상 바인딩하여 메시지 당 여러 응답을 유발합니다.

소품을 부모에서 자녀에게 전달하고 재산 감시자를 자녀에게 배치하는 정통 솔루션은 조금 더 효과적이었습니다. 문제는 아동이 가치 전환에만 행동 할 수 있다는 것입니다. 동일한 메시지를 여러 번 전달하면 전환을 강제하기 위해 일종의 부기 관리가 필요하므로 자녀가 변경 사항을 선택할 수 있습니다.

배열에서 메시지를 줄 바꿈하면 값이 동일하더라도 자식 감시자를 트리거합니다.

부모의:

{
   data: function() {
      msgChild: null,
   },
   methods: {
      mMessageDoIt: function() {
         this.msgChild = ['doIt'];
      }
   }   
   ...
}

아이:

{
   props: ['msgChild'],
   watch: {
      'msgChild': function(arMsg) {
         console.log(arMsg[0]);
      }
   }
}

HTML :

<parent>
   <child v-bind="{ 'msgChild': msgChild }"></child>
</parent>

1
msgChild가 부모에서 항상 같은 상태 인 경우에는 작동하지 않는다고 생각합니다. 예를 들어 : 모달을 여는 구성 요소를 원합니다. 부모는 현재 상태가 열려 있는지 또는 닫혀 있는지 상관하지 않으며 언제든지 모달을 열려고합니다. 따라서 부모가 this.msgChild = true를 수행하면; 모달이 닫히고 부모가 this.msgChild = true를 수행하면 자식은 이벤트를받지 못합니다.
Jorge Sainz

1
@ JorgeSainz : 데이터 값에 할당하기 전에 값을 배열로 래핑하는 이유입니다. 배열에 값을 래핑하지 않으면 지정한대로 동작합니다. 따라서 msgChild = true, msgChild = true-이벤트가 없습니다. msgChild = [true], msgChild = [true]-이벤트!
Jason Stewart

1
나는 그것을 보지 못했다. 설명을 주셔서 감사합니다
Jorge Sainz 14:01의

이것은 시원하지만 약간의 hackish를 느낍니다. 컴포넌트 참조 해킹을 사용하는 것보다 깨끗하고 이벤트 버스 솔루션보다 덜 복잡하기 때문에 사용할 것입니다. vue는 디커플링을 원하고 상태 변경 만 구성 요소에 영향을 줄 수 있지만 필요한 경우 자식 메서드를 호출하는 기본 방법이 있어야 함을 알고 있습니다. 어쩌면 상태가 변경되면 소품의 수정자가 자동으로 기본값으로 재설정하여 감시자가 다음 상태 변경을 준비 할 수 있습니다. 어쨌든 찾기를 게시 해 주셔서 감사합니다.
Craig

6

자식 구성 요소에서 메서드를 호출하는 간단한 분리 방법은 자식에서 처리기를 생성 한 다음 부모에서 호출하는 것입니다.

var Child = {
  template: '<div>{{value}}</div>',
  data: function () {
    return {
      value: 0
    };
  },
  methods: {
  	setValue(value) {
    	this.value = value;
    }
  },
  created() {
    this.$emit('handler', this.setValue);
  }
}

new Vue({
  el: '#app',
  components: {
    'my-component': Child
  },
  methods: {
  	setValueHandler(fn) {
    	this.setter = fn
    },
    click() {
    	this.setter(70)
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id="app">
  <my-component @handler="setValueHandler"></my-component>
  <button @click="click">Click</button>  
</div>

부모는 자식 핸들러 함수를 추적하고 필요할 때마다 호출합니다.


나는이 솔루션이 어디로 가고 있는지 좋아하지만 부모의 "this.setter"는 정확히 무엇입니까?
Craig

핸들러 이벤트에 대한 인수로 하위 구성 요소에서 생성 한 setValue 함수 참조입니다.
nilobarp

2

아래 예제는 자체 설명입니다. 여기서 refs와 이벤트는 부모와 자식에서 함수를 호출하는 데 사용될 수 있습니다.

// PARENT
<template>
  <parent>
    <child
      @onChange="childCallBack"
      ref="childRef"
      :data="moduleData"
    />
    <button @click="callChild">Call Method in child</button>
  </parent>
</template>

<script>
export default {
  methods: {
    callChild() {
      this.$refs.childRef.childMethod('Hi from parent');
    },
    childCallBack(message) {
      console.log('message from child', message);
    }
  }
};
</script>

// CHILD
<template>
  <child>
    <button @click="callParent">Call Parent</button>
  </child>
</template>

<script>
export default {
  methods: {
    callParent() {
      this.$emit('onChange', 'hi from child');
    },
    childMethod(message) {
      console.log('message from parent', message);
    }
  }
}
</script>

1

부모가 자녀의 방법을 사용해야 할 필요성에 대해 고려해야한다고 생각합니다. 사실 부모는 자녀의 방법에 신경 쓸 필요가 없지만 자식 구성 요소를 FSA (유한 상태 기계)로 취급 할 수 있습니다. 하위 구성 요소의 상태를 제어하기 위해 상태 변경을 보거나 계산 기능을 사용하는 솔루션이면 충분합니다.


2
"부모가 자녀를 통제하는 데 관심을 가져서는 안된다"고 말하면 이것이 필요한 경우가 있습니다. 카운트 다운 타이머 구성 요소를 고려하십시오. 부모는 타이머를 재설정하여 다시 시작할 수 있습니다. 시간 = 60에서 시간 = 60으로 이동해도 소품이 수정되지 않으므로 소품을 사용하는 것만으로는 충분하지 않습니다. 타이머는 부모가 적절하게 호출 할 수있는 '재설정'기능을 노출해야합니다.
tbm

0

키를 사용하여 키를 사용하여 하위 구성 요소를 다시로드 할 수 있습니다

<component :is="child1" :filter="filter" :key="componentKey"></component>

새 필터로 구성 요소를 다시로드하려면 버튼 클릭으로 하위 구성 요소를 필터링하십시오.

reloadData() {            
   this.filter = ['filter1','filter2']
   this.componentKey += 1;  
},

필터를 사용하여 기능을 트리거하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.