本课程将深入讲解UniApp/Vue.js中的组件通信机制,包括父子组件通信、跨组件通信、事件总线、provide/inject等多种通信方式。掌握组件通信技术对于构建复杂应用至关重要。
父子组件通信是最常见的组件通信方式,父组件通过props向子组件传递数据,子组件通过$emit向父组件触发事件。
父组件通过props向子组件传递数据,子组件通过props选项接收数据。
子组件接收到的数据:{{ title }}
计数器:{{ count }}
用户信息:{{ userInfo.name }}
子组件通过$emit触发自定义事件,父组件通过v-on监听事件。
接收到的输入:{{ receivedInput }}
Vue提供了完整的props验证机制,可以确保组件接收到的数据符合预期。
export default {
props: {
basicProp: String,
multipleTypes: [String, Number],
requiredProp: {
type: String,
required: true
},
defaultProp: {
type: Number,
default: 100
},
objectDefault: {
type: Object,
default: () => ({
name: '默认值',
age: 0
})
},
customValidator: {
type: String,
validator: function(value) {
return ['success', 'warning', 'danger'].includes(value)
}
},
asyncProp: {
type: Function,
default: function() {
return Promise.resolve()
}
}
}
}
provide/inject用于跨层级组件通信,祖先组件通过provide提供数据,后代组件通过inject注入数据。
主题颜色:{{ themeColor }}
用户名:{{ userInfo.name }}
角色:{{ userInfo.role }}
默认情况下,provide/inject不是响应式的。如果需要响应式,可以使用Vue的reactive或ref。
主题颜色:{{ theme.color }}
字体大小:{{ theme.fontSize }}
计数:{{ count }}
事件总线是一种发布-订阅模式的通信方式,适用于任意组件之间的通信。
// utils/eventBus.js
import Vue from 'vue'
class EventBus {
constructor() {
this.events = {}
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = []
}
this.events[event].push(callback)
}
off(event, callback) {
if (!this.events[event]) return
if (!callback) {
delete this.events[event]
} else {
this.events[event] = this.events[event].filter(cb => cb !== callback)
}
}
emit(event, payload) {
if (!this.events[event]) return
this.events[event].forEach(callback => {
callback(payload)
})
}
once(event, callback) {
const onceCallback = (payload) => {
callback(payload)
this.off(event, onceCallback)
}
this.on(event, onceCallback)
}
clear() {
this.events = {}
}
}
export default new EventBus()
接收到的消息:{{ receivedMessage }}
一次性消息:{{ oneTimeMessage }}
// main.js
import Vue from 'vue'
import App from './App'
Vue.prototype.$eventBus = new Vue()
new Vue({
render: h => h(App)
}).$mount('#app')
$refs用于直接访问子组件实例,$parent用于访问父组件实例。
子组件内容
子组件数据:{{ childData }}
父组件数据:{{ parentData }}
插槽是Vue提供的一种内容分发机制,也可以用于组件通信。
{{ user.name }}
{{ item.name }}
共 {{ count }} 项
Vuex是Vue的官方状态管理库,适用于大型应用的复杂状态管理。
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0,
userInfo: null,
todos: []
},
mutations: {
INCREMENT(state) {
state.count++
},
SET_USER(state, userInfo) {
state.userInfo = userInfo
},
ADD_TODO(state, todo) {
state.todos.push(todo)
},
REMOVE_TODO(state, todoId) {
state.todos = state.todos.filter(todo => todo.id !== todoId)
}
},
actions: {
increment({ commit }) {
commit('INCREMENT')
},
async fetchUser({ commit }, userId) {
const res = await uni.request({
url: `/api/users/${userId}`
})
commit('SET_USER', res.data)
},
addTodo({ commit }, todo) {
commit('ADD_TODO', todo)
},
removeTodo({ commit }, todoId) {
commit('REMOVE_TODO', todoId)
}
},
getters: {
doubleCount: state => state.count * 2,
completedTodos: state => state.todos.filter(todo => todo.completed),
todoCount: state => state.todos.length
},
modules: {
user: {
namespaced: true,
state: {
profile: null,
settings: {}
},
mutations: {
SET_PROFILE(state, profile) {
state.profile = profile
}
},
actions: {
fetchProfile({ commit }) {
// 获取用户资料
}
}
}
}
})
计数:{{ count }}
双倍计数:{{ doubleCount }}
用户名:{{ userName }}
{{ product.name }}
¥{{ product.price }}
购物车数量:{{ cartCount }}
总价:¥{{ cartTotal }}
{{ label }}
{{ error }}
| 通信方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Props/$emit | 父子组件通信 | 简单直接,数据流清晰 | 跨层级传递繁琐 |
| provide/inject | 跨层级组件通信 | 避免props逐层传递 | 不是响应式,难以追踪 |
| 事件总线 | 任意组件通信 | 灵活,解耦 | 难以维护,容易混乱 |
| $refs/$parent | 直接访问组件实例 | 可以直接调用方法 | 破坏封装性 |
| Vuex/Pinia | 复杂状态管理 | 集中管理,易于调试 | 学习成本高,可能过度设计 |
本课程详细讲解了UniApp/Vue.js中的组件通信机制,包括:
掌握组件通信技术后,你可以构建更加灵活和可维护的应用架构。下一课我们将学习状态管理的相关知识。