Vue3 communication using writing
1. props
Method one, mixed writing
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
data(){
return {
msg1:"这是传级子组件的信息1"
}
},
setup(){
// 创建一个响应式数据
// 写法一 适用于基础类型 ref 还有其他用处,下面章节有介绍
const msg2 = ref("这是传级子组件的信息2")
// 写法二 适用于复杂类型,如数组、对象
const msg2 = reactive(["这是传级子组件的信息2"])
return {
msg2
}
}
}
</script>
// Child.vue 接收
<script>
export default {
props: ["msg1", "msg2"],// 如果这行不写,下面就接收不到
setup(props) {
console.log(props) // { msg1:"这是传给子组件的信息1", msg2:"这是传给子组件的信息2" }
},
}
</script>
Method two, pure Vue3 writing
// Parent.vue 传送
<child :msg2="msg2"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg2 = ref("这是传给子组件的信息2")
// 或者复杂类型
const msg2 = reactive(["这是传级子组件的信息2"])
</script>
// Child.vue 接收
<script setup>
// 不需要引入 直接使用
// import { defineProps } from "vue"
const props = defineProps({
// 写法一
msg2: String
// 写法二
msg2:{
type:String,
default:""
}
})
console.log(props) // { msg2:"这是传级子组件的信息2" }
</script>
2. $emit
// Child.vue 派发
<template>
// 写法一
<button @click="emit('myClick')">按钮</buttom>
// 写法二
<button @click="handleClick">按钮</buttom>
</template>
<script setup>
// 方法一 适用于Vue3.2版本 不需要引入
// import { defineEmits } from "vue"
// 对应写法一
const emit = defineEmits(["myClick","myClick2"])
// 对应写法二
const handleClick = ()=>{
emit("myClick", "这是发送给父组件的信息")
}
// 方法二 不适用于 Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const { emit } = useContext()
const handleClick = ()=>{
emit("myClick", "这是发送给父组件的信息")
}
</script>
// Parent.vue 响应
<template>
<child @myClick="onMyClick"></child>
</template>
<script setup>
import child from "./child.vue"
const onMyClick = (msg) => {
console.log(msg) // 这是父组件收到的信息
}
</script>
3. expose / ref
The parent component gets the properties of the child component or calls the method of the child component
// Child.vue
<script setup>
// 方法一 不适用于Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const ctx = useContext()
// 对外暴露属性方法等都可以
ctx.expose({
childName: "这是子组件的属性",
someMethod(){
console.log("这是子组件的方法")
}
})
// 方法二 适用于Vue3.2版本, 不需要引入
// import { defineExpose } from "vue"
defineExpose({
childName: "这是子组件的属性",
someMethod(){
console.log("这是子组件的方法")
}
})
</script>
// Parent.vue 注意 ref="comp"
<template>
<child ref="comp"></child>
<button @click="handlerClick">按钮</button>
</template>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const comp = ref(null)
const handlerClick = () => {
console.log(comp.value.childName) // 获取子组件对外暴露的属性
comp.value.someMethod() // 调用子组件对外暴露的方法
}
</script>
4. attrs
attrs: Contains the non-props attribute collection except class and style in the parent scope
// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2" title="3333"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const msg1 = ref("1111")
const msg2 = ref("2222")
</script>
// Child.vue 接收
<script setup>
import { defineProps, useContext, useAttrs } from "vue"
// 3.2版本不需要引入 defineProps,直接用
const props = defineProps({
msg1: String
})
// 方法一 不适用于 Vue3.2版本,该版本 useContext()已废弃
const ctx = useContext()
// 如果没有用 props 接收 msg1 的话就是 { msg1: "1111", msg2:"2222", title: "3333" }
console.log(ctx.attrs) // { msg2:"2222", title: "3333" }
// 方法二 适用于 Vue3.2版本
const attrs = useAttrs()
console.log(attrs) // { msg2:"2222", title: "3333" }
</script>
5. v-model
Can support multiple data two-way binding
// Parent.vue
<child v-model:key="key" v-model:value="value"></child>
<script setup>
import child from "./child.vue"
import { ref, reactive } from "vue"
const key = ref("1111")
const value = ref("2222")
</script>
// Child.vue
<template>
<button @click="handlerClick">按钮</button>
</template>
<script setup>
// 方法一 不适用于 Vue3.2版本,该版本 useContext()已废弃
import { useContext } from "vue"
const { emit } = useContext()
// 方法二 适用于 Vue3.2版本,不需要引入
// import { defineEmits } from "vue"
const emit = defineEmits(["key","value"])
// 用法
const handlerClick = () => {
emit("update:key", "新的key")
emit("update:value", "新的value")
}
</script>
6. provide / inject
provide / inject is dependency injection
provide: Allows us to specify the data we want to provide to the offspring components or
inject: Receive the data you want to add to this component in any descendant component, no matter how deep the component is nested, you can use it directly
// Parent.vue
<script setup>
import { provide } from "vue"
provide("name", "沐华")
</script>
// Child.vue
<script setup>
import { inject } from "vue"
const name = inject("name")
console.log(name) // 沐华
</script>
7. Vuex
// store/index.js
import { createStore } from "vuex"
export default createStore({
state:{ count: 1 },
getters:{
getCount: state => state.count
},
mutations:{
add(state){
state.count++
}
}
})
// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")
// Page.vue
// 方法一 直接使用
<template>
<div>{{ $store.state.count }}</div>
<button @click="$store.commit('add')">按钮</button>
</template>
// 方法二 获取
<script setup>
import { useStore, computed } from "vuex"
const store = useStore()
console.log(store.state.count) // 1
const count = computed(()=>store.state.count) // 响应式,会随着vuex数据改变而改变
console.log(count) // 1
</script>
8. mitt
There is no EventBus cross-component communication in Vue3, but now there is an alternative solution mitt.js, the principle is still EventBus
Install npm i mitt -S first
Then encapsulate it as before encapsulating the bus
mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt
Then the use of communication between the two components
// 组件 A
<script setup>
import mitt from './mitt'
const handleClick = () => {
mitt.emit('handleChange')
}
</script>
// 组件 B
<script setup>
import mitt from './mitt'
import { onUnmounted } from 'vue'
const someMethed = () => { ... }
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
mitt.off('handleChange',someMethed)
})
</script>
Vue2.x component communication method
There are 12 types of Vue2.x component communication | Parent-child component communication | Brother component communication | Cross-level component communication |
---|---|---|---|
props | props | EventBus | EventBus |
$emit / v-on | $emit / v-on | Vuex | provide/inject |
.sync | attrs/listeners | $parent | Vuex |
v-model | ref | attrs/listeners | |
ref | .sync | $root | |
children/parent | v-model | ||
attrs/listeners | children/parent | ||
provide / inject | |||
EventBus | |||
Vuex | |||
$root | |||
slot |
Vue2.x communication using writing
1. props
The parent component transmits data to the child component, this should be the most common way
After the child component receives the data, cannot directly modify the data of the parent component . An error will be reported, so when the parent component is re-rendered, the data will be overwritten. If you want to modify the sub-component, it is recommended to use computed
// Parent.vue 传送
<template>
<child :msg="msg"></child>
</template>
// Child.vue 接收
export default {
// 写法一 用数组接收
props:['msg'],
// 写法二 用对象接收,可以限定接收的数据类型、设置默认值、验证等
props:{
msg:{
type:String,
default:'这是默认数据'
}
},
mounted(){
console.log(this.msg)
},
}
2. .sync
It can help us realize the two-way binding of the data passed by the parent component to the child component, so the child component can directly modify the data after receiving the data, and the data of the parent component will be modified at the same time
// Parent.vue
<template>
<child :page.sync="page"></child>
</template>
<script>
export default {
data(){
return {
page:1
}
}
}
// Child.vue
export default {
props:["page"],
computed(){
// 当我们在子组件里修改 currentPage 时,父组件的 page 也会随之改变
currentPage {
get(){
return this.page
},
set(newVal){
this.$emit("update:page", newVal)
}
}
}
}
</script>
3. v-model
Similar to .sync, it can realize the two-way binding of the data passed from the parent component to the child component, and the child component modifies the data of the parent component through $emit
// Parent.vue
<template>
<child v-model="value"></child>
</template>
<script>
export default {
data(){
return {
value:1
}
}
}
// Child.vue
<template>
<input :value="value" @input="handlerChange">
</template>
export default {
props:["value"],
// 可以修改事件名,默认为 input
model:{
event:"updateValue"
},
methods:{
handlerChange(e){
this.$emit("input", e.target.value)
// 如果有上面的重命名就是这样
this.$emit("updateValue", e.target.value)
}
}
}
</script>
4. ref
If ref is on an ordinary DOM element, the reference points to that DOM element;
If on the child component, the reference point is the child component instance, then the parent component can actively obtain the properties of the child component or call the method of the child component through ref
// Child.vue
export default {
data(){
return {
name:"沐华"
}
},
methods:{
someMethod(msg){
console.log(msg)
}
}
}
// Parent.vue
<template>
<child ref="child"></child>
</template>
<script>
export default {
mounted(){
const child = this.$refs.child
console.log(child.name) // 沐华
child.someMethod("调用了子组件的方法")
}
}
</script>
5. $emit / v-on
The child component sends data to the parent component by dispatching events, or triggers operations such as updating the parent component
// Child.vue 派发
export default {
data(){
return { msg: "这是发给父组件的信息" }
},
methods: {
handleClick(){
this.$emit("sendMsg",this.msg)
}
},
}
// Parent.vue 响应
<template>
<child v-on:sendMsg="getChildMsg"></child>
// 或 简写
<child @sendMsg="getChildMsg"></child>
</template>
export default {
methods:{
getChildMsg(msg){
console.log(msg) // 这是父组件接收到的消息
}
}
}
6.attrs/listeners
When multi-level nested components pass data, if you only pass data without intermediate processing, you can use this, such as when the parent component passes data to the grandchild component
$attrs: Contains the non-props attribute set in the parent scope except class and style. Get all the eligible attribute sets in the parent scope through this.attrs, and then continue to pass it to other components inside the child component, you can pass v-bind="attrs"
$listeners: Contains the collection of listener events except .native in the parent scope. If you want to continue to pass to other components inside the sub-component, you can pass v-on="$linteners"
Use the same way
// Parent.vue
<template>
<child :name="name" title="1111" ></child>
</template
export default{
data(){
return {
name:"沐华"
}
}
}
// Child.vue
<template>
// 继续传给孙子组件
<sun-child v-bind="$attrs"></sun-child>
</template>
export default{
props:["name"], // 这里可以接收,也可以不接收
mounted(){
// 如果props接收了name 就是 { title:1111 },否则就是{ name:"沐华", title:1111 }
console.log(this.$attrs)
}
}
7.children/parent
$children: Get an array of VueComponent objects containing all child components (not including grandchild components), you can get all the data and methods in the child components directly
$parent: Get the VueComponent object of a parent node, which also contains all the data and methods in the parent node
// Parent.vue
export default{
mounted(){
this.$children[0].someMethod() // 调用第一个子组件的方法
this.$children[0].name // 获取第一个子组件中的属性
}
}
// Child.vue
export default{
mounted(){
this.$parent.someMethod() // 调用父组件的方法
this.$parent.name // 获取父组件中的属性
}
}
8. provide / inject
provide / inject is dependency injection. It is said that it is not recommended to be used directly in application code, but it is commonly used in some plug-ins or component libraries, so I don’t think it’s useful, it’s pretty easy to use.
provide: allows us to specify the data or methods we want to provide to the offspring components
inject: Receive the data or method you want to add to this component in any descendant component, no matter how deep the component is nested, you can use it directly
It should be noted that the data passed by provide and inject is not responsive, that is to say, after receiving the data with inject, the data in the provider changes, and the data in the descendant components will not change, unless the incoming is a monitorable Object
So it is recommended to pass some constants or methods
// 父组件
export default{
// 方法一 不能获取 methods 中的方法
provide:{
name:"沐华",
age: this.data中的属性
},
// 方法二 不能获取 data 中的属性
provide(){
return {
name:"沐华",
someMethod:this.someMethod // methods 中的方法
}
},
methods:{
someMethod(){
console.log("这是注入的方法")
}
}
}
// 后代组件
export default{
inject:["name","someMethod"],
mounted(){
console.log(this.name)
this.someMethod()
}
}
9. EventBus
EventBus is the central event bus, whether it is parent-child components, sibling components, cross-level components, etc. can use it to complete communication operations
There are three ways to define
// 方法一
// 抽离成一个单独的 js 文件 Bus.js ,然后在需要的地方引入
// Bus.js
import Vue from "vue"
export default new Vue()
// 方法二 直接挂载到全局
// main.js
import Vue from "vue"
Vue.prototype.$bus = new Vue()
// 方法三 注入到 Vue 根对象上
// main.js
import Vue from "vue"
new Vue({
el:"#app",
data:{
Bus: new Vue()
}
})
Use it as follows, take method 1 on-demand introduction as an example
// 在需要向外部发送自定义事件的组件内
<template>
<button @click="handlerClick">按钮</button>
</template>
import Bus from "./Bus.js"
export default{
methods:{
handlerClick(){
// 自定义事件名 sendMsg
Bus.$emit("sendMsg", "这是要向外部发送的数据")
}
}
}
// 在需要接收外部事件的组件内
import Bus from "./Bus.js"
export default{
mounted(){
// 监听事件的触发
Bus.$on("sendMsg", data => {
console.log("这是接收到的数据:", data)
})
},
beforeDestroy(){
// 取消监听
Bus.$off("sendMsg")
}
}
10. Vuex
Vuex is a state manager that centrally stores and manages the state of all components. This piece of content is too long. If you are not familiar with the basics, you can look at this Vuex, and the general usage is as follows
For example, create such a file structure
The content in index.js is as follows
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import actions from './actions'
import mutations from './mutations'
import state from './state'
import user from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user
},
getters,
actions,
mutations,
state
})
export default store
Then introduce in main.js
import Vue from "vue"
import store from "./store"
new Vue({
el:"#app",
store,
render: h => h(App)
})
Then in the required components
import { mapGetters, mapMutations } from "vuex"
export default{
computed:{
// 方式一 然后通过 this.属性名就可以用了
...mapGetters(["引入getters.js里属性1","属性2"])
// 方式二
...mapGetters("user", ["user模块里的属性1","属性2"])
},
methods:{
// 方式一 然后通过 this.属性名就可以用了
...mapMutations(["引入mutations.js里的方法1","方法2"])
// 方式二
...mapMutations("user",["引入user模块里的方法1","方法2"])
}
}
// 或者也可以这样获取
this.$store.state.xxx
this.$store.state.user.xxx
11. $root
$root can get the data and methods in App.vue
12. slot
It is to pass the data of the child component to the parent component through the slot, and then insert it back
// Child.vue
<template>
<div>
<slot :user="user"></slot>
</div>
</template>
export default{
data(){
return {
user:{ name:"沐华" }
}
}
}
// Parent.vue
<template>
<div>
<child v-slot="slotProps">
{{ slotProps.user.name }}
</child>
</div>
</template>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。