Vue3中组件通讯的方式

Vue3中组件通讯的方式

1 🤖GPT🤖: (答案有点问题混淆了vue2的内容)

父组件向子组件传递数据

  1. props 子组件通过 props 属性从父组件接收数据。
  2. emit事件子组件通过emit 事件 子组件通过 emit事件子组件通过emit 发射事件向父组件发送消息。
  3. provide / inject 父组件通过 provide 提供数据,子组件通过 inject 注入数据。
  4. ref 父组件通过 ref 获取子组件实例,然后调用子组件的方法。
  5. Slots 在父组件中使用Slots向子组件传递内容,子组件可以通过$slots来获取这些内容,并将它们渲染到自己的视图中。

子组件向父组件传递数据

emit事件使用emit 事件 使用 emit事件使用emit 发射事件,父组件通过 v-on 监听该事件。

provide/inject 子组件通过 inject 注入父组件提供的数据,然后触发 Action 修改该数据,父组件的数据也就变了。

Ref 父组件通过 ref 获取子组件的实例,子组件调用 ref 内容,父组件监听其变化。

Vuex 使用 Vuex 管理共享状态,子组件通过 mutation 或 action 修改状态,父组件监听状态变化。

Event Bus 利用 Vue 的实例作为 EventBus ,子组件通过 Bus.$emit 触发事件,父组件监听该事件的变化。

兄弟组件之间的数据传递

EventBus 可以使用EventBus来创建一个全局的事件总线,从而在兄弟组件之间进行数据传递。通过在兄弟组件中使用emit和emit和emit和on来触发和监听事件,从而实现数据的传递。

Provide 和 Inject Vue 3中的Provide和Inject API也可以用于兄弟组件之间的数据传递,可以通过在父组件中使用Provide来提供数据,然后在兄弟组件中使用Inject来获取这些数据,从而实现兄弟组件之间的数据传递。

Vuex Vuex是Vue 3中的状态管理库,可以用于管理全局的数据状态,从而实现兄弟组件之间的数据传递。

父组件向子组件传递数据:(父传子)

1. props:

逐级透传

父组件

html 复制代码
<template>
	<ChildComponent  :msg="message" />
</template>
<script setup> 
	const message = 'hello'
</script>

子组件:

html 复制代码
<template>
	<p>{{ msg }}</p> 
</template>

<script setup>
	defineProps(['msg'])
</script>

2. provide/inject

跨级共享

provide(提供): 父组件中注册,传递给后代组件的数据对象

inject( 注入):后代组件中接收父组件提供的数据对象

父组件 Root.vue

html 复制代码
<template>
  <div>
    <Footer/>
  </div>
</template>
<script setup>
    import { ref,provide } from 'vue'
    import Footer from './Footer.vue' //导入子组件Footer
    //父组件中注册给共享后代组件的信息
    provide(/* 注入名 */ 'mgs', /* 值 */ '父组件信息!')  
</script>

子组件 Footer.vue

html 复制代码
<template>
    <DeepChild/>
</template>
<script setup>
import DeepChild from './DeepChild.vue' //导入子组件Footer
//在子组件Footer中可以不需要接收父组件Root共享的数据,在后代组件中,直接接收,实现跨级传递
</script>

子孙组件DeepChild.vue

不需要父组件Footer传递,就能跨级获取祖先组件Root传递的数据

html 复制代码
<template>
    <div>
        {{ msg }}
    </div>
</template>
<script setup>
    import { inject } from 'vue'
    const msg = inject('msg') //跨级接收祖先组件的共享的信息
    console.log(msg) //父组件信息
</script>

父组件向子组件传递信息,如果是多层组件嵌套(父>子>孙>孙孙...) ,props逐级透传十分麻烦,props可用但不优雅,更推荐 provide/inject依赖注入的方式;

provide/inject依赖注入中父组件向后代组件通讯,如果说props是传递,逐级透传的,那么依赖注入更准确来说是在父组件中与后代组件共享数据,可实现跨级共享;

3. 透传 Attributes(非props和非emit)

"透传 attribute"指的是传递给一个组件,却没有被该组件声明为 props 或 emits 的 attribute 或者 v-on 事件监听器。最常见的例子就是 class、style 和 id

作用: 在父组件标签上声明的参数/事件监听,会透传到子组件中

3.1 Attributes透传参数

父组件

html 复制代码
<!-- 透传参数class到子组件中 -->
<MyButton class="large" />

子组件 MyButton.vue

html 复制代码
<button>click me</button>

最终渲染的html标签

html 复制代码
<button class="btn large">click me</button>
3.2 Attributes透传事件监听(有点像冒泡事件)

父组件

html 复制代码
 <!-- 透传参数class到子组件中 -->
 <MyButton @click="onClick1"  />
 
 <script setup>
     import  MyButton from './MyButton.vue'
     const onClick = ()=>{
       cosole.log("透传事件监听,从父组件触发")
     }
 </script>

子组件 MyButton.vue

html 复制代码
<button @click ="onClick2">click me</button>

当点击子组件的按钮时:

父组件的onClick1 和子组件的onClick2 都触发

3.3 useAttrs 像defineProps获取透传Attributes

父组件

html 复制代码
<!-- 透传参数ms到子组件中 -->
<Child  msg="父组件中传递数据"  />

<script setup>
    import  Child from './child.vue'
</script>

子组件child.vue

html 复制代码
 <script setup>
import { useAttrs } from 'vue'
//useAttrs像defineProps获取透传Attributes
const attrs = useAttrs()
cosole.log(attrs.msg) //父组件中传递数据
</script>

4. slot 插槽

父组件向子组件指定位置插入html内容渲染

4.1 默认插槽(传递html/组件)

父组件

html 复制代码
<template>
  <Child>
    <div>插入的html,将会在子组件中指定slot的位置渲染出来</div>
  </Child>
</template>

子组件

html 复制代码
<template>
   <slot><slot/>
</template>
4.2 具名插槽(父->子)

当需要渲染不同的内容时,默认插槽显然不够用,需要按插槽的name名进行区别渲染

父组件

#XX == v-slot:XX 这2个写法都是插槽name名在父组件的写法

html 复制代码
<子>
  <template #XX1> 插槽1 </template>
  <template v-slot:XX2>插槽2</template>
</子>

子组件

html 复制代码
<template>
   <slot name="XX1"><slot/>
   <slot name="XX2"><slot/>  
</template>
4.3 作用域插槽 (子>父)

作用插槽分为: 默认作用域插槽和 具名作用域插槽

elementUI中table组件插入按钮就是使用了默认作用域插槽

4.3.1. 默认作用域插槽: v-slot:defalut = #defalut = v-slot

父组件

html 复制代码
<子>
  <template #default="slotProps">
      {{slotProps.XX}}
  </template>
</子>

子组件

html 复制代码
<slot :XX="子组件数据"></slot>
4.3.2. 具名作用域插槽

父组件

html 复制代码
 <子>
  <template #slotName="slotProps">
      {{slotProps.XX}}
  </template>
</子>

子组件

html 复制代码
<slot name="slotName"  :XX="子组件数据"></slot>

Element-PlusUI组件框架中table组件

table组件中就用到了作用域插槽

html 复制代码
<el-table :data="tableData" style="width: 100%" max-height="250">
  <el-table-column fixed prop="date" label="Date" width="150" />
  <el-table-column fixed="right" label="Operations" width="120">
    <template #default="scope">
        {{scope.row.date}}
    </template>
  </el-table-column>
</el-table>

子组件向父组件传递数据:(子传父)

1.组件事件emit

父组件中v-on(简写@)监听

子组件中$emit触发

父组件

父组件中v-on(简写@)监听

html 复制代码
 <template>
  <child @some-event="callback" />
</template>
<script setup>
import child from './child.vue'
const callback = (target) => {
  console.log('父组件-callback ')
  console.log(target) //子组件传递的数据
}
</script>

子组件

子组件中$emit触发

html 复制代码
 <templete>
  <!-->在templete中使用$emit触发,不需要defineEmits声明</-->    
  <button @click="$emit('someEvent', '子组件传递的数据')">click me</button>  
    <!-->触发方法中的emit,需要defineEmits声明</-->      
   <button @click="buttonClick()">click me</button>  
</templete>

<script setup>
//setup语法糖中显示声明emit    
const emit = defineEmits(['someEvent'])
function buttonClick() {
  //触发emit  
  emit('someEvent', '子组件传递的数据')
}
</script>

2. defineExpose/ ref

子组件中通过defineExpose向外暴露数据或方法

父组件中通过ref获取子组件暴露的数据或调用子组件的方法

父组件

在父组件中需要声明子组件的ref, 如:const childRef = ref()

html 复制代码
 <template>
  <child ref="childRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 引入子组件
import child from './child.vue'
    
const childRef = ref()
onMounted(() => {
  console.log(childRef.value.data1) // 子组件数据
  childRef.value.fn() // 子组件中的方法
})
</script>

子组件

子组件中通过defineExpose向外暴露数据或方法

html 复制代码
 <script setup>
import { ref } from 'vue'
const data1 = ref('子组件数据')
const fn = () => {
  console.log('子组件中的方法')
}
//通过defineExpose向外暴露数据或方法
defineExpose({
  data1,
  fn
})
</script>

跨组件通讯-全局状态共享(状态管理库): Vuex /Pinia

在Vue3已经逐渐用Pinia这个菠萝替代Vuex了

Pinia,官方文档描述:符合直觉的 Vue.js 状态管理库 hook的写法!

其实Pinia的官方文档就写得很清楚了:🛬🛬🛬🛬🛬🛬🛬🛬🛬🛬🛬🛬为什么你应该使用 Pinia?

相关推荐
Bigger13 小时前
Tauri (25)——消除搜索列表默认选中的 UI 闪动
前端·react.js·weui
hongkid13 小时前
React Native 如何打包正式apk
javascript·react native·react.js
李少兄13 小时前
简单讲讲 SVG:前端开发中的矢量图形
前端·svg
前端小万13 小时前
告别 CJS 库加载兼容坑
前端·前端工程化
恋猫de小郭13 小时前
Flutter 3.38.1 之后,因为某些框架低级错误导致提交 Store 被拒
android·前端·flutter
JarvanMo13 小时前
Flutter 需要 Hooks 吗?
前端
光影少年13 小时前
前端如何虚拟列表优化?
前端·react native·react.js
Moment13 小时前
一杯茶时间带你基于 Yjs 和 reactflow 构建协同流程图编辑器 😍😍😍
前端·后端·面试
菩提祖师_14 小时前
量子机器学习在时间序列预测中的应用
开发语言·javascript·爬虫·flutter
invicinble14 小时前
对于前端数据的生命周期的认识
前端