2

vue3组件常用的通信方式有很多,父传子*, 子传父父直接获取子ref,pinia,pinia在vue3中替换了vuex,更简洁,方便使用操作。EventBus公交车provide + inject等。

一、父传子(props)

父传子是通过父组件自定义标签添加属性,并传递数据给子组件,子组件接收通过 引入vue插件 解构 defineProps,调用并创建 props,同时指定要接收的数据名称。

 const  props = defineProps(['传递的数据名称']) 

案例:

父组件 在views文件夹中创建文件Home.vue
<script setup lang="ts">
// 引入vue插件
import { ref } from "vue"
// 引入子组件 
import Son from "../components/Son.vue"
// 定义传递给子组件的数据
const title = ref("我是子组件")
</script>
<template>
    <h1>父组件</h1>
    <!-- 使用子组件  -->
    <Son :title="title"></Son>
</template>


子组件  在components文件夹中创建Son.vue
<script setup lang="ts">
// 引入vue 解构 需要的方法
import { defineProps } from "vue"
// 调用defineProps方法并获取父组件传递的数据
// const props = defineProps(['title'])
const { title } = defineProps(['title']) // 可以简写 解构
</script>
<template>
    <!-- 渲染父组件传递的数据 -->
    <h1>{{ title }}</h1>
</template>


路由:
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      redirect: "/home"
    },
    {
      path: '/home',
      name: 'about',
      component: () => import('../views/Home.vue')
    }
  ]
})

export default router

效果图:
image.png

二、子传父(emit)自定义事件

子传父通过 父组件给子组件标签绑定自定义事件,将事件函数定义在父组件中,子组件中通过从 vue 中解构 defineEmits,调用并创建emit,同时接收父组件给绑定的事件。调用 emit触发父组件给绑定的事件,并传递数据,最后父组件在事件函数中通过参数接收子组件传递的数据。
案例:
父组件

<script setup lang="ts">
// 引入vue插件
import { ref } from "vue"

// 引入子组件
import Son from "../components/Son.vue"

// 定义传递给子组件的数据
const title = ref("我是子组件")
const msg = ref('')
// 定义事件函数
const handleAdd = (item: any) => {
    msg.value += item
}

</script>
<template>
    <h1>父组件</h1>
    <!-- 使用子组件 
        title: 传递给子组件的数据
        handleAdd:自定义事件
    -->
    <Son :title="title" @handleAdd="handleAdd"></Son>
    <h3>{{ msg }}</h3>
</template>

image.png

子组件

<script setup lang="ts">
// 引入vue 解构 需要的方法
import { defineProps, defineEmits } from "vue"
// 调用defineProps方法并获取父组件传递的数据
// const props = defineProps(['title'])
const { title } = defineProps(['title']) // 可以简写 解构

// 调用defineEmits方法 并接受父组件给绑定的事件
const emit = defineEmits(['handleAdd'])
const handleTitle = () => {
    emit("handleAdd", '我是子组件传递的数据')
}
</script>
<template>
    <!-- 渲染父组件传递的数据 -->
    <h1 @click="handleTitle">{{ title }}</h1>
</template>

image.png
效果图:
emit.gif

三、ref()

ref()方法 从vue中解构出 ref,然后父组件给dome标签或者子组件标签,添加ref属性,值是已经定义好的ref空数据的变量名称。
子组件从vue中解构出defineExpose,调用并想外暴露你想要获取的数据/方法
父组件通过从vue中解构生命周期onMounted,调用onMounted生命周期在里面 通过调用ref的数据value获取到 dome标签 或 子组件实例对象。
案例:
父组件

<script setup lang="ts">
// 引入vue插件
import { ref, onMounted } from "vue"
// 引入子组件
import Ref from "../components/Ref.vue";

// 定义ref
const myref = ref()
onMounted(() => {
    console.log(myref.value, '');
    // ref组件定义的数据
    console.log(myref.value.message);
    // 调用 ref组件中暴露出的方法
    myref.value.handleAdd()

})


</script>
<template>
    <h1>父组件</h1>
    <!-- 定义ref -->
    <Ref ref="myref"></Ref>
</template>

image.png

子组件

<script setup lang="ts">
// 引入vue
import { defineExpose, ref } from "vue"
// 定义数据
const message = ref("我是Ref子组件中的数据")
// 定义方法
const handleAdd = () => {
    console.log('我是Ref子组件中的方法');
}
// 通过 defineExpose 将数据方法暴露出去
defineExpose({
    message,
    handleAdd
})
</script>
<template>
    我是ref方法
</template>

image.png

效果图:
image.png

四、pinia

Vuex 和 Pinia 是 Vue 3 中的全局状态管理工具,使用这两个工具可以轻松实现组件通信。

它们都是全局的、所有组件都可以访问的、存储数据和方法,用来管理组件中的共享状态的仓库。并且能够在整个组件中进行访问和修改。让我们更有效的 组织 和 管理 整个组件的状态,使我们更轻松的开发复杂的、大型数据的前端项目。

同时解决了同步异步对调试工具的影响 和 代码的耦合性 还有组件之间数据通信的混乱问题。

  • 使用pinia 首先我们需要先下载安装

      npm install pinia
  • 然后需要在 main.js/ts 中配置
    image.png
  • 创建仓库文件夹(stores),同时定义仓库文件
    image.png
  • 仓库文件的内容

    • 导入
    • 创建仓库

      • 定义数据/方法
    • 导出仓库
    // 导入
    import { defineStore } from "pinia";
    import { ref } from "vue"
    // 创建仓库
    const tableStore = defineStore("table", () => {
      // 定义数据
      let count = ref(0)
    
      // 定义方法
      const changeCount = () => {
          // 数量自增
          count.value++;
      }
      const changeDrop = () => {
          // 数量自减
          count.value--;
      }
      // 返回 数据 和 方法
      return {
          count,
          changeCount,
          changeDrop
      }
    })
    // 导出仓库
    export default tableStore
  • 在组件中使用

    <script setup lang="ts">
    // 引入vue插件
    import { ref, onMounted } from "vue"
    // 引入仓库
    import tableStore from "../stores/table"
    // console.log(tableStore().count);
    
    // 定义数量加加的方法
    const handleCountAdd = () => {
      // 调用仓库中数量加加的方法
      tableStore().changeCount()
    }
    
    // 定义数量减少的方法
    const handleCountDrop = () => {
      // 调用仓库中数量减少的方法
      tableStore().changeDrop()
    }
    
    </script>
    <template>
      <h1>父组件</h1>
      <!-- 渲染仓库数据 / 方法调用-->
      <button @click="handleCountAdd">+</button>
      <h2>{{ tableStore().count }}</h2>
      <button @click="handleCountDrop">-</button>
    </template>

    效果图:
    count.gif

注意事项:默认从pinia仓库中获取到的数据不是响应式的,变成响应式,使用以下三个方案:

  • 定义依赖仓库数据 得到 新数据 的 计算属性 数据
  • 使用vue的组合式API中的toRef将仓库中的某个数据转换成行。

image.png
*


hanbo_bo
16 声望1 粉丝