• Vue3之属性传值的四种情况


    Vue3之属性传值的四种情况

    一、引言

    在vue3中,组件与组件之间是可以传递属性的,包括三种类型:

    • 父组件向子组件传值
    • 子组件向父组件传值
    • 祖先组件向后代组件传值
    • 兄弟组件之间传值

    本篇文章来分析一下他们分别是如何实现的?

    本篇文章均采用vue3+ts格式书写

    二、父组件向子组件传值

    首先,在父组件中子组件标签上 加上自定义的属性名称以及对应的数据,如下:

    <Header class="xm-header" :title="data">Header>
    
    • 1

    这里,我们自定义属性名为title,属性值为data,注意data为响应式数据

    其次,在子组件中要去通过defineProps()方法接收这个值,

    const props = defineProps<{
      title: string
    }>()
    
    • 1
    • 2
    • 3

    这里使用的是ts写法,父组件传递的值会被封装成一个对象,在<>中写上对象的类型推断,即可取到值。

    这里我们可以看一下props的内容

    在这里插入图片描述

    且看源码可以知道,这个返回的对象是一个只读属性,readonly是Vue3中提供的一个新特性,用于将一个响应式对象变成只读对象。

    export declare function defineProps<TypeProps>(): DefineProps<LooseRequired<TypeProps>, BooleanKey<TypeProps>>;
    export type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
        readonly [K in BKeys]-?: boolean;
    };
    
    • 1
    • 2
    • 3
    • 4

    它的返回值是Readonly,且这个泛型T是我们传进去的ts类型

    {title: string}
    
    • 1

    一个普通的object对象,而在template中可以使用两种方式获取到title的值

    1. 直接使用{{props.title}}
    2. {{title}}

    第二种方式我也不知道为什么可以直接使用,希望有大佬在评论区解答一下

    存在一种情况,就是父组件没有传值,但是我希望有个默认值,可以使用withDefault()方法

    withDefaults(
      defineProps<{
      title: string
    }>(),
      { title: '默认标题' }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    第一个参数传defineProps()方法,第二个参数传一个对象,这个对象中,还能这样使用:

    {title:()=>"默认标题"}
    
    • 1

    三、子组件向父组件传值

    子组件向父组件中传值使用defineEmits()方法,它的作用是在使用emits声明由组件触发的自定义事件时获得完整的类型推导。

    const emit = defineEmits<{
        //在父组件中自定义的返回事件的名称,name是方法的参数,其对应类型为传递的值的类型
      onClick:[name:string]
    }>()
    
    • 1
    • 2
    • 3
    • 4

    注:这里声明的onClick不能使用on-click的形式,会报错

    同时还要在子组件中声明一个事件,实现动态传递值,比如说你定义一个按钮,其执行的函数是send函数。

    const send = () => {
      emit("onClick","gunala")
    }
    
    • 1
    • 2
    • 3

    这里可以使用emit方法,注意:这个方法是defineEmits的返回值。

    第一个参数是:在父组件中自定义的返回事件的名称;第二个参数是:要传递的数值

    最后一步,在父组件中接收返回的自定义函数

    <Header class="xm-header" :title="data" @onClick="name">Header>
    
    • 1

    这里name是一个函数,需要在父组件中定义声明。

    const name = (target:string):void=>{
        //这个target就是我们传递的值
      console.log(target);
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    四、祖先组件向后代组件传值

    如果爷爷组件想向孙子组件传值的话,以前是要先向父亲组件传值,再由父亲组件向儿子组件传值

    vue3提供了一种简便的方式:provide()和inject()

    前提,在setup阶段调用,即在中使用。

    比如,我现在想向子孙组件中传递一个参数,改变子孙组件中的一个div块的背景色

    //祖先组件
    import { ref, provide } from 'vue'
    const color = ref("yellow")
    provide("color", color)
    
    • 1
    • 2
    • 3
    • 4

    在子孙组件中接收参数

    //子孙组件
    <script setup lang="ts">
    	import { inject } from 'vue';
    	//引入ts中的Ref类型的声明
    	import type { Ref } from 'vue';
    	const color = inject<Ref<string>>('color')
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其次可以在子孙组件中的style样式中直接获取到color值,使用v-bind

    .box {
        width: 100px;
        height: 100px;
        background-color: v-bind(color);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    五、兄弟组件之间传值

    Vue3中推荐使用第三方库 mitt 作为兄弟组件传值的媒介,不再需要找到父组件作为传值的媒介,提高服务性能。

    使用方法:

    1. 安装mitt库
    npm run mitt -S
    
    • 1
    1. 在main.ts中注册为全局配置属性
    import App from "./App.vue";
    //引入mitt
    import mitt from "mitt"
    const Mitt = mitt();
    
    export const app = createApp(App);
    //配置全局属性,属性名:$Bus
    app.config.globalProperties.$Bus = Mitt;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这样直接使用,在后面会没有类型推导和提示,可以声明$Bus的类型。

    declare module "vue" {
        //用于声明全局属性类型
        export interface ComponentCustomProperties {
            $Bus: typeof Mitt;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 在组件中使用

    我在这里声明了两个兄弟组件,他们在一个父亲组件中被引用

    在这里插入图片描述

    我在A组件中写了一个按钮,其功能是向B组件传值,

    
      
    
      
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在B组件监听接收A组件传来的值

    <script lang="ts" setup>
      	import { getCurrentInstance } from 'vue';
    	const instance = getCurrentInstance()
        //on()方法是监听函数,监听是否接受到第一个事件名
    	instance?.proxy?.$Bus.on('data', (data: string) => {
      		console.log('B组件接收到数据:', data);
    	})
     </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这里来看一下结果:

    在这里插入图片描述

    也可以监听所有事件:“*”

    <script lang="ts" setup>
      	import { getCurrentInstance } from 'vue';
    	const instance = getCurrentInstance()
        //on()方法是监听函数,监听是否接受到第一个事件名,函数的第一个属性type是监听到的事件名称,data是传递的值
    	instance?.proxy?.$Bus.on('*', (type:string,data: string) => {
      		console.log('B组件接收到来自',type,'的数据:', data);
    	})
     </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    取消对某个事件的监听:

    // 需要取消指定事件的监听,需要将回调定义在外部
    const Fn =  (data: string) => {
      console.log('B组件接收到数据:', data);
    }
    instance?.proxy?.$Bus.on('data',Fn)
    instance?.proxy?.$Bus.off('data',Fn)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    清除所有事件的监听:

    instance?.proxy?.$Bus.all.clear()
    
    • 1
  • 相关阅读:
    顺丰面试,第二个问题把我劝退了!
    ESP8266-Arduino网络编程实例-ESP-MESH传感器数据发送与接收
    FOC学习笔记-坐标变换以及仿真验证
    Monitor Deep Learning Training Progress
    阿里巴巴建议这样遍历Map,今天就用几种方式做个比较一下看那种最好用
    Ubuntu安装PCAN-View
    Python之json模块
    Ubuntu20.04配置C/C++环境
    实现在外网SSH远程访问内网树莓派的详细教程
    LQ0250 n进制小数【程序填空】
  • 原文地址:https://blog.csdn.net/m0_63837020/article/details/136333514