Vue3从入门到实战:深度掌握组件通信(上部曲)

props的概念:

当你使用Vue 3的组合式API时,props就是一种让你可以从父组件向子组件传递数据的方式。你可以想象成你在给子组件写一封信,把需要传递的信息放在信封里。

在Vue 3中,你可以在子组件的代码中定义props,就像在信封上写下你需要传递的信息的名字。你可以指定每个props的类型,比如是字符串、数字等等,这样Vue就会帮你确保接收到的数据是正确的类型。

你还可以指定props是否是必需的,就像是你在信封上写着"必须打开",这样别人在使用你的组件时就必须传递这个props,否则会出现警告。

如果你给props设置了默认值,就像是在信封里放了一张字条,如果别人没有传递这个props,那么组件就会使用默认值。

当父组件给子组件传递了props,子组件就可以在自己的代码中使用这些props了,就像是打开了你传递的信封,取出里面的信息。你可以根据需要对这些props进行处理和计算,就像是读取信中的内容并进行一些操作。

假设在App组件的框架下,里面有众多的组件,其中A组件的数据和B组件如何进行交互呢?

答案:组件通信

1.组件通信方式1-props

若父传子 :属性值是非函数

如图:左边是父组件,右边是子组件


若 **子传父**:属性值是**函数**。

子传父:

  1. 接受子子组件传来的东西需要提前定义一个方法getToy
  2. 把getToy传给子组件
  3. 子那边要照样接收
  4. 直接使用父传来的,记得要加参数

Child.vue子组件代码:

javascript 复制代码
<template>
  <div class="child">
    <h3>子组件</h3>
		<h4>玩具:{{ toy }}</h4>
		<h4>父给的车:{{ car }}</h4>
		<button @click="sendToy(toy)">把玩具给父亲</button>
  </div>
</template>

<script setup lang="ts" name="Child">
	import {ref} from 'vue'
	// 数据
	let toy = ref('奥特曼')
	// 声明接收props
	defineProps(['car','sendToy'])
</script>

<style scoped>
	.child{
		background-color: skyblue;
		padding: 10px;
		box-shadow: 0 0 10px black;
		border-radius: 10px;
	}
</style>

Father.vue父组件代码

javascript 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
		<h4>汽车:{{ car }}</h4>
		<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
		<Child :car="car" :sendToy="getToy"/>
  </div>
</template>

<script setup lang="ts" name="Father">
	import Child from './Child.vue'
	import {ref} from 'vue'
	// 数据
	let car = ref('奔驰')
	let toy = ref('')
	// 方法
	function getToy(value:string){
		toy.value = value
	}
</script>

<style scoped>
	.father{
		background-color:rgb(165, 164, 164);
		padding: 20px;
		border-radius: 10px;
	}
</style>

补充:

v-show指v的是如果不点击按钮,就没有参数接受,就不会显示信息,否则则显示出来

2.组件通信方式2-自定义事件

自定义事件的概念:

当我们在Vue 3中需要让组件之间进行通信时,可以使用自定义事件。可以把自定义事件想象成人与人之间的交流,就像你和朋友之间通过说话来传递信息一样。

在Vue 3中,我们可以在一个组件中触发自定义事件,就像你向朋友说出一句话一样。你可以使用$emit方法来触发事件,并传递一些数据作为事件的参数。

而在另一个组件中,你可以监听并响应这个自定义事件,就像是朋友听到你的话后做出回应。你可以使用$on方法来监听事件,并在事件触发时执行相应的逻辑。

通过自定义事件,不同的组件可以进行灵活的交流和信息传递,就像是人们通过说话来相互沟通。这样就可以实现组件之间的解耦,让它们能够独立地进行通信。

概述:自定义事件常用于:子 => 父。

  1. 给子组件绑定了一个send-toy事件,只要点击就会调用saveToy,这就是自定义事件
  2. 如何触发send-toy事件呢?在子组件defineEmits声明中放入该事件
  3. 然后只要调用emit('send-toy')就可以触发了

Child.vue子组件代码:

javascript 复制代码
<template>
  <div class="child">
    <h3>子组件</h3>
		<h4>玩具:{{ toy }}</h4>
		<button @click="emit('send-toy',toy)">测试</button>
  </div>
</template>

<script setup lang="ts" name="Child">
	import { ref } from "vue";
	// 数据
	let toy = ref('奥特曼')
	// 声明事件
	const emit =  defineEmits(['send-toy'])
</script>

<style scoped>
	.child{
		margin-top: 10px;
		background-color: rgb(76, 209, 76);
		padding: 10px;
		box-shadow: 0 0 10px black;
		border-radius: 10px;
	}
</style>

Father.vue父组件代码:

javascript 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
		<h4 v-show="toy">子给的玩具:{{ toy }}</h4>
		<!-- 给子组件Child绑定事件 -->
    <Child @send-toy="saveToy"/>
  </div>
</template>

<script setup lang="ts" name="Father">
  import Child from './Child.vue'
	import { ref } from "vue";
	// 数据
	let toy = ref('')
	// 用于保存传递过来的玩具
	function saveToy(value:string){
		console.log('saveToy',value)
		toy.value = value
	}
</script>

<style scoped>
	.father{
		background-color:rgb(165, 164, 164);
		padding: 20px;
    border-radius: 10px;
	}
	.father button{
		margin-right: 5px;
	}
</style>

3.组件通信方式3-mitt

mitt的概念:

"Mitt" 是一个小而灵活的JavaScript库,用于在应用程序中处理事件的订阅和发布。可以把它想象成一个事件调度中心,就像是一个小管家,帮助不同的组件之间进行信息传递和交流。

当我们需要在应用程序中的不同部分之间传递消息时,可以使用 "Mitt" 来管理这些消息。它提供了一种简单的方式来订阅事件和触发事件。

假设你有几个组件,它们需要相互通信。你可以创建一个 "Mitt" 的实例,就像是雇佣了一个小管家。然后,你可以让组件们通过 "Mitt" 的实例来订阅事件,就像是告诉小管家:"如果有人说了某个事件,告诉我一声"。

当某个组件需要发送一个事件时,它可以通过 "Mitt" 的实例来触发该事件,就像是对小管家说:"有人说了某个事件,快去告诉其他组件"。

然后,其他组件就会收到这个事件,并可以根据需要做出响应,就像是收到小管家传递的消息后采取相应的行动。

"Mitt" 的好处在于它的简洁性和灵活性。它不依赖于任何特定的框架或库,可以在各种环境中使用。它是一个轻量级的解决方案,但非常实用,可以帮助你构建松散耦合的应用程序,让组件之间的通信更加方便和可靠。

通过mitt可以任意组件传递数据

比如如下的A组件通过绑定emitter,然后B组件触发emitter就可以获得A组件数据,爽完。

$event.target

event是触发对象事件,target是发生三个事件的本体

双向绑定:页面和控制台绑定,即在那面修改信息,另外也会发生变化

概述:与消息订阅与发布(`pubsub`)功能类似,可以实现任意组件间通信。
1.安装mitt

javascript 复制代码
npm i mitt

2.新建文件:src\utils\emitter.ts

emitter.ts文件代码:

javascript 复制代码
// 引入mitt
import mitt from 'mitt'

// 调用mitt得到emitter,emitter能:绑定事件、触发事件
const emitter = mitt()



// 暴露emitter
export default emitter

3.接收数据的组件中:绑定事件、同时在销毁前解绑事件


4.组件通信方式4-v-model (重点)

v-model的概念:

当我们在构建一个交互性的网页或应用程序时,很常见的需求是让用户能够输入数据并与之进行交互。Vue中的 v-model 就是为了解决这个需求而设计的。

想象一下你有一个输入框,用户可以在里面输入文本。你希望能够获取用户输入的值,并将其保存到Vue实例中的一个数据属性中,以便后续使用。同时,你也希望当你在Vue实例中修改了这个数据属性的值时,输入框中的内容也能够自动更新。

这就是 v-model 的作用啦!它是Vue中的一个特殊指令,让你可以将输入框和Vue实例中的数据属性绑定在一起,实现双向的数据绑定。

当你在输入框中输入文本时,v-model 会自动将输入的值保存到Vue实例中的数据属性中。而当你在Vue实例中修改了这个数据属性的值时,v-model 会自动将最新的值显示在输入框中。

这就像是你和Vue实例之间建立了一条数据的通道:你可以通过输入框向Vue实例发送数据,同时也可以通过修改Vue实例中的数据属性来控制输入框的内容。

需要注意的是,v-model 并不仅限于输入框,还可以用于复选框、单选按钮等表单元素,甚至是自定义的组件。

4.1 v-model用在html标签上

1.双向绑定:控制台的信息能显示在页面上,同时哪边被修改了都可以同步。

2.控制台数据的信息呈现在页面上

3.在页面修改信息,控制台数据同步信息

这里是程序员要写的v-model的代码:

javascript 复制代码
<input type="text" v-model="username">

其实这段代码的本质是:

javascript 复制代码
<input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value">

底层原理是 动态的value值和input事件

这两段代码是等价的

补充:

为什么报警告呢?

输入担心不是html输入类型的元素。所有要<HTMLInputElement>来断言告诉它不用担心。


4.2. v-model用在组件标签上

我们先写一个组件:

该组件的作用是改变输入框的样式。

javascript 复制代码
<template>
  <input 
    
  >
  <br>
  <input 
   
  >
</template>

<script setup lang="ts" name="MyInput">
  
</script>

<style scoped>
  input {
    border: 2px solid black;
    background-image: linear-gradient(45deg,red,yellow,green);
    height: 30px;
    font-size: 20px;
    color: white;
  }
</style>

然后在father.vue组件增添代码:

javascript 复制代码
 <MyInput v-model="username"/>

这段代码的本质:

javascript 复制代码
<MyInput :modelValue="username" @update:modelValue="username = $event"/>

:modelvalue传过来"username",实现控制台数据呈现到页面上

@update:modelValue只是事件名,它绑定username这个事件

然后在MyInput.vue组件上修改:

1.用defineProps把modelvalue名接收了

2.呈现在input输入框中

上面两步是把控制台数据呈现到页面。

  1. 用defineEmits把input事件里的update:modelValue接收了

4.同理,把它用在输入框中。

上面两步代码是在页面上修改数据时,也可以绑定控制台数据

其实MyInput.vue类似UI库里面的组件,我这么写是为了解释<MyInput v-model="username"/>底层逻辑的实现,实际开发中,直接写<MyInput v-model="username"/>就好了。

补充:

$event到底是啥? 啥时候能.target?

对于原生事件,$event就是事件对象 =====>能.target

对于自定义事件,$event就是触发事件时,所传递的数据 ==>不能target

MyInput.vue代码:

javascript 复制代码
<template>
  <input 
    type="text" 
    :value="modelValue"
    @input="emit('update:modelValue',(<HTMLInputElement>$event.target).value)"

  >
</template>

<script setup lang="ts" name="MyInput">
defineProps(['modelValue'])
  const emit = defineEmits(['update:modelValue'])
</script>

<style scoped>
  input {
    border: 2px solid black;
    background-image: linear-gradient(45deg,red,yellow,green);
    height: 30px;
    font-size: 20px;
    color: white;
  }
</style>

Father.vue文件代码:

javascript 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
    
    <!-- v-model用在html标签上 
     1.程序员写的代码  
    <input type="text" v-model="username">

     1.等价于下面这段代码
    <input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value">  -->

   <!-- v-model用在组件标签上 
      2.程序员写的代码     
  <MyInput v-model="username"/>
      2.等价于下面这段代码
  <MyInput :modelValue="username" @update:modelValue="username = $event"/>  -->

  </div>
</template>

<script setup lang="ts" name="Father">
	import { ref } from "vue";
  import MyInput from './MyInput.vue'
  // 数据
  let username = ref('zhansgan')
</script>

<style scoped>
.father {
  padding: 20px;
  background-color: rgb(165, 164, 164);
  border-radius: 10px;
}
</style>

4.3v-model的细节

javascript 复制代码
<!-- 也可以更换value,例如改成abc-->
<MyInput v-model:ming="userName"/>

<!-- 上面代码的本质如下 -->
<MyInput :ming="uerName" @update:ming="userName = $event"/>

MyInput.vue文件中代码:

javascript 复制代码
<template>
  <input 
    type="text" 
    :value="modelValue"
    @input="emit('update:ming',(<HTMLInputElement>$event.target).value)"

  >
</template>ming

<script setup lang="ts" name="MyInput">
defineProps(['ming'])
  const emit = defineEmits(['update:ming'])
</script>

<style scoped>
  input {
    border: 2px solid black;
    background-image: linear-gradient(45deg,red,yellow,green);
    height: 30px;
    font-size: 20px;
    color: white;
  }
</style>

如果value可以更换,那么就可以在组件标签上多次使用v-model

比如:

javascript 复制代码
<MyInput v-model:ming="userName" v-model:mima="password/>
相关推荐
weixin_382395232 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__2 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.3 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~4 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华4 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子6 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅7 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni7 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学8 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端