• vue3组件通信方式


    vue3组件传值共8种方式

    1. props传值

    props适用于父传子,有两种写法,混合写法和纯vue3写法(语法糖)

    1. 混合写法(不推荐!!!)
    // 父组件
    <script setup lang="ts">
    import child from '../components/Child.vue'
    </script>
    
    <template>
      <child msg="父组件的消息"/>
    </template>
    
    
    // 子组件
    <script>
    export default {
      props: ["msg"], // 这行要写,不然下面接收不到
      setup(props) {
        console.log(props)
      },
    }
    </script>
    
    <template>
      <div class="greetings">
        <h1 class="green">{{ msg }}</h1>
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    2. 纯 Vue3 写法(语法糖)

    父组件变,子组件如下:

    <script setup lang="ts">
    defineProps<{
      msg: string
    }>()
    </script>
    
    <template>
      <div class="greetings">
        <h1 class="green">{{ msg }}</h1>
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    当js逻辑中需要使用传过来的props时,也可以定义一个变量承接一下:

    <script setup lang="ts">
    const props = defineProps<{
      msg: string
    }>()
    
    console.log(props)  // Proxy {msg: '父组件的消息'}
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:如果父组件是混合写法,子组件纯 Vue3 写法的话,是接收不到父组件里 data 的属性,只能接收到父组件里 setup 函数里传的属性
    如果父组件是纯 Vue3 写法,子组件混合写法,可以通过 props 接收到 data 和 setup 函数里的属性,但是子组件要是在 setup 里接收,同样只能接收到父组件中 setup 函数里的属性,接收不到 data 里的属性。所以官方也不推荐混合写法。

    2. attrs传值(父传子)

    attrs包含了父作用域里除 class 和 style 除外的非props 属性集合

    // 父组件
    <script setup lang="ts">
    import { reactive } from 'vue'
    import child from '../components/Child.vue'
    const info = reactive({foo: 111})
    console.log(info)
    </script>
    
    <template>
      <child msg="父组件的消息" :info="info" />
    </template>
    
    
    // 子组件
    <script setup lang="ts">
     import { useAttrs } from "vue"
    
    const attrs = useAttrs()
    console.log(attrs)
    </script>
    
    <template>
      <div class="greetings">
        <!-- <h1 class="green">{{ msg }} -- {{ info.foo }}</h1> -->
        <h1 class="green">{{ attrs.msg }} -- {{ attrs.info.foo }}</h1>
      </div>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3. expose/ref (子传父)

    父组件获取子组件的属性或者调用子组件方法

    // 子组件
    <script setup lang="ts">
    defineExpose({
        childInfo: '子组件的信息',
        greet() {
            console.log('来自子组件的问候')
        }
    })
    </script>
    
    // 父组件
    <script setup lang="ts">
    import { reactive, ref } from 'vue'
    import child from '../components/Child.vue'
    const info = reactive({foo: 111})
    // console.log(info)
    
    const comp = ref()
    const handlerClick = () => {
        console.log(comp.value.childInfo) // 获取子组件对外暴露的属性
        comp.value.greet() // 调用子组件对外暴露的方法
    }
    </script>
    
    <template>
      <child ref="comp" msg="父组件的消息" :info="info" />
      <button @click="handlerClick">按钮</button>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4. v-model

    支持多个数据双向绑定

    // Parent.vue
    <script setup>
        import child from '../components/Child.vue'
        import { ref, reactive } from "vue"
        const key = ref("1111")
        const value = ref("2222")
    </script>
    <template>
    	<child ref="comp" msg="父组件的消息" :info="info" v-model:key="key" v-model:value="value"/>
    </template>
    
    // Child.vue
    <template>
         <h1 class="green" @click="handlerClick">{{ attrs.msg }} -- {{ attrs.info.foo }}</h1>
    </template>
    <script setup>
        const emit = defineEmits(['key', 'value'])
    	const handlerClick = () => {
    	    emit('update:key', '新的key')
    	    emit('update:value', '新的value')
    	}
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    5. $emit

    // 子组件
    <script setup lang="ts">
    const emit = defineEmits(['childClick'])
    
    const clickMe = () => {
        emit('childClick', '子组件的信息')
    }
    </script>
    
    <template>
      <div class="greetings">
        <button @click="clickMe">点我</button>
      </div>
    </template>
    
    // 父组件
    <script setup lang="ts">
    const onChildClick = (msg: string) => {
        console.log(msg)
    }
    </script>
    
    <template>
      <child ref="comp" msg="父组件的消息" :info="info" v-model:key="key" v-model:value="value" @childClick="onChildClick"/>
    </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在子组件中也可以直接调用$emit方法:

    <button @click="$emit('childClick', '子组件的信息')">点我</button>
    
    • 1

    注意:在 < template > 中使用的 $emit 方法不能在组件的 < script setup > 部分中使用。组件要触发的事件可以显式地通过 defineEmits() 宏来声明。

    6. provide / inject(跨代传值)

    provide: 提供一个值,可以被后代组件注入。
    inject: 注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。

    // Parent.vue
    <script setup>
        import { provide } from "vue"
        provide('parent', 'parent的值')
    </script>
    
    // Child.vue
    <script setup>
        import { inject } from "vue"
        const value = inject('parent')
    	console.log(value)  // parent的值
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7. mitt

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

    使用步骤:

    // 安装mitt
    cnpm i mitt -S
    
    • 1
    • 2

    封装:

    mitt.js
    import mitt from 'mitt'
    const mitt = mitt()
    export default mitt
    
    • 1
    • 2
    • 3
    • 4

    使用:

    // 组件 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    8. vuex / pinia(跨代传值)

    pinia之前有篇详细介绍:pinia指南

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    zookeeper+kafka消息队列群集部署
    HTML5教程
    Anaconda下载安装教程,新手详细
    uni-app轮播图制作
    AQS之排斥锁分析
    MR场景直播-帮助企业高效开展更有意思的员工培训
    最新最全Jmeter+InfluxDB1.8+Grafana可视化性能监控平台搭建(win11本地)
    图文详解Linux基础经典教程(07)——CentOS安装Tomcat
    Tuxera Ntfs For Mac 2023的具体使用方法
    Apache-maven的安装与配置(IDEA)
  • 原文地址:https://blog.csdn.net/weixin_43867717/article/details/127268568