1. component间通信overview
in Vue.jsapplicationin, component间通信 is 指不同component之间传递data and event mechanism. Vueproviding了 many 种component间通信方式, 适用于不同 场景.
1.1 component间通信 场景
- 父子component通信
- 兄弟component通信
- 跨级component通信
- 任意component间通信
1.2 component间通信 方式
- props (父向子传递data)
- event (子向父传递data)
- event总线 (任意component间通信)
- Provide/Inject (祖先向 after 代传递data)
- Vuex/Pinia (statusmanagementlibrary)
- $parent/$children (直接访问componentinstance)
- $refs (直接访问DOM or componentinstance)
2. 父子component通信
父子component is 最common componentrelationships, Vueproviding了props and eventmechanism来implementation父子component间 双向通信.
2.1 父向子传递data: props
父componentthroughprops向子component传递data, 子componentthroughprops选项接收data.
// 父component
var ParentComponent = {
template: `
<div class="parent">
<h3>父component</h3>
<p>父componentdata: {{ message }}</p>
<ChildComponent :message="message" :count="count"></ChildComponent>
</div>
`,
data: function() {
return {
message: 'Hello from parent',
count: 100
};
},
components: {
'ChildComponent': ChildComponent
}
};
// 子component
var ChildComponent = {
template: `
<div class="child">
<h4>子component</h4>
<p>父component传递 message: {{ message }}</p>
<p>父component传递 计数: {{ count }}</p>
</div>
`,
props: ['message', 'count']
};
2.2 子向父传递data: event
子componentthrough$emitmethod触发event, 父componentthroughv-on指令监听event来接收data.
// 父component
var ParentComponent = {
template: `
<div class="parent">
<h3>父component</h3>
<p>子component传递 data: {{ childData }}</p>
<ChildComponent @child-event="handleChildEvent"></ChildComponent>
</div>
`,
data: function() {
return {
childData: ''
};
},
methods: {
handleChildEvent: function(data) {
this.childData = data;
console.log('收 to 子component event:', data);
}
},
components: {
'ChildComponent': ChildComponent
}
};
// 子component
var ChildComponent = {
template: `
<div class="child">
<h4>子component</h4>
<button @click="sendMessage">向父component发送message</button>
</div>
`,
methods: {
sendMessage: function() {
// 触发自定义event, 传递data
this.$emit('child-event', 'Hello from child');
}
}
};
2.3 父子component双向data绑定: v-model
v-model指令可以implementation父子component间 双向data绑定, 它practical on is props and event 语法糖.
// 父component
var ParentComponent = {
template: `
<div class="parent">
<h3>父component</h3>
<p>父componentdata: {{ message }}</p>
<ChildComponent v-model="message"></ChildComponent>
</div>
`,
data: function() {
return {
message: 'Hello'
};
},
components: {
'ChildComponent': ChildComponent
}
};
// 子component
var ChildComponent = {
template: `
<div class="child">
<h4>子component</h4>
<input type="text" :value="value" @input="updateValue">
</div>
`,
props: ['value'], // v-model默认usingvalueserving asprop
methods: {
updateValue: function(event) {
// v-model默认监听inputevent
this.$emit('input', event.target.value);
}
}
};
自定义v-model
可以throughmodel选项自定义v-model prop and event名.
// 子component
var ChildComponent = {
template: `
<div class="child">
<h4>子component</h4>
<input type="text" :value="modelValue" @input="updateValue">
</div>
`,
model: {
prop: 'modelValue', // 自定义prop名
event: 'update:modelValue' // 自定义event名
},
props: ['modelValue'],
methods: {
updateValue: function(event) {
this.$emit('update:modelValue', event.target.value);
}
}
};
3. 兄弟component通信
兄弟component之间没 has 直接 通信方式, 需要through父componentserving asin间媒介, or 者usingevent总线, statusmanagementlibraryetc.方式.
3.1 through父componentin转
兄弟componentthrough父componentserving asin间媒介来传递data.
// 父component
var ParentComponent = {
template: `
<div class="parent">
<h3>父component</h3>
<BrotherA @send-data="handleDataFromA"></BrotherA>
<BrotherB :data="sharedData"></BrotherB>
</div>
`,
data: function() {
return {
sharedData: ''
};
},
methods: {
handleDataFromA: function(data) {
this.sharedData = data;
}
},
components: {
'BrotherA': BrotherA,
'BrotherB': BrotherB
}
};
// 兄弟componentA
var BrotherA = {
template: `
<div class="brother-a">
<h4>兄弟componentA</h4>
<button @click="sendToB">向兄弟componentB发送data</button>
</div>
`,
methods: {
sendToB: function() {
this.$emit('send-data', 'Hello from Brother A');
}
}
};
// 兄弟componentB
var BrotherB = {
template: `
<div class="brother-b">
<h4>兄弟componentB</h4>
<p>来自兄弟componentA data: {{ data }}</p>
</div>
`,
props: ['data']
};
3.2 event总线
event总线 is a simple release-subscribe模式, 适用于任意component间通信.
// creationevent总线
var bus = new Vue();
// componentA: releaseevent
var ComponentA = {
template: `
<div class="component-a">
<h4>componentA</h4>
<button @click="sendMessage">发送message</button>
</div>
`,
methods: {
sendMessage: function() {
// releaseevent
bus.$emit('custom-event', 'Hello from Component A');
}
}
};
// componentB: subscribeevent
var ComponentB = {
template: `
<div class="component-b">
<h4>componentB</h4>
<p>收 to message: {{ message }}</p>
</div>
`,
data: function() {
return {
message: ''
};
},
created: function() {
// subscribeevent
var that = this;
bus.$on('custom-event', function(data) {
that.message = data;
});
}
};
注意
usingevent总线时, 需要注意 in component销毁时取消event监听, 避免memory泄漏.
created: function() {
this.busListener = bus.$on('custom-event', function(data) {
this.message = data;
}.bind(this));
},
beforeDestroy: function() {
// 取消event监听
bus.$off('custom-event', this.busListener);
};
4. 跨级component通信
跨级component is 指父component 子component 子component, or 者更深层次 componentrelationships.
4.1 Provide/Inject API
Vue 2.2.0+ providing了Provide/Inject API, 允许祖先component向其所 has after 代component注入依赖, 无论component层次 has how deep.
// 祖先component
var AncestorComponent = {
template: `
<div class="ancestor">
<h3>祖先component</h3>
<ParentComponent></ParentComponent>
</div>
`,
provide: function() {
return {
ancestorData: 'Hello from ancestor',
ancestorMethod: this.ancestorMethod
};
},
methods: {
ancestorMethod: function() {
console.log('This is a method from ancestor');
}
},
components: {
'ParentComponent': ParentComponent
}
};
// 父component
var ParentComponent = {
template: `
<div class="parent">
<h4>父component</h4>
<ChildComponent></ChildComponent>
</div>
`,
components: {
'ChildComponent': ChildComponent
}
};
// 子component ( after 代component)
var ChildComponent = {
template: `
<div class="child">
<h5>子component</h5>
<p>来自祖先component data: {{ ancestorData }}</p>
<button @click="callAncestorMethod">调用祖先component method</button>
</div>
`,
inject: ['ancestorData', 'ancestorMethod'], // 注入祖先componentproviding 依赖
methods: {
callAncestorMethod: function() {
this.ancestorMethod();
}
}
};
提示
Provide/Inject API主要用于 high 阶插件/componentlibrary Development, 不推荐 in 普通applicationinusing, 因 for 它会使component 依赖relationships变得不明确.
4.2 throughprops and event层层传递
可以throughprops将data from 祖先component层层传递给 after 代component, throughevent将data from after 代component层层传递给祖先component. 但这种方式 in component层次较深时会变得繁琐.
5. statusmanagementlibrary
for 于 complex application, Vue推荐usingstatusmanagementlibrary (such asVuex or Pinia) 来managementcomponent间共享 status.
5.1 VuexIntroduction
Vuex is Vue 官方statusmanagementlibrary, 它providing了一个集in式storemanagementapplication 所 has component status, 并以相应 规则保证status以一种可预测 方式发生变化.
Vuex core concepts
- State: storeapplicationstatus object
- Getter: from Stateinfork出 new status
- Mutation: modifyState 唯一方式, 必须 is synchronizationfunction
- Action: processingasynchronousoperation, 可以submittingMutation
- Module: 将Store分割成module, 便于management
5.2 PiniaIntroduction
Pinia is Vue 3 官方statusmanagementlibrary, 它providing了更简洁 API, 更 good TypeScriptsupport, 以及更flexible architecture.
Pinia 优势
- 更简洁 API, 不需要Mutation
- 更 good TypeScriptsupport
- support many 个Store
- supportComposition API
- 体积更 small , performance更 good
提示
in after 续 课程in, 我们将详细介绍Vuex and Pinia using.
6. other通信方式
Vue还providing了一些other component间通信方式, 虽然不推荐 in produceenvironmentin频繁using, 但 in 某些specific场景 under 可能会 has 用.
6.1 $parent/$children
可以through$parent访问父componentinstance, through$children访问子componentinstancelist.
// 父component访问子component
this.$children[0].someMethod();
// 子component访问父component
this.$parent.someMethod();
warning
using$parent/$children会使component间耦合度增加, 不利于component 复用 and maintenance, 不推荐频繁using.
6.2 $refs
可以through$refs访问DOM元素 or componentinstance.
// 父component模板
<ChildComponent ref="childRef"></ChildComponent>
// 父component访问子componentinstance
this.$refs.childRef.someMethod();
7. component间通信 best practices
7.1 选择合适 通信方式
- 父子component: 优先usingprops and event, or 者v-model
- 兄弟component: 优先using父componentin转, or 者event总线, complex 场景usingVuex/Pinia
- 跨级component: 优先usingProvide/Inject API, complex 场景usingVuex/Pinia
- 任意component: 优先usingevent总线, complex 场景usingVuex/Pinia
7.2 避免过度耦合
- 尽量reducingcomponent间 直接依赖
- 避免using$parent/$children
- complex statusmanagementusingVuex/Pinia
7.3 保持单向data流
尽量保持data流 单向性, 即父componentthroughprops向子component传递data, 子componentthroughevent向父component发送message, 避免直接modifyprops.
7.4 合理usingstatusmanagementlibrary
for 于 complex application, 合理usingVuex/Pinia可以简化component间通信, improvingcode 可maintenance性. 但 for 于 simple application, usingprops and event可能更加 high 效.
练习 1: 父子component通信
- creation一个父component and 一个子component.
- 父component向子component传递一个listdata.
- 子component显示该list, 并 for 每个list项添加一个delete按钮.
- 点击delete按钮时, 子component向父component发送event, 父componentdelete for 应 list项.
练习 2: event总线
- creation一个event总线.
- creation三个component: componentA, componentB and componentC.
- componentA发送event, componentB and componentC接收event并显示data.
- 确保 in component销毁时取消event监听.
练习 3: Provide/Inject API
- creation一个祖先component, providing一些data and method.
- creation一个父component, 嵌套 in 祖先componentin.
- creation一个子component, 嵌套 in 父componentin.
- 子componentusingInject API获取祖先componentproviding data and method, 并 in 页面 on 显示 and 调用.