Vue组件通信方式概述

98 阅读1分钟

父子组件通信

prop

最常用父子组件通信方式,父组件向子组件传递参数,子组件声明prop进行接收,若存在父组件传递给子组件的参数中有未声明prop的,则会将其放置在子组件的$attrs中

子组件Counter

<template>
</template>
<script>
export default {
  props: ["num1", "num2"],
  created() {
    console.log(this.num1) // 1
    console.log(this.num2) // 2
    console.log(this.$attrs) // { num3: 3 }
  }
}
</script>

父组件

<template>
    <Counter :num1="1" :num2="2" :num3="3"/>
</template>
<script>
import Counter from "path/to/Counter"
export default {
  components: {
    Counter
  },
}
</script>

$emit

$emit抛出一个事件给父组件并传递带上参数,父组件如果传递了该事件的回调,则父组件会执行该回调函数

$listeners

listenerslisteners和emit类似,不过$listeners存储的是父组件传递给子组件的所有事件,子组件可以通过该属性拿到对应的方法回调,直接执行并传递参数

子组件Counter

<template>
  <button @click="$listeners.update(num1++)">click</button>
</template>
<script>
export default {
  data() {
    return {
      num1: 0
    }
  }
}
</script>

父组件

<template>
  <div>
    <Counter @update="onUpdate"/>
    <span>{{num}}</span>
  </div>
</template>
<script>
import Counter from "path/to/Counter"
export default {
  components: {
    Counter
  },
  data() {
    return {
      num: 0
    }
  },
  methods: {
    onUpdate(num) {
      console.log(num)
      this.num = num;
    }
  }
}
</script>

ref

ref可以加在组件实例上,通过获取该ref得到组件实例,直接修改获取得到的组件实例的属性,例如data等

子组件Counter

<template>
  <span>{{num1}}</span>
</template>
<script>
export default {
  data() {
    return {
      num1: 0
    }
  }
}
</script>

父组件

<template>
  <div>
    <Counter ref="counter"/>
    <button @click="onClick">+1</button>
  </div>
</template>
<script>
import Counter from "path/to/Counter"
export default {
  components: {
    Counter
  },
  data() {
    return {
      num1: 0
    }
  },
  methods: {
    onClick() {
      const counter = this.$refs["counter"];
      counter.num1++;
    }
  }
}
</script>

slot和scope-slot

通过作用域插槽,可以让父组件在作用域插槽内部访问子组件传递给作用插槽的数据

子组件Counter

<template>
  <div>
    <header>
      <slot name="userInfo" :userInfo="user"></slot>
    </header>
    <main>
      some main info
    </main>
  </div>
</template>
<script>
export default {
  data() {
    return {
      user: {
        username: "ainuo5213",
        description: "小蔡鸡"
      }
    }
  }
}
</script>

父组件

<template>
  <Counter ref="counter">
    <template #userInfo="slotProp">
      <p>昵称:{{slotProp.userInfo.username}}</p>
      <p>描述:{{slotProp.userInfo.description}}</p>
    </template>
  </Counter>
</template>
<script>
import Counter from "path/to/Counter"
export default {
  components: {
    Counter
  },
}
</script>

跨组件通信

vuex

vuex统一的数据仓库,全局共享单一实例的数据,例子见官方文档

router

router可以通过地址栏进行组件的间接通信

eventBus

导出一个vue的eventbus

export default new Vue({})

开启监听

import eventBus from "path/to/eventBus"
export default {
    name: "App",
    created() {
        eventBus.$on("eventName", this.onHookInvoked)
    },
    destroyed() {
        eventBus.$off("eventName", this.onHookInvoked)
    },
    methods: {
        onHookInvoked(callback) {
            const params = 22;
            callback(params)
        }
    }
}

触发监听

<template>
  <buttton @click="onClick">click</buttton>
</template>
<script>
import eventBus from "path/to/eventBus"
export default {
  name: "App",
  methods: {
    onClick() {
      eventBus.$emit("eventName", params => {
        console.log(params)
      });
    }
  }
}
</script>

provide和inject

父组件使用

<script>
import Numbers from './components/Numbers.vue'

export default {
  name: 'App',
  components: {
    Numbers
  },
  provide: {
    foo: "111"
  }
}
</script>

子组件使用

<script>
export default {
  name: 'HelloWorld',
  inject: ["foo"],
  mounted() {
    console.log(this.foo)
  }
}
</script>

若有其他案例请提供补充,谢谢大佬