我天,现在的00后差距都这么大了吗?前两天跟一个初中同学打电话聊天,无意间就聊到一个同学已经生娃了。我当时反应这么早吗,这才多少岁啊,就开始结婚生娃?哎!突然有点伤感了,我这么大还没牵过女孩子的手呢。有的人才20岁出头就已经过上了一家三口的日子,而我20都好几了,还在上着大学,敲着带电脑温度的代码。不过,现在还是好好的敲代码吧!家里没有money,得先赚点彩礼钱!不过现在敲的代码中还蕴藏了不少的奥秘呢,今天就从vue的父子组件通信中学习学习孩子的教育吧,为以后教娃做点准备!
vue中的父子组件通信
Vue.js 的核心优势之一在于它的组件化设计思想。每个组件都可以被视为一个独立的单元,它们通过数据和事件进行交互。在我们的日常开发过程中,经常需要在不同级别的组件之间共享数据或触发行为,例如父组件向子组件传递数据,或者子组件向父组件进行通信。
父组件向子组件传递数据
这个情况我们还是比较常见也比较容易接受的,只需要父组件把需要传递的东西给子组件就可以了。就好像我在读大学的时候父亲只用按时把生活费通过微信或者支付宝打给我们,我们点击收款就行了,至于我们花钱干啥就他就管不到!父组件给子组件传递数据也是这样,通过props把该给的数据传给子组件,子组件再接收下来就行了。具体的操作如下:
vue
// parent.vue
<template>
<child :list="list"/>
</template>
<script setup>
const list = ref(['html', 'css'])
</script>
---------------------------------------------------
// child.vue
<script setup>
const props = defineProps({
list:{
type:Array,
default:() => []
}
})
</script>
父组件将list传递给了child <child :list="list"/>
,然后子组件就进行接收,使用defineProps方法接收传递过来的名为list的参数,指定接收的数据类型以及默认接收的数据。如果父组件传递过来的不是数组类型的话,那就会发出警告并使用默认的值。如果我们不想使用默认值的话,就要在对象添加个属性 required: true
。如:
xml
<script setup>
const props = defineProps({
list: {
type: Array,
required: true
}
});
</script>
这样,如果父组件没有传递正确的数组类型,Vue 会抛出一个错误,并且不会使用默认值。所以说以后我们在给娃生活费的时候,还是尽量不要给现金,不然娃用不了,会挨饿的!
这就是父组件向子组件传递数据的方法,这个方法还是比较好用的,也是较为通用的方法。
当然,父组件向子组件传递数据还有一种方法 ,就是使用provide inject。
这种方法不仅仅局限于父亲给儿子money了,还可以表示爷爷给孙子money ,甚至是太太太太太太太爷爷!哈哈哈哈。不过确实,我们可能不能享受到太太太太太太太爷爷给我们零花钱,但是组件可以的!不过这样写代码不是故意的根本不会这样写!这个provide inject也很简单,直接父组件使用provide方法提供个数据,子组件用inject接收就可以了。具体的使用可以看我演示:
vue
// parent.vue
const list = ref(['html', 'css'])
provide('list',list.value)
------------------------------------
//child.vue
import { inject } from 'vue'
const list = inject('listSend')
但是provide
和 inject
不应该用于父子组件之间的通信,因为props更好一点,而且如果组件树非常庞大时,可能会导致数据来源和依赖关系变得模糊。如果不当使用 provide
,可能会导致全局状态的污染,特别是在多个组件共享同一 provide
数据时。所以我们有更好的解决办法,如使用Vuex 。至于什么是vuex下一次再介绍,就先不在这里介绍了。
子组件向父组件传递信息
子组件向父组件传递信息就有好几种方法了,甚至我们可以同样的使用props传递,但是这种方法不被推荐,因为vue主张的是数据单向流动。而且如果多个子组件都直接修改同一个父组件的数据,就会导致状态不一致,难以追踪哪个子组件做了修改,从而增加调试的难度。所以我们一般使用下面这几种方法:
1. 使用发布订阅机制
这个看起来很高大上,但是其实也是挺高大上的。就是子组件可以通过 $emit
方法触发自定义事件,然后 父组件可以在使用子组件时监听这些事件。这个就相当于你的娃想要花钱买点其他的东西,比如说给女神买花,买早餐等,这时候就要跟老父亲说,我谈恋爱了,给女神干了啥啥,你看着整。所以还是通过例子来给大家看一下吧:
vue
parent.vue
<template>
<child @addMsg="handle"/> //
<div class="body">
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue';
import child from './child.vue'
const list = ref(['html', 'css'])
const handle = (aa) => { // 父组件订阅一个事件
list.value.push(aa)
}
</script>
------------------------------------------------------
child.vue
<template>
<div class="header">
<input type="text" v-model="newMsg">
<button @click="add" type="submit">确定</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
const newMsg = ref('')
const emits = defineEmits(['addMsg'])
const add = () => {
emits('addMsg',newMsg.value) // 发布事件,并且将输入的值与事件一并发出去
}
</script>
子组件发布一个addMsg事件,并且将值给发布出去const emits = defineEmits(['addMsg'])
,父组件就订阅这个事件<child @addMsg="handle"/>
,然后看着子组件干啥就行了。嗯,好有教学意义!我们要支持孩子们的想法,但是也要做好监督,毕竟孩子们还小。哈哈哈哈哈哈
2. 使用v-model绑定
其实这个就是发布订阅的优化,父组件通过v-model绑定属性传给子组件,子组件发布事件update通知父组件的事件更新。还是给大家看看这个怎么使用的吧!
vue
parent.vue
<template>
<Child v-model:list="list" />
<div class="body">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const list = ref(['html', 'css'])
</script>
---------------------------------------------
child.vue
<template>
<div class="header">
<input type="text" v-model="newMsg">
<button @click="add">确定</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
list: []
})
const newMsg = ref('')
const emits = defineEmits(['update:list'])
const add = () => {
const arr = props.list
arr.push(newMsg.value)
emits('update:list', arr)
}
</script>
这里其实就相当于把父组件与子组件的list双向绑定了,子组件里面的值发生修改了,父组件值也会发生改变。注意哦:defineEmits(['update:list'])这个update可不能变
3.通过ref获取到子组件的dom结构
这个方法就是通过ref获取到子组件的dom结构,子组件将该干的干完了,父组件直接坐享其成,获取到子组件中做好的数据显示出来就行了。具体的操作如下:
vue
parents.vue
<template>
<Child ref="childRef" />
<div class="body">
<ul>
<li v-for="item in childRef?.list">{{ item }}</li>
</ul>
</div>
</template>
<script setup>
import Child from './child.vue';
import { ref } from 'vue';
const childRef = ref(null)
</script>
-------------------------------------------------------------
child.vue
<template>
<div class="header">
<input type="text" v-model="newMsg">
<button @click="add">确定</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const newMsg = ref('')
const list = ref(['html', 'css'])
const add = () => {
list.value.push(newMsg.value)
}
defineExpose({ list })
</script>
我们通常可以使用ref获取到dom结构,但是我们不能直接获取组件的结构,我们可以使用defineExpose()方法主动暴露出list结构,这样父组件就可以得到子组件的list。但是这里涉及到一个生命周期的问题,就是父组件的挂载一定是在子组件挂载之后的。而父组件挂载后childRef就是我们刚开始的值null,
- {{ item }}
所以我们直接使用显示不出来效果的,我们可以直接使用es6的语法糖childRef?.list 这就表示如果childRef没有值就不读取后面的值。另外值得一题的是,list是响应式的,暴露出来的东西还是响应式的。
总结
- 确实哦,写代码不仅能提高我们的编程能力,还能提高我们的带娃能力。组件间的通信还是比较重要的,谁叫我们的页面是由一个又一个的页面组成呢。今天就主要介绍了一下父子组件间的通信,我们还会遇到兄弟组件间的通信,以及多级组件间的通信。这些组件的通信就有父子组件的通信有点不同,但是也是比较好理解的,下一次就给大家分享一下兄弟组件间怎么通信。晚安啦!