在 Vue 项目中,组件间的引用与数据交互是核心功能之一。以下是组件引用和数据交互的详细实现方式及示例:
一、组件引用方式
1. 基本组件引用
- 局部注册:在父组件中按需引入子组件并注册。
// ParentComponent.vue
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
template: `<ChildComponent :message="msg" @update="handleUpdate" />`
}
- 全局注册:在主入口文件中统一注册,所有组件均可使用。
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import GlobalComp from './components/GlobalComp.vue'
const app = createApp(App)
app.component('GlobalComp', GlobalComp)
app.mount('#app')
2. 动态组件加载
<!-- DynamicComponent.vue -->
<template>
<component :is="currentView"></component>
</template>
<script>
import Home from './Home.vue'
import About from './About.vue'
export default {
data() {
return {
currentView: 'Home'
}
},
components: { Home, About }
}
</script>
二、组件间数据交互方式
1. Props & $emit(父子组件通信)
- 父 → 子:通过
props
传递数据。 - 子 → 父:通过
$emit
触发自定义事件。
示例:
<!-- Parent.vue -->
<template>
<div>
<Child :count="counter" @increment="addCount" />
</div>
</template>
<script>
import Child from './Child.vue'
export default {
data() {
return { counter: 0 }
},
methods: {
addCount() {
this.counter += 1
}
}
}
</script>
<!-- Child.vue -->
<template>
<button @click="increment">Click Me: {{ count }}</button>
</template>
<script>
export default {
props: ['count'],
methods: {
increment() {
this.$emit('increment') // 通知父组件
}
}
}
</script>
2. provide/inject
(任意层级组件通信)
用于祖先组件直接向后代组件传递数据,无需逐层传递。
示例:
<!-- Ancestor.vue -->
<template>
<div>
<Descendant />
</div>
</template>
<script>
import Descendant from './Descendant.vue'
export default {
provide() {
return {
sharedState: this.state
}
},
data() {
return { state: 'from Ancestor' }
}
}
</script>
<!-- Descendant.vue -->
<template>
<div>{{ injectedData }}</div>
</template>
<script>
export default {
inject: ['sharedState'],
computed: {
injectedData() {
return this.sharedState
}
}
}
</script>
3. Vuex(复杂状态管理)
适用于多组件共享状态的场景。
安装与配置:
npm install vuex@next
// store.js
import { createStore } from 'vuex'
export const store = createStore({
state() {
return { count: 0 }
},
mutations: {
increment(state) {
state.count++
}
}
})
<!-- Counter.vue -->
<template>
<div>
{{ $store.state.count }}
<button @click="$store.commit('increment')">Increment</button>
</div>
</template>
4. 事件总线(Event Bus)
用于非父子组件间的轻量级通信(Vue 3 推荐使用 mitt
替代)。
示例:
// eventBus.js
import mitt from 'mitt'
const emitter = mitt()
export default emitter
<!-- Sender.vue -->
<script>
import emitter from './eventBus'
emitter.emit('notify', { message: 'Hello!' })
</script>
<!-- Receiver.vue -->
<script>
import emitter from './eventBus'
emitter.on('notify', (data) => {
console.log(data.message)
})
</script>
三、完整示例:计数器应用
1. 项目结构
src/
├── components/
│ ├── CounterDisplay.vue
│ └── IncrementButton.vue
├── App.vue
└── main.js
2. 代码实现
<!-- App.vue -->
<template>
<div>
<CounterDisplay :count="counter" />
<IncrementButton @increment="counter++" />
</div>
</template>
<script>
import CounterDisplay from './components/CounterDisplay.vue'
import IncrementButton from './components/IncrementButton.vue'
export default {
data() {
return { counter: 0 }
},
components: { CounterDisplay, IncrementButton }
}
</script>
<!-- CounterDisplay.vue -->
<template><h1>Count: {{ count }}</h1></template>
<script>
export default {
props: ['count']
}
</script>
<!-- IncrementButton.vue -->
<template><button @click="$emit('increment')">+1</button></template>
四、注意事项
- Prop 单向数据流:子组件不应直接修改父组件传递的
props
。 - 事件命名规范:使用
kebab-case
命名自定义事件(如update:field
)。 - 性能优化:避免过度使用全局状态管理(如 Vuex),优先选择组件间直接通信。
通过以上方式,可以实现灵活高效的组件引用与数据交互!