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

相关推荐
m0_7482309410 分钟前
Rust赋能前端: 纯血前端将 Table 导出 Excel
前端·rust·excel
qq_5895681018 分钟前
Echarts的高级使用,动画,交互api
前端·javascript·echarts
黑客老陈1 小时前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安1 小时前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
编程百晓君2 小时前
一文解释清楚OpenHarmony面向全场景的分布式操作系统
vue.js
暴富的Tdy2 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se2 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235612 小时前
web 渗透学习指南——初学者防入狱篇
前端
℘团子এ2 小时前
js和html中,将Excel文件渲染在页面上
javascript·html·excel