vue2 的12种 vs vue3 的9种组件通信整理

1、vue2 vs vue3组件通信有哪些

Vue 中组件通信方式有很多,其中Vue2Vue3实现起来也会有很多差异。如下表总结

vue2 vue3 说明
props Props/defineProps 父传子
$emit / v-on defineEmits 子传父
attrs/listeners attrs 父传子、跨层级组件通信
children/parent 父传子,子传父
$ref expose / ref 父组件访问子组件
v-model v-model 子传父,父传子
.sync 子传父,父传子
插槽 slot 插槽 slot 默认插槽、具名插槽、作用域插槽 父传子,
provide / inject provide / inject 跨层级组件通信
EventBus mitt 兄弟组件通信、跨层级组件通信
Vuex Vuex 复杂关系的组件数据传递,跨组件通信 兄弟组件通信、跨层级组件通信
$root 跨层级组件通信

2、vue2组件通信

2.1 props

props 是组件通信中最常用的通信方式之一。父组件通过v-bind 传入,子组件通过props接收

复制代码
//父组件

<template>
  <div>
    <Child :msg="parentMsg" />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components:{
    Child
  },
  data() {
    return {
      parentMsg: '父组件信息'
    }
  }
}
</script>


//子组件

<template>
  <div>
    {{msg}}
  </div>
</template>
<script>
export default {
  props:['msg']
}
</script>

2.2 $emit / v-on

子组件可以通过emit 发布一个事件并传递一些参数,父组件通过v-on进行这个事件的监听

复制代码
// 子组件 派发
export default {
  data(){
      return { msg: "这是发给父组件的信息" }
  },
  methods: {
      handleClick(){
          this.$emit("sendMsg",this.msg)
      }
  },
}

// 父组件 响应
<template>
    <child v-on:sendMsg="getChildMsg"></child>
    // 或 简写
    <child @sendMsg="getChildMsg"></child>
</template>

export default {
    methods:{
        getChildMsg(msg){
            console.log(msg) // 这是父组件接收到的消息
        }
    }
}

2.3 attrs/listeners

$attrs 包含父作用域里除 classstyle 除外的非 props 属性集合。通过 this.attrs 获取父作用域中所有符合条件的属性集合,然后还要继续传给子组件内部的其他组件,就可以通过 v**-bind="attrs"。**

$listeners :包含父作用域里 .native 除外的监听事件集合。如果还要继续传给子组件内部的其他组件,就可以通过 v-on="$linteners"

其中**attrs**` 和`**listeners** 使用法相同

复制代码
// 父组件
<template>
    <child :name="name" title="1111" ></child>
</template
export default{
    data(){
        return {
            name:"小明"
        }
    }
}

// 子组件
<template>
    // 继续传给孙子组件
    <sun-child v-bind="$attrs"></sun-child>
</template>
export default{
    props:["name"], // 这里可以接收,也可以不接收
    mounted(){
        // 如果props接收了name 就是 { title:'张三'},否则就是{ name:"小明", title:1111 }
        console.log(this.$attrs)
    }
}

2.4 children / parent

$children:获取到一个包含所有子组件(不包含孙子组件)的 VueComponent 对象数组,可以直接拿到子组件中所有数据和方法等

$parent:获取到一个父节点的 VueComponent 对象,同样包含父节点中所有数据和方法等

复制代码
//父组件
export default{
    mounted(){
        this.$children[0].someMethod() // 调用第一个子组件的方法
        this.$children[0].name // 获取第一个子组件中的属性
    }
}

// 子组件
export default{
    mounted(){
        this.$parent.someMethod() // 调用父组件的方法
        this.$parent.name // 获取父组件中的属性
    }
}

2.5 $ref

ref 如果在普通的DOM 元素上,引用指向的就是该DOM元素;

如果在子组件上,引用的指向就是子组件实例,然后父组件就可以通过 $ref 主动获取子组件的属性或者调用子组件的方法

复制代码
// 子组件
export default {
    data(){
        return {
            name:"张三"
        }
    },
    methods:{
        someMethod(msg){
            console.log(msg)
        }
    }
}

// 父组件
<template>
    <child ref="child"></child>
</template>
<script>
import Child from './Child'
export default {
  components: {
    Child
  },
    mounted(){
        const child = this.$refs.child
        console.log(child.name) // 张三
        child.someMethod("调用了子组件的方法")
    }
}
</script>

2.6 v-model

详情请看:vue2和vue3的数据双向绑定差异整理

2.7 .sync

可以帮我们实现父组件向子组件传递的数据 的双向绑定,所以子组件接收到数据后可以直接修改,并且会同时修改父组件的数据

复制代码
// 父组件
<template>
    <child :page.sync="page"></child>
</template>
<script>
export default {
    data(){
        return {
            page:1
        }
    }
}

// 子组件
export default {
    props:["page"],
    computed(){
        // 当我们在子组件里修改 currentPage 时,父组件的 page 也会随之改变
        currentPage {
            get(){
                return this.page
            },
            set(newVal){
                this.$emit("update:page", newVal)
            }
        }
    }
}
</script>

2.8 插槽 slot

把子组件的数据通过插槽的方式传给父组件使用,然后再插回来

复制代码
// 子组件
<template>
    <div>
        <slot :user="user"></slot>
    </div>
</template>
export default{
    data(){
        return {
            user:{ name:"张三" }
        }
    }
}

//父组件
<template>
    <div>
        <child v-slot="slotProps">
            {{ slotProps.user.name }}
        </child>
    </div>
</template>

2.9 provide / inject

provide:是一个对象,或者是一个返回对象的函数。里面包含要给子孙后代属性

inject :一个字符串数组,或者是一个对象。获取父组件或更高层次的组件provide 的值,既在任何后代组件都可以通过inject获得

复制代码
//父组件
<script>
import Child from './Child'
export default {
  components: {
    Child
  },
  data() {
    return {
      msg1: '子组件msg1',
      msg2: '子组件msg2'
    }
  },
  provide() {
    return {
      msg1: this.msg1,
      msg2: this.msg2
    }
  }
}
</script>

//子组件

<script>
export default {
  inject:['msg1','msg2'],
  created(){
    //获取高层级提供的属性
    console.log(this.msg1) //子组件msg1
    console.log(this.msg2) //子组件msg2
  }
}
</script>

2.10 EventBus

兄弟组件通信可以通过一个事件中心EventBus 实现,既新建一个Vue实例来进行事件的监听,触发和销毁。不管是父子组件,兄弟组件,跨层级组件等都可以使用它完成通信操作

定义方式有三种

复制代码
// 方法一
// 抽离成一个单独的 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()
    }
})

使用如下,以方法一按需引入为例

复制代码
// 在需要向外部发送自定义事件的组件内
<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")
    }
}

2.11 Vuex

Vuex 是状态管理器,集中式存储管理所有组件的状态。详情请看官方文档:Vuex

2.12 $root

root** 是一个属性,用于访问根组件实例。它的作用是连接所有其他的**Vue** 实例组件,并向子组件提供全局配置和实例方法。根实例是**Vue** 的上下文环境,包含了整个 **Vue** 应用的数据和方法。使用**root属性,可以方便地访问根实例的方法、数据和生命周期钩子函数。

复制代码
// main.js
new Vue({
  data() {
    return {
      isUpdate: true
    };
  },
  router,
  store,
  render: h => h(App)
}).$mount('#app');

// 组件 created() 或mounted(), method中
created() {
  console.log(this.$root.isUpdate);
  this.$root.isUpdate = false;
}

3、vue3组件通信

3.1 Props/defineProps

props 是组件通信中最常用的通信方式之一。父组件通过v-bind 传入,子组件通过props接收

使用方法详情看官方文档:Props

3.2 defineEmits

子组件可以通过emit发布一个事件并传递一些参数,父组件通过v-on进行这个事件的监听

复制代码
// 子组件
<template>
  <div>
    <button @click="handleIncrement">Increment</button>
    <button @click="handleDecrement">Decrement</button>
  </div>
</template>

<script setup lang="ts">
const emit = defineEmits(['increment', 'decrement']);

const handleIncrement = () => {
  emit('increment');
};

const handleDecrement = () => {
  emit('decrement');
};
</script>

// 父组件

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <chlid @increment="increment" @decrement="decrement" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import Chlid  from './chlid.vue';

const counter = ref(0);

const increment = () => {
  counter.value++;
};

const decrement = () => {
  counter.value--;
};
</script>

3.3 attrs

子组件使用**$attrs**可以获得父组件除了props传递的属性和特性绑定属性 (class和 style)之外的所有属性。

复制代码
//父组件

<template>
  <div>
    <Child @parentFun="parentFun" :msg1="msg1" :msg2="msg2"  />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components:{
    Child
  },
  data(){
    return {
      msg1:'子组件msg1',
      msg2:'子组件msg2'
    }
  },
  methods: {
    parentFun(val) {
      console.log(`父组件方法被调用,获得子组件传值:${val}`)
    }
  }
}
</script>

//子组件

<template>
  <div>
    <button @click="getParentFun">调用父组件方法</button>
  </div>
</template>
<script>
export default {
  methods:{
    getParentFun(){
      this.$listeners.parentFun('我是子组件数据')
    }
  },
  created(){
    //获取父组件中所有绑定属性
    console.log(this.$attrs)  //{"msg1": "子组件msg1","msg2": "子组件msg2"}
    //获取父组件中所有绑定方法    
    console.log(this.$listeners) //{parentFun:f}
  }
}
</script>

3.4 expose / ref

$refs可以直接获取元素属性,同时也可以直接获取子组件实例。

注意:通过ref获取子组件实例必须在页面挂载完成后才能获取。子组件必须元素或方法暴露出去父组件才能获取到

复制代码
//父组件

<template>
  <div>
    <Child ref="child" />
  </div>
</template>
<script setup>
import Child from './Child'
import { ref, onMounted } from "vue";
const child = ref() //注意命名需要和template中ref对应
onMounted(() => {
  //获取子组件属性
  console.log(child.value.msg) //子组件元素

  //调用子组件方法
  child.value.childFun('父组件信息')
})
</script>

//子组件

<template>
    <div>
    </div>
</template>
<script setup>
import { ref,defineExpose } from "vue";
const msg = ref('子组件元素')
const childFun = (val) => {
    console.log(`子组件方法被调用,值${val}`)
}
//必须暴露出去父组件才会获取到
defineExpose({
    childFun,
    msg
})
</script>

3.5 v-model

可以支持多个数据双向绑定

复制代码
// 父组件
<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>

// 子组件
<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>

3.6 插槽 slot

把子组件的数据通过插槽的方式传给父组件使用,然后再插回来。有默认插槽、具名插槽、作用域插槽三种方式

使用方法请看官方文档:插槽slot

3.7 provide / inject

provide / inject为依赖注入

provide:可以让我们指定想要提供给后代组件的数据或

inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用

复制代码
// 父组件
<script setup>
    import { provide } from "vue"
    provide("name", "张三")
</script>

// 孙组件
<script setup>
    import { inject } from "vue"
    const name = inject("name")
    console.log(name) // 张三
</script>

3.8 mitt

Vue3 中没有了EventBus 跨组件通信,但是现在有了一个替代的方案mitt.js ,原理还是 EventBus

详情请看文档**:mitt**

3.9 Vuex

Vuex 是状态管理器,集中式存储管理所有组件的状态。详情请看官方文档:Vuex

相关推荐
用户40993225021215 小时前
为什么Vue 3的计算属性能解决模板臃肿、性能优化和双向同步三大痛点?
前端·ai编程·trae
海云前端115 小时前
Vue首屏加速秘籍 组件按需加载真能省一半时间
前端
蛋仔聊测试15 小时前
Playwright 中route 方法模拟测试数据(Mocking)详解
前端·python·测试
零号机15 小时前
使用TRAE 30分钟极速开发一款划词中英互译浏览器插件
前端·人工智能
molly cheung15 小时前
FetchAPI 请求流式数据 基本用法
javascript·fetch·请求取消·流式·流式数据·流式请求取消
疯狂踩坑人15 小时前
结合400行mini-react代码,图文解说React原理
前端·react.js·面试
Mintopia15 小时前
🚀 共绩算力:3分钟拥有自己的文生图AI服务-容器化部署 StableDiffusion1.5-WebUI 应用
前端·人工智能·aigc
街尾杂货店&15 小时前
CSS - transition 过渡属性及使用方法(示例代码)
前端·css
CH_X_M15 小时前
为什么在AI对话中选择用sse而不是web socket?
前端
Mintopia16 小时前
🧠 量子计算对AIGC的潜在影响:Web技术的未来可能性
前端·javascript·aigc