当前位置: 首页 > news >正文

前端框架Vue3(四)——组件通信及其他API

组件通信

组件关系传递方式
父传子1. props2. v-model3. $refs4. 默认插槽、具名插槽
子传父1.props2.自定义事件3.v-model4.parent5.作用域插槽
祖传孙、孙传祖1.$attrs2.provideinject
兄弟间、任意组件间1.mitt2.pinia

【props】

概述:props是使用频率最高的一种通信方式,常用与:父<=>子

  • 父传子:属性值是非函数
  • 子传父:属性值是函数
    父组件:
<template>
<div class="father">
<h3>父组件,</h3>
<h4>我的车:{{car}}</h4>
<h4>儿子给的玩具:{{toy}}</h4>
<Child car="car" getToy="getToy"/>
</div>
</template>
<script setup lang="ts"name="Father">
import Child from './Child.vue
import ref from "vue";
//数据
const car=ref('奔驰')
const 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>
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{ toy }}</h4>
<h5>父给的车:{{ car }}</h5>
<button @click="send">把玩具交给父亲</button>
</div>
</template>
<script setup lang="ts" name="Child">import { ref } from 'vue';const toy = ref('奥特曼')defineProps(['car','sendToy'])</script>
<style scoped>
.child{
background-color:skyblue;
padding:10px;
box-shadow:00 10px black;
border-radius:10px;
}
</style>

【custom-event】

<template><div class="father"><h3>父组件</h3><h4 v-show="toy">子给的玩具:{{ toy }}</h4><!--给子组件Child绑定事件  --><Child @send-toy="getToy" /></div>
</template><script setup lang="ts" name="Father">
import { ref } from 'vue';
import Child from './Children.vue';
const toy = ref('奥特曼');
// 接收子组件传来的 toy
function getToy(value:string){
console.log('父',value)
toy.value = value
}
</script>
<template>
<div class="child">
<h3>子组件</h3>
<h4>玩具:{{ toy }}</h4>
<button @click="emit('send-toy',toy)">点击</button>
</div>
</template>
<script setup lang="ts" name="ChildEvent">
import { ref } from 'vue'
const toy = ref('奥特曼');
const emit=defineEmits(['send-toy']);
</script>
<style scoped>
.child{
background-color:skyblue;
padding:10px;
box-shadow:00 10px black;
border-radius:10px;
}
</style>

【mitt】

<template><div class="child2"><h3>子组件2</h3><h4>电脑:{{ computer }}</h4><h5>哥哥给的玩具:{{ toy }}</h5></div>
</template><script setup lang="ts" name="Child2">
import emitter from '@/tools/emitter'
import { onUnmounted, ref } from 'vue'const computer = ref('小米')
const toy = ref('')// 给emitter绑定事件
emitter.on('send-toy', (value:unknown) => {if (typeof value === 'string') {toy.value = value}
})onUnmounted(() => {emitter.off('send-toy')
})
</script>
<template>
<div class="child1">
<h3>子组件1</h3>
<h4>玩具:{{ toy }}</h4>
<button @click="emitter.emit('send-toy',toy)">玩具给弟弟</button>
</div>
</template>
<script setup lang="ts" name='Child1'>
import emitter from '@/tools/emitter';
import { ref } from 'vue'const toy=ref('奥特曼')
</script>

【v-model】

<template><div class="father"><h3>父组件</h3><h4>{{ username }}</h4><!-- v-model用在html标签上 --><!-- <input type="text" v-model="username"> --><!-- <input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value"> --><!-- v-model用在组件标签上 --><HISTInput v-model="username"></HISTInput><!--  <HISTInput:modelValue="username"@update:modelValue="username=$event"></HISTInput> --></div>
</template>
<template><input type="text":value="modelValue"@input="emit('update:modelValue', (<HTMLInputElement>$event.target).value)">
</template><script setup lang="ts" name="HISTInput">
defineProps(['modelValue'])
const emit=defineEmits(['update:modelValue'])
</script>

【$attrs】

  1. 概述:$attrs用于实现当前组件的父组件,向当前组件的子组件通信**(祖一孙)**。
  2. 具体说明:$attrs是一个对象,包含所有父组件传入的标签属性。

注意:$attrs会自动排除props中声明的属性(可以认为声明过的props被子组件自己“消费”了)

<template><div></div>
</template><script setup lang="ts" name="GrandChild"></script><style lang="scss" scoped></style>
<template><div class="Child"><h3>孙组件</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>]c:{{ c }}</h4><h4>d:{{ d }}</h4><h4>x:{{ x }}</h4><h4>y:{{ y }}</h4><h4>z:{{ z }}</h4><button @click="updateA(6)">点我加6</button><GrandChild v-bind="$attrs" /></div>
</template><script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue';
defineProps(['a','b','c','d','x','y','z','updateA'])
</script><style lang="scss" scoped></style>
<template><div class="father"><h3>父组件</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>c:{{ c }}</h4><h4>d:{{ d }}</h4><Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/></div>
</template><script setup lang="ts" name="Father">
import Child from './ChildPractice.vue'
import { ref } from 'vue'const a=ref(1)
const b=ref(2)
const c=ref(3)
const d=ref(4)
function updateA(value:number){a.value=value
}
</script><style lang="scss" scoped></style>

refs、refs、refsparent】

  1. 概述:
    • $refs用于:父→子。
    • $parent用于:子一父。
  2. 原理如下:
属性说明
$refs值为对象,包含所有被ref属性标识的D0M元素或组件实例。
$parent值为对象,当前组件的父组件实例对象。
<template><div class="father"><h2>父组件</h2><h4>房产:{{ house }}</h4><button @click="changeToy">修改Child1的玩具</button><button @click="changeComputer">修改Child1的玩具</button><button @click="getAllChild($refs)">获取所有的子组件实例对象</button><Child1 ref="c1"></Child1><Child2></Child2></div>
</template><script setup lang="ts" name="FatherPractice">
import { ref } from 'vue';
import Child1 from './Child1Practice.vue';
import Child2 from './Child2Practice.vue';//注意点:当访问obj.c的时候,底层会自动读取value属性,因为c是在obj这个对象中的
/*let obj= reactive({
a:1,
b:2,
c:ref(3)
})
let x =ref(4)
console.log(obj.a)
console.log(obj.b)
console.log(obj.c)
console.log(x)*/
const house = ref(4);
const c1=ref()
function changeToy() {c1.value.a('小牛牛')
}
function changeComputer() {c1.value.b('redmi')
}
function getAllChild(refs:any) {for (const key in refs) {refs[key].b+=3}
}
defineExpose({house
})
</script><style scoped></style>
<template><div class="child1-practice"><h3>子组件1</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><button @click="minusHouse($parent)">干掉父亲的一套房产</button></div>
</template><script setup lang="ts" name="Child1Practice">
import { ref } from 'vue'
const a = ref(1)
const b = ref(2)
defineExpose({a,b
})function minusHouse (parent:any) {parent.house-=1
}
</script><style scoped></style>
<template><div class="child2-practice"><h2>子组件2</h2><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4></div>
</template><script setup lang="ts" name="Child2Practice">
import { ref } from 'vue';
const a = ref(1)
const b = ref(2)
</script><style scoped></style>

【provide、inject】

  1. 概述:实现祖孙组件直接通信
  2. 具体使用
    • 在祖先组件中通过provide配置向后代组件提供数据
    • 在后代组件中通过inject配置来声明接收数据
<template><div class="Child"><h3>孙组件</h3><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>]c:{{ c }}</h4><h4>d:{{ d }}</h4><h4>x:{{ x }}</h4><h4>y:{{ y }}</h4><h4>z:{{ z }}</h4><button @click="updateA(6)">点我加6</button><GrandChild v-bind="$attrs" /></div>
</template><script setup lang="ts" name="Child">
import GrandChild from './GrandChild.vue';
defineProps(['a','b','c','d','x','y','z','updateA'])
</script><style lang="scss" scoped></style>
<template><div class="father"><h3>父组件</h3><h4>银子:{{ money }}</h4><h4>车子:{{ car.name }},价值:{{ car.price }}</h4><Child /></div>
</template><script setup lang="ts" name="Father">
import { provide, reactive, ref } from 'vue'
import Child from './ChildPractice.vue'
const money=ref(1000)
const car=reactive({name:'保时捷',price:100000
})
function changeMoney(value:number){money.value-=value
}
// 向后代提供数据
provide('moneyContext',{money:money.value,changeMoney})
provide('car',car)
</script><style lang="scss" scoped></style>
<template><div class="grand-child"><h3>孙组件</h3><h4>银子:{{money}}</h4><h4>车子:{{ car.brand }},价值{{car.price}}万元</h4><button @click="updateMoney(6)">花钱</button></div>
</template><script setup lang="ts" name="GrandChild">import { inject } from 'vue';const {money,updateMoney}=inject('moneyContext',{money:0,updateMoney:(_:number)=>{}})const car=inject('car',{brand:'未知',price:1000})
</script><style lang="scss" scoped></style>

【slot】

<template><div class="father-practice"><h3>父组件</h3><div class="content"><Category><template v-slot:s2><ul><li v-for="item in games" :key="item.id">{{ item.name }}</li></ul></template><template v-slot:s1><h2>热门游戏列表</h2></template></Category><Category><template v-slot:s2><img :src=imgUrl alt=""></template><template v-slot:s1><h2>今日美食城市</h2></template></Category><Category><template v-slot:s1><video :src="videoUrl"></video></template><template v-slot:s2><h2>近日影视推荐</h2></template></Category></div></div>
</template><script setup lang="ts" name="father-practice">
import { reactive, ref } from 'vue';
import Category from './CategoryPractice.vue';
const games=reactive([{id:1,name:'英雄联盟'},{id:2,name:'王者荣耀'},{id:3,name:'和平精英'},{id:4,name:'穿越火线'},
])
const imgUrl=ref('https://z1.ax1x.com/2023/11/19/piNxLo4.jpg')
const videoUrl=ref('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')</script><style scoped>
.father{
background-color:rgb(165,164,164);
padding:20px;
border-radius:10px;
}.content{
display:flex;
justify-content: space-evenly;
}
</style>
<template><div class="category">
<slot names="s1">默认内容1</slot>
<slot name="s2">默认内容2</slot>
</div>
</template><script setup lang="ts" name="CategoryPractice"></script><style scoped>
.category-practice {
background-color: skyblue;
}</style>

其他API

【shallowRef与shallowReactive】

shallowRef
  1. 作用:创建一个响应式数据,但只对顶层属性进行响应式处理。
  2. 用法:
    let =myVar shallowRef(initialValue);
  3. 特点:只跟踪引用值的变化,不关心值内部的属性变化。
shallowReactive
  1. 作用:创建一个浅层响应式对象,只会使对象的最顶层属性变成响应式的,对象内部的嵌套属性则不会变成
    响应式的
  2. 用法:
    const =myobj shallowReactive({...})
  3. 特点:对象的顶层属性是响应式的,但嵌套对象的属性不是。

通过使用shallowRef()shallowReactive()来绕开深度响应。浅层式API创建的状态只在其顶层是
响应式的对所有深层的对象不会做任何处理,避免了对每一个内部属性做响应式所带来的性能成本,
这使得属性的访问变得更快,可提升性能。

<template><div class="App">
<h2>求和:{{ sum }}</h2>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>车:{{ car.brand }}</h2>
<button @click="changeSum">sum+1</button>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
<button @click="changeBrand">修改品牌</button>
<button @click="changeColor">修改颜色</button>
<button @click="changeEngine">修改发动机</button>
<button @click="changeCar">修改整个车</button>
</div>
</template><script setup lang="ts" name="App">
import {  ref, shallowRef,shallowReactive } from 'vue'
const sum=shallowRef(0)
const person=ref({name:'张三',age:18})
// const car =reactive({
// brand:'奔驰',
// options:{
// color:'红色',
// engine:''
// }
// })
const car =shallowReactive({
brand:'奔驰',
options:{
color:'红色',
engine:''
}
})
function changeSum(){sum.value+=1
}
function changeName (){person.value.name='李四'
}function changeAge (){person.value.age =60
}function changePerson (){person.value={name:'王五',age:19}
}
function changeBrand(){
car.brand='宝马'
}
function changeColor(){
car.options.color='紫色'
}
function changeEngine(){
car.options.engine ='V12'
}
function changeCar(){
Object.assign(car)
}
</script><style scoped>
.App{background-color: #ddd;border-radius: 10px;box-shadow: 0 0 10px;padding: 10px;
}
button{margin:0 5px;
}
</style>

【readonly与shallowReadonly】

readonly
  1. 作用:用于创建一个对象的深只读副本。
  2. 用法:
    const original reactive({...}) const readOnlyCopy= readonly(original);
  3. 特点
    • 对象的所有嵌套属性都将变为只读。
    • 任何尝试修改这个对象的操作都会被阻止(在开发模式下,还会在控制台中发出警告)。
  4. 应用场景:
    • 创建不可变的状态快照。
    • 保护全局状态或配置不被修改。
shallowReadonly
  1. 作用:与readonly类似,但只作用于对象的顶层属性。
  2. 用法:
    const original reactive({...}) const shallowReadOnlyCopy shallowReadonly(original);
  3. 特点:
    • 只将对象的顶层属性设置为只读,对象内部的嵌套属性仍然是可变的。
    • 适用于只需保护对象顶层属性的场景。
<template><div class="app">
<h2>当前sum求和为:{{sum}}</h2>
<h2>当前sum2求和为:{{sum2}}</h2>
<h2>当前汽车为:{{car}}</h2>
<h2>当前汽车为:{{car2}}</h2>
<button @click="changeSum">sum1+1</button>
<button @click="changeSum2">sum2+1</button>
<button @click="changeBrand">修改品牌</button>
<button @click="changeBrand2">修改品牌</button>
<button @click="changeColor">修改颜色</button>
<button @click="changePrice">修改价格</button>
<button @click="changeColor2">修改颜色</button>
<button @click="changePrice2">修改价格</button>
</div>
</template><script setup lang="ts" name="App">
import { reactive, readonly, ref, shallowReadonly } from 'vue'
const sum = ref(0)
const sum2=readonly(()=>sum.value+1)
const car=reactive({brand:'audi',options:{color:'red',price:100000}
})
function changeSum(){sum.value+=1
}
const car2=shallowReadonly(car)
function changeSum2(){sum2.value+=1
}
function changeColor(){car.options.color='blue'
}
function changePrice(){car.options.price+=10
}
function changeBrand(){car.brand='hongqi'
}
function changeBrand2(){car2.brand='hongqi'
}
function changeColor2(){car.options.color='blue'
}
function changePrice2(){car.options.price+=10
}
</script><style scoped>
.app{background-color: #ddd;border-radius: 10px;box-shadow: 0 0 10px;padding: 10px;
}
button{margin:0 5px;
}
</style>

【toRaw与markRaw】

toRaw
  1. 作用:用于获取一个响应式对象的原始对象,toRaw返回的对象不再是响应式的,不会触发视图更新

官网描述:这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方
法。不建议保存对原始对象的持久引用,请谨慎使用。
何时使用?一一在需要将响应式对象传递给非Vue的库或外部系统时,使用toRaw可以确保它们收
到的是普通对象

  1. 具体编码:
import {reactive,toRaw,markRaw,isReactive} from "vue";
//toRaw 
//响应式对象
let person =reactive({name:tony',age:18))
//原始对象
let rawPerson =toRaw(person)
//markRaw 
let citysd markRaw([
{id:'asdda01',name:'北京'}{id:'asdda02',name:'上海'}{id:'asdda3',name:'天津'}{"name":"重庆","id":"asdda04"}
])
//根据原始对象citys去创建响应式对象citys2--创建失败,因为citys被markRaw标记了
let citys2 =reactive(citys)
console.log(isReactive(person))
console.log(isReactive(rawPerson))
console.log(isReactive(citys))
console.log(isReactive(citys2))
markRaw
  1. 作用:标记一个对象,使其永远不会变成响应式的。

例如使用mockjs时,为了防止误把mockjs变为响应式对象,可以使用markRaw去标记mockjs

  1. 编码:
//markRaw 
let citys= markRaw([
{id:'asdda01',name:'北京'}{id:'asdda02',name:'上海'}{id:'asdda03',name:'天津'}{id:"asdda04",name:"重庆"}
])
//根据原始对象citys去创建响应式对象citys2--创建失败,因为citys被markRaw标记了
let citys2 =reactive(citys)
【customRef】

作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行逻辑控制。
实现防抖效果(useSumRef.ts):

import {customRef from "vue";
export default function(initValue:string,delay:number){
let msg= customRef((track,trigger)=>{
let timer:number
return{
get(){
track()//告诉Vue数据msg很重要,要对msg持续关注,一旦变化就更新
return initValue
},
set(value){
clearTimeout(timer)
timer =setTimeout(()=>
initValue =value
trigger()//通知Vue数据msg变化了
}delay);
}
}
})

【Teleport】

  • 什么是Teleport?一一Teleport是一种能够将我们的组件html结构移动到指定位置的技术。
<teleport to='body'>
<div class="modal" v-show="isShow">
<h2>我是一个弹窗</h2>
<p>我是弹窗中的一些内容</p>
<button @click="isShow=false">关闭弹窗</button>
</div>
</teleport>

【Suspense】

  • 等待异步组件时渲染一些额外内容,让应用有更好的用户体验
  • 使用步骤:
    • 异步引入组件
    • 使用Suspense包裹组件,并配置好defaultfallback
import defineAsyncComponent,Suspense from "vue";
const Child =defineAsyncComponent(()=>import('./Child.vue'))
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>

【全局API转移到应用对象】

  • app.component
  • app.config
  • app.directive
  • app.mount
  • app.unmount
  • app.use

【其他】

  • 过渡类名v-enter修改为v-enter-from、过渡类名v-leave修改为v-leave-from
  • keyCode作为v-on修饰符的支持。
  • v-model指令在组件上的使用已经被重新设计,替换掉了v-bind.sync
  • v-ifv-for在同一个元素身上使用时的优先级发生了变化。
  • 移除了$on$off$once实例方法。
  • 移除了过滤器filter
  • 移除了$children实例propert
http://www.dtcms.com/a/307415.html

相关文章:

  • 前端开发(HTML,CSS,VUE,JS)从入门到精通!第一天(HTML5)
  • Java WEB技术-序列化和反序列化认识(SpringBoot的Jackson序列化行为?如何打破序列化过程的驼峰规则?如何解决学序列化循环引用问题?)
  • Amazon RDS for MySQL成本优化:RDS缓存降本实战
  • 三坐标测量机路径规划与补偿技术:如何用算法看见微米级误差?
  • 抖音集团基于Paimon的流式数据湖应用实践
  • 常见的中间件漏洞如tomcat,weblogic,jboss,apache靶场攻略
  • wpf之ContentPresenter
  • 《Java 程序设计》第 14 章 - JavaFX 基础
  • windows服务器 maven 配置环境变量,验证maven环境变量是否配置成功
  • AI在法律合同内容比对的应用实例
  • 使用 Elasticsearch 和 AI 构建智能重复项检测
  • 接口基础-智能家居控制系统
  • 家政小程序系统开发:满足多元家政需求
  • AI 类型的 IDE
  • 直播小程序 app 系统架构分析
  • FastMCP本地构建Server和Clinet交互
  • PyTorch深度学习快速入门学习总结(三)
  • selenium+pyautogui实现页面鼠标自动化控制
  • 学习Python中Selenium模块的基本用法(4:WebDriver常用属性及函数)
  • RabbitMQ的特点和消息可靠性保障
  • RabbitMQ 队列配置设置 RabbitMQ 消息监听器的并发消费者数量java
  • [Linux入门] Linux防火墙技术入门
  • rabbitmq的安装和使用-windows版本
  • 远程仓库地址发生变化
  • RabbitMQ安装与介绍
  • 推客小程序商业模型设计:合规分佣体系×盈利模式×LTV提升策略
  • Cesium 快速入门(七)材质详解
  • 一键打包所有docker镜像的脚本
  • 暑期算法训练.11
  • 【09】大恒相机SDK C#开发 ——库函数 IntPtr ConvertToRGB24详细解释 及 示例