Vue.js 组件通信主要通过以下几种方式来实现:
Props(属性)
- 方向:父组件到子组件
- 用途:父组件通过属性向子组件传递数据。
- 特性:
- 只读:默认情况下,子组件不能改变props的值。
- 验证:可以通过props选项定义验证规则。
- 动态:props的值可以随父组件状态的变化而变化。
父组件(Parent.vue)
<template>
<div>
<ChildComponent :message="parentMessage" />
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: 'Hello from Parent'
};
}
};
</script>
子组件(ChildComponent.vue)
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
props: {
message: String
}
};
</script>
$emit(事件)
- 方向:子组件到父组件
- 用途:子组件通过触发自定义事件来通知父组件。
- 特性:
- 传递数据:事件可以携带数据。
- 多个事件:子组件可以触发多个不同的事件。
子组件(ChildComponent.vue)
<template>
<button @click="notifyParent">Notify Parent</button>
</template>
<script>
export default {
methods: {
notifyParent() {
this.$emit('child-event', 'Hello from Child');
}
}
};
</script>
父组件(Parent.vue)
<template>
<ChildComponent @child-event="handleChildEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleChildEvent(data) {
console.log('Received data from child:', data);
}
}
};
</script>
Vuex
- 全局状态管理
- 用途:用于管理整个应用的状态,任何组件都可以访问。
- 特性:
- State:存储全局状态。
- Mutations:唯一改变state的方式,同步操作。
- Actions:用于异步操作,可以派发mutations。
- Getters:计算属性,基于state创建缓存的属性。
- Modules:大型应用中可以分割状态管理模块。
首先,设置 Vuex Store:
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
sharedCounter: 0
},
mutations: {
increment(state) {
state.sharedCounter++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
getCounter: state => state.sharedCounter
}
});
主应用(main.js)
确保应用使用了 Vuex Store
:
import Vue from 'vue';
import App from './App.vue';
import store from './store';
new Vue({
store,
render: h => h(App)
}).$mount('#app');
父/子组件使用 Vuex
可以在任何组件中通过 this.$store
访问 Vuex Store
。
ComponentUsingVuex.vue
<template>
<div>
<p>Counter: {{ counter }}</p>
<button @click="increment">Increment</button>
<button @click="incrementAsync">Increment Async</button>
</div>
</template>
<script>
export default {
computed: {
counter() {
return this.$store.getters.getCounter;
}
},
methods: {
increment() {
this.$store.commit('increment');
},
incrementAsync() {
this.$store.dispatch('incrementAsync');
}
}
};
</script>
Provide/Inject
- 跨级通信
- 用途:允许祖先组件提供数据,后代组件注入数据,无需依赖父组件层级。
- 特性:
- 不受组件层次限制,但可能导致代码耦合度增加。
- 不推荐在常规组件通信中广泛使用,更适合库或框架级别的数据传递。
祖先组件(AncestorComponent.vue)
<template>
<div>
<ChildComponent />
</div>
</template>
<script>
export default {
provide() {
return {
ancestorValue: 'Value from Ancestor'
};
}
};
</script>
后代组件(DescendantComponent.vue)
<template>
<div>
<p>Value from Ancestor: {{ injectedValue }}</p>
</div>
</template>
<script>
export default {
inject: ['ancestorValue'],
mounted() {
console.log('Injected value:', this.injectedValue);
}
};
</script>
Ref 和 v-model
- 直接引用
- 用途:父组件直接引用子组件实例,或双向数据绑定。
- 特性:
- Refs:用于获取子组件实例或DOM元素,进行直接操作。
- v-model:用于双向数据绑定,常见于表单元素,也可以应用于自定义组件。
父组件(ParentComponent.vue)
<template>
<ChildComponent ref="childRef" v-model="parentValue" />
<button @click="logChildRef">Log Child Ref</button>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentValue: 'Initial Value'
};
},
methods: {
logChildRef() {
console.log(this.$refs.childRef);
}
}
};
</script>
子组件(ChildComponent.vue)
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
};
</script>
Custom Events(自定义事件)
- 事件通信
- 用途:自定义事件允许组件间非标准的通信。
- 特性:
- 可以在任何组件之间触发和监听。
- 适用于特定的交互或组件间的复杂通信。
子组件(ChildComponent.vue)
<template>
<button @click="customEvent">Send Custom Event</button>
</template>
<script>
export default {
methods: {
customEvent() {
this.$emit('custom-event', 'Data to send');
}
}
};
</script>
父组件(ParentComponent.vue)
<template>
<ChildComponent @custom-event="handleCustomEvent" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
methods: {
handleCustomEvent(data) {
console.log('Received custom event data:', data);
}
}
};
</script>
Slots(插槽)
- 内容分发
- 用途:允许父组件的内容插入到子组件的特定位置。
- 特性:
- 默认插槽:子组件的默认内容区域。
- 具名插槽:子组件可以定义多个插槽,父组件指定插入内容的位置。
- 作用域插槽:父组件可以访问子组件的数据来决定插槽内容。
父组件(ParentComponent.vue)
<template>
<WrapperComponent>
<h1 slot="header">Custom Header</h1>
<p slot="body">Custom Body Content</p>
</WrapperComponent>
</template>
<script>
import WrapperComponent from './WrapperComponent.vue';
export default {
components: {
WrapperComponent
}
};
</script>
WrapperComponent.vue
<template>
<div>
<slot name="header"></slot>
<div class="content">
<slot name="body"></slot>
</div>
</div>
</template>
Composition API(组合API)
- 新功能
- 用途:Vue 3引入的新特性,允许在组件内更好地组织逻辑和数据。
- 特性:
setup()
函数:在组件生命周期开始时运行,可以访问props和触发生命周期钩子。ref
和reactive
:用于响应式数据管理。provide
和inject
:在组合API中也有相应的实现,更灵活地进行跨组件数据传递。
父组件(ParentComponent.vue)
<template>
<ChildComponent :count="count" @updateCount="updateCount" />
</template>
<script>
import { ref, onMounted } from 'vue';
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
setup() {
const count = ref(0);
function updateCount(newCount) {
count.value = newCount;
}
onMounted(() => {
console.log('Initial count:', count.value);
});
return {
count,
updateCount
};
}
};
</script>
子组件(ChildComponent.vue)
<template>
<button @click="increment">Increment</button>
</template>
<script>
import { ref, emit } from 'vue';
export default {
props: ['count'],
setup(props) {
const count = ref(props.count);
function increment() {
count.value++;
emit('updateCount', count.value);
}
return {
count,
increment
};
}
};
</script>