《Vue3学习手记6》
组件通信
props
props 可以父传子,也可以子传父
1.父传子
子组件:
<template><div class="child"><h2>子组件</h2><h3>礼物:{{ gift }}</h3><h3 v-show="zichan">父亲给我的:{{zichan}}</h3><button @click="getRich">点我接收父亲的资产</button></div>
</template><script setup lang="ts" name="Child">
import {ref} from "vue"
const gift=ref("鲜花")
const zichan=ref("")// 1.2子组件接收参数
const props=defineProps(["rich"])function getRich(){zichan.value=props.rich.car
}
</script>
父组件:
<template><div class="father"><h2>父组件</h2><h3>资产:{{rich.car}}--{{ rich.money }}--{{ rich.house }}</h3><hr><Child :rich="rich"/> <!-- 1.1父组件给子组件传递 --> </div>
</template><script setup lang="ts" name="Father">
import Child from "@/pages/01_props/Child.vue"
import { ref,reactive } from "vue";
const rich=reactive({car:"劳斯莱斯",money:"1000w",house:"3栋房子",
})
</script>
2.子传父
子组件:
<template><div class="child"><h2>子组件</h2><h3>礼物:{{ gift }}</h3><button @click="send(gift)">点我将礼物传递给父亲</button></div>
</template><script setup lang="ts" name="Child">
import {ref} from "vue"
const gift=ref("鲜花")
// 2.3儿子接收函数
const props=defineProps(["sendGift"])// 2.4调用sendGift(),并将参数传递过去
function send(gift:string){props.sendGift(gift)
}
// 或者直接在模板中写:<button @click="sendGift(gift)">点我将礼物传递给父亲</button>
</script>
父组件:
<template><div class="father"><h2>父组件</h2><h3>资产:{{rich.car}}--{{ rich.money }}--{{ rich.house }}</h3><hr><!-- 2.5将儿子传递的参数呈现在页面上 --><h3 v-show="gift">儿子传递给我的礼物:{{gift}}</h3><Child:sendGift="getGift"/> <!-- 2.2将函数给儿子 --></div>
</template><script setup lang="ts" name="Father">
import Child from "@/pages/01_props/Child.vue"
import { ref,reactive } from "vue";
const rich=reactive({car:"劳斯莱斯",money:"1000w",house:"3栋房子",
})
// 2.6 参数呈现在页面上
const gift=ref("")
// 2.1子传父——父亲需要给孩子一个函数
function getGift(value:string){ //value是需要接受到的儿子给父亲的数据gift.value=value
}</script>
自定义事件
自定义事件 子传父
父组件接收数据(绑定事件),子组件提供数据(触发事件)
子组件:
<template><div class="child"><h3>子组件</h3><h3>礼物:{{ gift }}</h3><button @click="send(gift)">点我将礼物送给父亲</button> </div>
</template><script setup lang="ts" name="Child">import {ref} from "vue"const gift=ref("鲜花")// 3.接收自定义事件const emit=defineEmits(["get"])// 4.触发自定义事件function send(gift:string){emit("get",gift)}// 5.也可以写为:<button @click="emit("get",gift)">点我将礼物送给父亲</button>
</script>
父组件:
<template><div class="father"><h3>父组件</h3><h2>儿子传递给我的礼物:{{present}}</h2><!--1.绑定自定义事件:--><Child @get="getGift"/></div>
</template><script setup lang="ts" name="Father">
import Child from "@/pages/02_custom-event/Child.vue"
import {ref} from "vue"
const present=ref("")
// 2.方法function getGift(value:string){present.value=value}
</script>
mitt
与消息订阅与发布(pubsub
)功能类似,可以实现任意组件间通信。
1.安装:npm i mitt
2.src下新建utils文件夹,utils下新建emitter.ts文件
下面案例是实现兄弟组件通信 ,哥哥给弟弟传递数据
解析:哥哥传递数据(触发事件),弟弟接收数据(绑定事件)
弟弟组件:
<template><div class="child2"><h3>子组件2</h3><h2 v-show="toy">哥哥传递给我的玩具:{{ toy }}</h2></div>
</template><script setup lang="ts" name="Child2">
import emitter from "@/utils/emitter"
import {ref} from "vue"// 1.绑定事件并且使其呈现在页面
const toy=ref("")
emitter.on("getToy",(value:string)=>{ //value是接收到的哥哥传过来的参数toy.value=value //这行代码中的toy和哥哥传递的toy不一样
})
</script>
哥哥组件:
<template><div class="child1"><h3>子组件1</h3><h2>玩具:{{toy}}</h2><button @click="sendToy">点我将玩具给弟弟</button></div>
</template><script setup lang="ts" name="Child1">
import emitter from "@/utils/emitter"
import {ref} from "vue"
const toy=ref("乐高")// 2.触发事件
function sendToy(){emitter.emit("getToy",toy) //toy是传递的参数
}
</script>
v-model
表单组件双向绑定底层原理
v-model既可以子传父(@update:modelValue=“userName=$event”),也可以父传子(:modelValue=“userName”)
父组件:
<template><div class="father"><h3>父组件</h3><!-- 知识点一: --><!-- v-model用在html标签上 --><!-- <input type="text" v-model="userName">可以实现双向绑定 --><!-- v-model的底层原理:动态value值配合input事件 --><!-- <input type="text" :value="userName" @input="userName = (<HTMLInputElement>$event.target).value"> --><!-- v-model用在组件标签上 --><!-- 自己封装一个好看的组件 --><MyInput v-model="userName"/> <!-- 这样写并不能实现双向绑定 --><!-- 底层原理: --> <!-- 需要在MyInput里进行封装,才可以进行双向绑定 --><!-- <MyInput :modelValue="userName" @update:modelValue="userName=$event"/> --> <!-- 名字上规定的 --><!-- 12行代码和15行任选一个写,两者一个是简洁写法,一个是底层原理 --></div>
</template><script setup lang="ts" name="Father">import { ref } from "vue";import MyInput from './MyInput.vue'const userName=ref("zhangsan")
</script>
MyInput组件:
<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>
v-model修改名字
如果修改了,就可以在组件标签上多次使用v-model;例如下边的代码增加了一个密码表单
<!-- 知识点三:--><!-- 修改modelValue (如果修改了,就可以在组件标签上多次使用v-model)--><MyInput v-model:account="userName" v-model:psd="passWord"/> <!-- account代替了原来的modelValue -->
但是在MyInput组件中需要将modelValue替换为account和psd