Vue3组件通信的八种方式

Vue3 组件通信的8种方式

1. props

父传子,直接传值 ,用v-bind绑定值传递给孩子, 子传父,父亲写方法传递给孩子,孩子接收方法然后调用并把值传递给父
组件通信props

2. 自定义事件

自定义事件

3. mitt(不常用,知道就行)

3.1 安装mitt

npm i mitt 

3.2 使用mitt

import mitt from 'mitt'

const emitter = mitt()  //emitter 能绑定事件,解绑事件,触发事件

export default emitter

// 导出emitter后,在mian.ts中引入供后续使用



//emitter 共有四个方法
emitter.all()                         //拿到所有绑定的事件
emitter.on('事件名', callback)      	//绑定事件
emitter.emit('事件名', callback)      //触发事件
emitter.off('事件名', callback)      //解绑事件

4. v-model(重要)

当我们在开发的时候,我们在DOM标签,自定义组件,UI库组件上使用的都是 v-model="xxxxxx",但是对于它为什么能够双向绑定数据,我们还是可以知道一下。

Vue 2的v-model底层:

<template>
	<input v-model="username" />

// Vue2 底层
<input :value="username" @input = "username = $event.target.value" />
</template>

<script>
	let username = ref("张三")
</script>

<style></style>

Vue 3的v-model底层(对于2有些小改动):

<template>
	//自定义组件
	<MyInput v-model="username" />
	//当然也可以修改modelValue的值,当我们这样写了之后,底层的modelValue都被被替换成title,知道就行
	<MyInput v-model:title="username" />


	// Vue3 底层, 
	<MyInput :modelValue="username" @update = "username = $event" />
</template>

<script setup>
	let username = ref("张三")
</script>

<style></style>

// MyInput 组件,结合props + 自定义事件进行组件间通信,通常来说是UI库设计人员写的底层代码,我们作为开发会用即可,但是能了解它的底层逻辑还是对我们写代码很有帮助的

<template>
	<input type="text" :value="modelValue" @input = "emits('update:modelValue', $event.target.value)"
</template>

<script setup>
	defineProps(['modelValue'])
    const emits = defineEmits(['update:modelValue'])
</script>

<style></style>

最后对于这个点再说说$event

  • 对于原生事件,$event就是事件对象,能$event.target.value
  • 对于自定义事件,$event就是触发事件时所传递的数据,不能.target
5. $attrs(不推荐使用,知道就行)

通用于祖传孙,通过父组件(中间组件)作为桥梁传递,祖传递的数据,如果不被defineProps接收,那么都会被$attrs接收

6. Provide、inject依赖注入(重要,需要掌握)

对于多层级嵌套的组件我们使用 props 则必须将其沿着组件链逐级传递下去,这会非常麻烦,provideinject 可以帮助我们解决这一问题

Provide (提供):

<script setup>
import { provide, ref } from 'vue'

//1. 注入名可以是一个字符串或者是Symbol(Es6),使用Symbol()函数可以返回一个独一无二的值
//2.一个组件可以多次调用 provide(),使用不同的注入名,注入不同的依赖值
//3.后代组件会用注入名来查找期望注入的值
//4.第二个参数是提供的值,值可以是任意类型,包括响应式的状态,比如一个 ref (important!!!)

const message = ref('hello!')

provide(/* 注入名 */ 'message', /* 值 */ message)


//我们既可以在一个组件中提供依赖,还可以在整个应用层面提供依赖,在应用级别提供的数据在该应用内的所有组件中都可以注入
const app = createApp({})

app.provide(/* 注入名 */ 'message', /* 值 */ 'hello!')

</script>

Inject (注入):

  • 如果注入的值是一个ref,那么注入进来的就是一个ref对象,不会自动解包为其内部的值,能够一直保持响应性链接。
<script setup>
import { inject } from 'vue'

const message = inject('message')
</script>
  • 如果inject传入的注入名没有被祖先链上的组件提供,会出现警告,这种情况的话我们需要声明一个默认值
// 如果没有祖先组件提供 "message"
// `value` 会是 "这是默认值"
const value = inject('message', '这是默认值')
  • 如果想要提供的数据不被注入方更改,使用 readonly() 来包装提供的值
<script setup>
import { ref, provide, readonly } from 'vue'

const count = ref(0)
provide('read-only-count', readonly(count))
</script>
  • 尽可能将任何对响应式状态的变更都保持在供给方组件中
7. Pinia(重要,需要掌握)

关于Pinia其实也很简单,大致核心就是在Vue3中:

  • ref就是state属性
  • computed() 就是 getters
  • function() 就是 actions
  • 采用 defineStore()定义,返回值是UsexxxStore第一个参数约定俗成为store文件夹中当前文件的名称,当作唯一ID,第二个参数在Vue3中我们传入一个箭头函数(()=> { })
  • 我们需要将定义的refcomputed()function(), 通过一个对象return暴露出去,供外部组件使用

更多的细节大家可以去官网查看,传送门 Pinia

8. slot-插槽(重要,需要掌握)
  • 默认插槽

    <FancyButton>
      Click me! <!-- 插槽内容,可以是任意的模板内容,甚至可以是组件 -->
    </FancyButton>
    
    <button class="fancy-btn">
      <slot></slot> <!-- 插槽出口,相当于插槽内容的占位符 -->
    </button>
    

    父组件没有提供任何插槽内容时,只需要在slot标签之间加默认值,即 <slot>默认值</slot>,默认值会被作为默认内容渲染,如果我们提供了插槽内容,那么被显式提供的内容会取代默认内容。

    默认插槽其实也是一种具名插槽,它的名字是<slot name="defalult"/>

  • 具名插槽
    具名插槽就是给每个插槽取个独一无二的名字,以保证在有多个插槽出口的时候,每个出口能渲染不一样的内容,说白了就是一个萝卜一个坑

    <div class="container">
      <header>
        <slot name="header"></slot>
      </header>
      <main>
        <slot></slot>
      </main>
      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
    

    要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令,如下:

    <BaseLayout>
      <template v-slot:header>
        <!-- header 插槽的内容放这里 -->
      </template>
    </BaseLayout>
    
    //v-slot对应的简写
    <BaseLayout>
      <template #header>
        <!-- header 插槽的内容放这里 -->
      </template>
    </BaseLayout>
    

    当一个组件同时接收默认插槽和具名插槽时,所有位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容

    <BaseLayout>
      <template #header>
        <h1>头部</h1>
      </template>
    
      <!-- 隐式的默认插槽 -->
      <p>任意内容.</p>
      <p>另外一段.</p>
    
      <template #footer>
        <p>尾部</p>
      </template>
    </BaseLayout>
    
  • 作用域插槽
    由于插槽的内容无法访问到子组件的数据(数据),而我们想要使用父组件域内和子组件域内的数据,需要给slot传递数据,父组件进行接收

<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>
// 子组件传递过来的数据都会在slotProps对象中
<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>


//也可以解构

<MyComponent v-slot="{text,  count}">
  {{ text }} {{ count }}
</MyComponent>

具名作用域插槽用法:

<div>
  <slot name="mesg" :text="greetingMessage" :count="1"></slot>
</div>
<MyComponent v-slot:mesg="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>


//有时候你也会看到这种简写形式,是一样的
<MyComponent #mesg="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

默认作用域插槽用法:

<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>
<MyComponent #default="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

v-slot:xxx就是选择插槽,v-slot="xxx"就是子组件传的值,这句话很关键,能理解了说明你也懂插槽了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值