【Vue组件通信方式】


前言

组件通信在工作中很常见但通讯的方式很多且使用场景也不同故在此记录和总结。

一、父子组件通信

1、父传子

①使用props接收父组件传递的属性

// 父组件
<template>
 <Helloword :msg=msg />
</template>

<script>
export default {
  data() {
    return {
      msg: 'message'
    }
  }
}
</script>
// 子组件
<template>
  <h1>{{ msg }}</h1>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
}
</script>

② 使用$attrs接收父组件未在 propsemits 中定义的属性和事件

  • 父组件level1向level2传递属性a、b、c和事件getA()、getB()、getC()
// level1.vue
<template>
    <p>Level1</p>
    <Level2
        :a="a"
        :b="b"
        :c="c"
        @getA="getA" 
        @getB="getB"
        @getC="getC"
    ></Level2>
</template>

<script>
import Level2 from './Level2'

export default {
    name: 'Level1',
    components: { Level2 },
    data() {
        return {
            a: 'aaa',
            b: 'bbb',
            c: 'ccc'
        }
    },
    methods: {
        getA() {
            return this.a
        },
        getB() {
            return this.b
        },
        getC() {
            return this.c
        }
    }
}
</script>
  • 组件level2使用this.$attrs接收父组件未在 propsemits 中定义的属性和事件
// level2.vue
<template>
    <p>Level2</p>
    <Level3
        :x="x"
        :y="y"
        :z="z"
        @getX="getX"
        @getY="getY"
        @getZ="getZ"
        v-bind="$attrs"
    ></Level3>
</template>

<script>
import Level3 from './Level3'

export default {
    name: 'Level2',
    components: { Level3 },
    props: ['a'],
    emits: ['getA'],
    data() {
        return {
            x: 'xxx',
            ...
        }
    },
    methods: {
        getX() {
            return this.x
        }
        ...
    },
    created() {
        console.log('level2', Object.keys(this.$attrs)) // 是 props 和 emits 后补
    },
}
</script>

在这里插入图片描述

  • 子组件level3接收父组件level2中未被propsemits接收的属性和事件。level2组件中定义level3组件时使用v-bind="$attrs"可接收level1中未在 propsemits 中定义的属性和事件。
<template>
    <p>Level3</p>
</template>

<script>
export default {
    name: 'Level3',
    props: ['x'],
    emits: ['getX'],
    inheritAttrs: false, // 避免在dom节点中增加传递的属性如<p b='b' c='c'></p>。使用attrs在只有一个根元素时就会生成
    created() {
         console.log('level3', Object.keys(this.$attrs)) // 是 props 和 emits 候补
    }
}
</script>

在这里插入图片描述

$attrs可以实现多级组件传递但是依赖v-bind="$attrs"。它是 props 和 emits 候补

③使用 $parent获取父组件的信息

   mounted() {
        console.log(this.$parent.getX())
    },

2、子传父

① 使用 $emit传递信息给父组件

父组件

<template>
  <HelloWorld :getMsg="getMsg"/>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    getMsg(msg) {
    	console.log(msg);
    }
  },
}

子组件

// 子组件:HelloWorld
<template>
   <button @click = "clickHandler">传递</button>
</template>

<script>
export default {
  name: 'HelloWorld',
 // emits: ['showMsg'], // Vue3
  methods: {
    clickHandler() {
      this.$emit('getMsg', 'hello world')
    }
  },
}
</script>

② 使用$refs获取子组件的属性和事件

父组件

<template>
    <p>Level3</p>
    <HelloWorld msg="hello 双越" ref="hello1"/> // 子组件
</template>
<script>
import HelloWorld from '../HelloWorld'
export default {
    ...
    mounted() {
        console.log(this.$refs.hello1.name) // created里面组件未渲染完成需要再mounted里面获取
    },
}
</script>

二、自定义事件适用于兄弟组件或“距离”较远的组件

兄弟组件1

<template>
  <p><button @click="trigger">点击传值</button></p>
</template>

<script>
import event from '../utils/event.js'

export default {
  name: 'CustomEvent2',
  methods: {
    trigger() {
      event.emit('showMsg', 'hello custom event') // 触发事件
    }
  },
}
</script>

// 兄弟组件2

<template>
  <p>接收值</p>
</template>

<script>
import event from '../utils/event.js'

export default {
  name: 'CustomEvent1',
  methods: {
    showMsg(msg) {
      console.log(msg)
    }
  },
  mounted() {
    event.on('showMsg', this.showMsg) //绑定事件
  },
  // Vue2.x beforeDestroy
  beforeUnmount() {
    event.off('showMsg', this.showMsg) // 组件销毁需要off事件。否则会造成内存泄漏
  },
}
</script>

Vue 版本的区别

自定义事件可能出现多个触发多个绑定所以容易造成项目混乱用的时候要遵守规范。

三、多级组件上下级provideinject

传递数据的组件使用provide传递

<template>
    <p>Level1: <input v-model="name"></p>
    <Level2></Level2>
</template>

<script>
import { computed } from 'vue'
import Level2 from './Level2'
export default {
    name: 'Level1',
    components: { Level2 },
    data() {
        return {
            name: 'lisa'
        }
    },
    provide() {
        return {
            info: computed(() => this.name) // cmputed包裹响应式数据实现下级组件数据响应式
        }
    }
}
</script>

需要被传递数据的组件使用inject接收。支持多层或多个组件接收。

<template>
    <p>Level2 {{info}}</p>
    <Level3></Level3>
</template>

<script>
import Level3 from './Level3'

export default {
    name: 'Level2',
    components: { Level3 },
    inject: ['info']
}
</script>

在这里插入图片描述

总结

  • 父子组件通讯
    • props emits this.$emit
    • $attrs 也可以通过 v-bind="$attrs" 向下级传递
    • $parent $refs
  • 多级组件上下级
    • provide inject
  • 跨级、全局
    • 自定义事件
    • Vuex
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue