当前位置: 首页 > article >正文

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包含父作用域里除 class style 除外的非 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


http://www.kler.cn/a/374949.html

相关文章:

  • 操作系统实验记录
  • Python之groupby()及aggregate()方法
  • 游戏和各大APP改IP地址方法教程
  • mybatis 参数判断报错的问题
  • 大模型学习笔记------什么是大模型
  • 【C++滑动窗口】2653. 滑动子数组的美丽值|1785
  • 【Wi-Fi】Wi-Fi 7(802.11be) Vs Wi-Fi 8 (802.11bn)
  • 「Mac畅玩鸿蒙与硬件19」鸿蒙UI组件篇9 - 自定义动画实现
  • 臻于智境 安全护航 亚信安全受邀出席新华三智算新品发布会
  • vue3二次封装UI组件
  • 深入理解 Dockerfile 和 docker-compose[实战篇]
  • 持续监控和反馈:工具与方法详解
  • Python数据类型:数字
  • 信息学奥赛复赛考点变化趋势分析:动态规划与数据结构成主流
  • .NET Core WebApi第6讲:WebApi的前端怎么派人去拿数据?(区别MVC)
  • STM32之看门狗
  • C++学习路线(二十七)
  • 12. 内存管理
  • 修改Windows远程桌面3389端口
  • 一. nginx学习笔记 又长又臭篇幅
  • Go如何实现自旋锁
  • 【项目小技巧】【C++】 Debug 日志输出 调用者的函数名,所在文件名和行号
  • C语言学,标准库 <string.h>
  • 自适应神经网络架构:原理解析与代码示例
  • 操作系统期中复习第一单元
  • Docker部署教程:打造流畅的斗地主网页小游戏