Vue3.0学习第七天 组件通讯

160 阅读2分钟

1-父传子

  • 父组件
<template>
  <div class="container">
    <h1>父组件</h1>
    <p>{{money}}</p>
    <hr>
    <-- 通过数据绑定的方式传递给子组件 -->
    <Son :money="money" />
  </div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {
  name: 'App',
  components: {
    Son
  },
  
  setup () {
    const money = ref(100)
    return { money }
  }
}
</script>
  • 子组件
<template>
  <div class="container">
    <h1>子组件</h1>
    <p>{{money}}</p>
  </div>
</template>
<script>
import { onMounted } from 'vue'
export default {
  name: 'Son',
  // 子组件定义props
  props: {
    money: {
      type: Number,
      default: 0
    }
  },
  setup (props) {
    // 通过setup函数的第一个参数获取父组件数据money
    console.log(props.money)
  }
}
</script>

父组件还是通过给子组件绑定属性,子组件则是在props中定义参数名,通过setup函数的第一个参数props接收 setup(props)

2-子传父

  • 父组件
<template>
  <div class="container">
    <h1>父组件</h1>
    <p>{{money}}</p>
    <hr>
    <-- 子组件自定义事件绑定父组件的函数 -->
    <Son :money="money" @change-money="updateMoney" />
  </div>
</template>
<script>
import { ref } from 'vue'
import Son from './Son.vue'
export default {
  name: 'App',
  components: {
    Son
  },
  setup () {
    const money = ref(100)
    // 父组件定义函数
    const updateMoney = (newMoney) => {
      money.value = newMoney
    }
    return { money , updateMoney}
  }
}
</script>
  • 子组件
<template>
  <div class="container">
    <h1>子组件</h1>
    <p>{{money}}</p>
    <button @click="changeMoney">花50元</button>
  </div>
</template>
<script>
import { onMounted } from 'vue'
export default {
  name: 'Son',
  // 子组件接收父组件数据使用props即可
  props: {
    money: {
      type: Number,
      default: 0
    }
  },
  // 接收setup函数的第二个参数中的 emit 用来触发自定义事件的函数
  setup (props, {emit}) {
    // 向父组件传值
    const changeMoney = () => {
      // 触发自定义事件,传递参数
      emit('change-money', 50)
    }
    return {changeMoney}
  }
}
</script>

父组件中还是使用 @自定义事件名=函数 触发,子组件需要接收setup中的第二个参数 context (context是非响应式对象,所以可以通过解构来获取其中的属性,context中包含了attrs,slots,emit,expose),所以子组件一般可以这样写 setup(props,{emit}) ,之后通过emit('自定义事件名',参数)传递参数

3-v-model双向绑定

1.使用上与vue2的不同之处

vue3.0中移除了v-bind的 .sync 修饰符而使用 带参数的v-model 替代,并允许在组件同时绑定多个v-model

  • vue2中的写法
<Son :money.sync='money'  />
  • vue3中的写法
<Son v-model:money="money" />

2.原理上与vue2的不同之处

无论vue2还是vue3它都是一个语法糖,都会生成一个属性和一个事件

  • vue2中v-model原理
    • value属性和input事件的语法糖
  • vue2中.sync原理
    • [属性名]属性和update:属性名事件的语法糖
  • vue3中v-model原理
    • 不带参数时:modelValue属性和update:modelValue事件的语法糖
    • 带参数时:[参数名]属性和update:参数名事件的语法糖

4-依赖注入

使用场景:有一个父组件,它的一个或多个后代组件想要共享父组件数据。

  • 父组件
<template>
  <div class="container">
    <h1>父组件 {{money}} <button @click="money=1000">发钱</button></h1>
    <hr>
    <Son />
  </div>
</template>
<script>
import { provide, ref } from 'vue'
import Son from './Son.vue'
export default {
  name: 'App',
  components: {
    Son
  },
  setup () {
    // 定义数据
    const money = ref(100)
    // 定义修改数据的方法
    const changeMoney = (saleMoney) => {
      money.value = money.value - saleMoney
    }
    // 将数据提供给后代组件 provide
    provide('money', money)
    // 将函数提供给后代组件 provide
    provide('changeMoney', changeMoney)

    return { money }
  }
}
</script>
  • 子组件
<template>
  <div class="container">
    <h2>子组件 {{money}}</h2>
    <hr>
    <GrandSon />
  </div>
</template>
<script>
import { inject } from 'vue'
import GrandSon from './GrandSon.vue'
export default {
  name: 'Son',
  components: {
    GrandSon
  },
  setup () {
    // 接收祖先组件提供的数据 inject
    const money = inject('money')
    return { money }
  }
}
</script>
  • 孙组件
<template>
  <div class="container">
    <h3>孙组件 {{money}} <button @click="fn">消费20</button></h3>
  </div>
</template>
<script>
import { inject } from 'vue'
export default {
  name: 'GrandSon',
  setup () {
    // 接收祖先组件提供的数据 inject
    const money = inject('money')
    // 不能自己修改数据,遵循单选数据流原则(修改哪个组件的数据就使用哪个组件内定义的函数)
    // 接收祖先组件提供的函数 inject
    const changeMoney = inject('changeMoney')
    // 修改数据
    const fn = () => {
      changeMoney(20)
    }
    return {money, fn}
  }
}
</script>

总结:

  • provide函数提供数据和函数给后代组件使用
  • inject函数给当前组件注入provide提供的数据和函数