一、父傳子(props)
在子組件中可以使用defineProps接收父組件向子組件的傳值
父組件fatherPage.vue:
<template><div class="father"><button @click="a = a + 1">按鈕</button><childPage :a="a" /></div>
</template><script lang="ts" setup>
import { ref } from "vue";
import childPage from "./childPage.vue";
const a = ref<number>(0);
</script>
<style scoped lang="less">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);display: flex;justify-content: center;align-items: center;button {width: 100px;height: 60px;cursor: pointer;}
}
</style>
子組件childPage.vue:
<template><div class="childPage">{{ a }}</div>
</template>
<script lang="ts" setup>
import { computed, defineProps } from "vue";
// 含默認值
// const porps = defineProps({
// a: {
// type: Number,
// default: 0,
// },
// });
const props = defineProps({ a: Number });
// 用computed使用props
const a = computed(() => props.a);
</script>
<style scoped lang="less">
.childPage {width: 100px;height: 60px;background-color: rgba(0, 0, 0, 0);display: flex;justify-content: center;align-items: center;color: #ffffff;
}
</style>
效果:
二、子傳父(emits)
在子組件中可以使用defineEmits向父組件傳遞信息。
父組件fatherPage.vue:
<template><div class="father">{{ a }}<childPage @update:a="update" /></div>
</template><script lang="ts" setup>
import { ref } from "vue";
import childPage from "./childPage.vue";
const a = ref<number>(0);
const update = (emitValue: number) => {a.value = emitValue;
};
</script>
<style scoped lang="less">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);color: #ffffff;display: flex;justify-content: center;align-items: center;button {width: 100px;height: 60px;cursor: pointer;}
}
</style>
子組件childPage.vue:
1.通過點擊觸發emit傳值
<template><div class="childPage"><button @click="updateA">按鈕</button></div>
</template><script lang="ts" setup>
import { ref, defineEmits } from "vue";const a = ref<number>(0);
const emit = defineEmits(["update:a"]);
const updateA = () => {a.value++;emit("update:a", a.value);
};
</script><style scoped lang="less">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
2.通過watch監聽值的變化進行傳值:
<template><div class="childPage"><button @click="updateA">按鈕</button></div>
</template><script lang="ts" setup>
import { ref, defineEmits, watch } from "vue";const a = ref<number>(0);
const emit = defineEmits(["update:a"]);
const updateA = () => {a.value++;setTimeout(() => {updateA();}, 1000);
};
watch(a, (newValue) => {emit("update:a", newValue);
});
</script><style scoped lang="less">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
三、父子組件進行雙向綁定(v-model)
在子組件中可以使用defineModel與父組件進行雙向綁定。注意:defineModel在vue3.3版本實驗性使用,穩定版在vue3.4。
父組件:
<template><div class="father">{{ a }}<childPage v-model="a" /></div>
</template><script lang="ts" setup>
import { ref } from "vue";
import childPage from "./childPage.vue";
const a = ref<number>();
</script>
<style scoped lang="less">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);color: #ffffff;display: flex;justify-content: center;align-items: center;button {width: 100px;height: 60px;cursor: pointer;}
}
</style>
子組件:
<template><div class="childPage"><button @click="updateA">按鈕</button></div>
</template><script lang="ts" setup>
import { defineModel } from "vue";const a = defineModel({type: Number,default: 0,
});const updateA = () => {a.value += 1;
};
</script><style scoped lang="less">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
四、使用vuex進行組件通信
使用vuex可以進行組件之間的通信,父子組件與兄弟組件均可
在vuex文件index.ts中:
import { createStore } from "vuex";export default createStore({state: {number: 0,},getters: {},mutations: {changeNumber(state, payload) {state.number = payload;},},actions: {},modules: {},
});
在第一個組件HomeView中:
<template><div class="father">{{ a }}<AboutView /></div>
</template><script lang="ts" setup>
import { computed } from "vue";
import { useStore } from "vuex";
import AboutView from "./AboutView.vue";
const store = useStore();
const a = computed(() => store.state.number);
</script>
<style scoped lang="scss">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);color: #ffffff;display: flex;justify-content: center;align-items: center;
}
</style>
在第二個組件AboutView中:
<template><div class="childPage"><button @click="updateA">按鈕</button></div>
</template><script lang="ts" setup>
import { useStore } from "vuex";const store = useStore();
let a = 0;const updateA = () => {a++;store.commit("changeNumber", a);
};
</script><style scoped lang="scss">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
五、使用pinia進行組件通信
pinia有著與vuex類似的功能,同樣可以實現組件間的通信。
在store的index.ts文件中:
import { defineStore } from "pinia";
import { ref } from "vue";
export const useCounterStore = defineStore("counter", () => {const count = ref(0);const changeCount = () => {count.value++;};return { count, changeCount };
});
在第一個組件fatherPage中:
<template><div class="father">{{ count }}<childPage /></div>
</template><script lang="ts" setup>
import childPage from "./childPage.vue";
import { useCounterStore } from "../store/index";
import { storeToRefs } from "pinia";
const store = useCounterStore();
const { count } = storeToRefs(store);
</script>
<style scoped lang="less">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);color: #ffffff;display: flex;justify-content: center;align-items: center;button {width: 100px;height: 60px;cursor: pointer;}
}
</style>
在第二個組件childPage中:
<template><div class="childPage"><button @click="changeCount">按鈕</button></div>
</template><script lang="ts" setup>
import { useCounterStore } from "../store/index";
const store = useCounterStore();
const { changeCount } = store;
</script><style scoped lang="less">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
六、使用事件總線進行組件通信
我們可以利用第三方庫比如說mitt以事件總線的方式實現傳值
在mitt的index.ts中:
import mitt from "mitt";
const emitter = mitt();
export default emitter;
在第一個組件fatherPage中:
<template><div class="father">{{ count }}<childPage /></div>
</template><script setup>
import childPage from "./childPage.vue";
import emitter from "@/mitt/index";
import { ref } from "vue";
const count = ref(0);
emitter.on("changeCount", (counter) => {count.value = counter;
});
</script>
<style scoped lang="less">
.father {width: 100%;height: 100vh;background-color: rgb(7, 14, 17);color: #ffffff;display: flex;justify-content: center;align-items: center;button {width: 100px;height: 60px;cursor: pointer;}
}
</style>
在第二個組件childPage中:
<template><div class="childPage"><button @click="changeCount">按鈕</button></div>
</template><script setup>
import emitter from "../mitt/index";
let a = 0;
const changeCount = () => {a++;emitter.emit("changeCount", a);
};
</script><style scoped lang="less">
.childPage {width: 100px;height: 60px;button {width: 100%;height: 100%;cursor: pointer;}
}
</style>
效果:
七、更詳細使用方式請參考以下文檔
1,Vue.js - 漸進式 JavaScript 框架 | Vue.js
2,開始 | Vuex
3,Pinia | Pinia 中文手冊 - 官網同步更新 v2.0.28
4,GitHub - developit/mitt: 🥊 Tiny 200 byte functional event emitter / pubsub.