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/>
相关推荐
web1350858863516 分钟前
前端node.js
前端·node.js·vim
m0_5127446417 分钟前
极客大挑战2024-web-wp(详细)
android·前端
若川26 分钟前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点41 分钟前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿1 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
m0_748256563 小时前
如何解决前端发送数据到后端为空的问题
前端
请叫我飞哥@3 小时前
HTML5适配手机
前端·html·html5
@解忧杂货铺5 小时前
前端vue如何实现数字框中通过鼠标滚轮上下滚动增减数字
前端·javascript·vue.js
F-2H7 小时前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++