Vue3组件通信之$emit和provide/inject

前面我们知道了父组件向子组件传值通过props,接下来我们再总结下子组件传递给父组件。

子组件传递给父组件

什么情况下子组件需要传递值给父组件呢?

  • 当子组件有一些事件发生的时候,而父组件需要更改展示的内容,那么就需要子组件向父组件传递值;
  • 当子组件需要传递一些内容给父组件的时候;比如:父组件跳转时需要子组件的值传递到下一个页面;

vue2中的用法(vue3也可以使用):

// App.vue
<template>
  <div>
    <h2>当前数为: {{count}}</h2>
    <Child @increment="increment" @decrement="decrement"></Child>
  </div>
</template>
<script>
import Child from './components/Child.vue'
export default {
  name: 'App',
  components: {
    Child
  },
  data() {
    return {
      count: 520
    }
  },
  methods: {
    increment(value) {
      this.count += value;
    },
    decrement(value) {
      this.count -= value;
    }
  }
}
</script>
// Child.vue
<template>
  <button @click="increment">加1</button>
  <button @click="decrement">减1</button>
</template>
<script>
export default {
  name: 'Child',
  methods: {
    increment() {
      this.$emit("increment", 2) // 可以在后面接上多个参数,用逗号隔开 比如:this.$emit("increment", 2, 3, 'hello')
    },
    decrement() {
      this.$emit("decrement", 2)
    }
  }
}
</script>

 vue3中第一种用法(通过数组形式):

// App.vue
<template>
  <div>
    <h2>当前数为: {{count}}</h2>
    <Child @addNum="increment" @subNum="decrement"></Child>
  </div>
</template>
<script>
import Child from './components/Child.vue'
export default {
  name: 'App',
  components: {
    Child
  },
  data() {
    return {
      count: 520
    }
  },
  methods: {
    increment(value) {
      this.count += value;
    },
    decrement(value) {
      this.count -= value;
    }
  }
}
</script>
// Child.vue
<template>
  <button @click="increment">加2</button>
  <button @click="decrement">减2</button>
</template>
<script>
export default {
  emits: ["addNum", "subNum"],
  name: 'Child',
  methods: {
    increment() {
      this.$emit("addNum", 100)
    },
    decrement() {
      this.$emit("subNum", 100)
    }
  }
}
</script>

效果和上面一样。

 第二种用法(通过对象形式):(主要是为了进行参数的验证

// Child.vue
<template>
  <button @click="increment">加</button>
  <button @click="decrement">减</button>
  <button @click="setOnePar">传单个参数</button>
  <button @click="setOtherPar">传递多个参数</button>
</template>
<script>
export default {
  emits: {
    addNum: null,
    subNum: null,
    setNum: payload => {
       console.log(payload) // 这儿打印的就是下方传递的值
       return true
    },
    setSomePar: (num, firstName, lastName) => {
       console.log(firstName + '-' + lastName) // Hello-Vue3
       if (num > 100) {
           return true
       } else {
           return false // 如果是return fasle的,那么会在出现警告,如下图
       }
    }
  },
  name: 'Child',
  data() {
    return {
      num: 100
    }
  },
  methods: {
    increment() {
      this.$emit("addNum", this.num)
    },
    decrement() {
      this.$emit("subNum", this.num)
    },
    setOnePat() {
      this.$emit("setNum", this.num)  
    },
    setOtherPar() {
      this.$emit("setSomePar", this.num, "Hello", "Vue3")
    }
  }
}
</script>

        上面所述,传入的num值为100,验证不通过,那么就会出现下面的警告。当return true ,警告就会消失,通过这个能够快速定位到自己传递的值是否满足条件。

 那不是父子组件该如何传值呢?(父与子孙)

         这是官方提供的一幅图,意思是在上级定义一个provide,那么只有在这一级下方的子孙组件才能够通过inject拿到值,而同级兄弟组件无法拿到。下面通过一个简单例子来演示一下用法:

// App.vue
<template>
  <div>
    <Child></Child>
  </div>
</template>
<script>
import Child from './components/Child.vue'
export default {
  provide: {  // 通过provide向子孙注入一些参数和参数值。
    name: '帅哥',
    age: 1
  },
  name: 'App',
  components: {
    Child
  },
  data() {
    return {
      count: 520
    }
  },
}
</script>

在Child组件中再定义一个子组件,也就是孙组件。

// Child.vue
template>
  <HelloWorld />
</template>
<script>
import HelloWorld from './HelloWorld.vue'
export default {
  name: "Child",
  components: {
    HelloWorld
  }
</script>

孙组件通过inject取值

// HelloWorld.vue
<template>
  <div class="">我是Hello World组件</div>
</template>
<script>
export default {
  inject: ['name', 'age'], // 子代通过inject取出父辈注入的值
  data() {
    return {}
  },
  created() {
    console.log(this.name, this.age); // "帅哥", 1
  }
}
</script>

如果说我们需要通过provide 传递自身data里面的值时,这时候需要换成函数形式:

// App.vue
<template>
  <div>
    <h2>当前数为: {{count}}</h2>
  </div>
</template>
<script>
import Child from './components/Child.vue'
export default {
  provide() { // 如果需要传入data里的值,则不能使用对象写法,否则会报错。
    return {
      name: '帅哥',
      age: this.count
    }
  },
  name: 'App',
  components: {
    Child
  },
  data() {
    return {
      count: 520
    }
  },
}
</script>

 但是这样仅仅只是传一次count的值,假如count的值被修改,传给子辈的值依然是原来的值,无法达到响应式,那么这个时候就要换一种写法:

// App.vue
<template>
  <div>
    <h2>当前数为: {{count}}</h2>
  </div>
</template>
<script>
import Child from './components/Child.vue'
import { computed } from 'vue'
export default {
  provide() { // 如果需要传入data里的值,则不能使用对象写法,否则会报错。
    return {
      name: '帅哥',
      age: computed(() => this.count) // ref对象.value,子辈组件通过 age.value取值
    }
  },
  name: 'App',
  components: {
    Child
  },
  data() {
    return {
      count: 520
    }
  },
}
</script>

总结:

        组件之间通信包含: 父传子(props)、子传父($emit)、父传子辈(provide/inject),那么还有一个是跨组件通信的是 vuex,后面再做记录。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值