VUE(3)
一 组件通信
1 .props
(1)父传子
<Person :ftoy="ftoy"/> //父组件代码
defineProps(['ftoy']) //子组件用这个函数接受
(2)子传父,父要通过函数传递给子,子在修改父的数据,函数接收数据变化后,父亲那里的数据也发生变化
function getsontoy(value:string){
stoy.value=value
} //父亲拿到的函数的value就是子传递过来的数据
<button @click="sendtoy(toy)">点击给父发送子玩具</button> 这个函数传递参数就可以发送子组建的数据了,在父的value里面
2 自定义事件
@后面接自定义的事件,子元素接受后想要使用,需要emit(‘事件名字’,可填传入的值,在定义事件的地方可以接收)
<Person @send-toy="sendtoy"/> //名称自定,=后面跟的是函数,可以接收参数
const emit=defineEmits(['send-toy'])
<button @click="emit('send-toy',toy)">点击给父发送子玩具</button>
3 mitt
第一步安装mitt 终端输入 npm i mitt
第二步 创建mitt 的ts 文件方便引用
import mitt from 'mitt'
const emitter = mitt()
export default emitter
第三 mitt使用首先要导入,发送事件
<button @click="emitter.emit('send-toy',toy)">子传父的玩具用mitt形式:</button> //emitter.emit()相当于触发或者发射事件,同样可以传递value值
import emitter from '../utils/emitter';
第四 组件接收,同样先要导入,后绑定事件接受,这里需要注意是绑定完,需要在卸载的时候,把事件解绑,防止内存泄漏
emitter.on('send-toy',(value:any)=>{
mstoy.value=value
})
onUnmounted(()=>{
emitter.off('send-toy')
}) //解绑事件
4 $attrs通信
attrs是父组件传递的所有数据,传递的对象可以选择接收或者不接收,但是attrs会保留所有传递的数据。通过这个我们就可以实现,父传孙。传递的写法和之前相同,就在子组件里面写下
<GrandChild v-bind="$attrs">
就可以传递给孙组件所有的数,当然使用的时候需要接受,如果父亲传递一个函数,可以接受数据,数据传递给孙组件,孙组件使用函数给值可以做到给父组件传递值,更新数据
defineProps(['ftoy','a','b','updata'])
5 $refs $parent 通信
$refs用于 父传子而 $parent用于子传父,他们都可以得到所有的父对象和子对象,通过这总形式通信传递,想要在父里面修改子组件数据,或者反过来都需要在被修改数据的组件里面暴露出数据用defineExpose()
<button @click="changeAllBook($refs)">修改子组件的书籍数量</button> //父亲通过refs拿到所有子组件对象
function changeAllBook(refs:any){ //遍历所有子组件对象,给子组件修改数据
console.log(refs)
for (let key in refs){
refs[key].book += 1
}
}
$parent写法也是同理的,但是只能用于,子对父
6 provide和inject
可以实现跨层级组件(祖孙)间通信,不用借助子组件。
provide('state', state) //父传递数据
const state = inject('state') //孙接收数据
7 默认插槽
使用默认插槽的要写成双标签,标签里面可以写样式,数据,数据使用的是父组件定义的数据,但是写完内容后,需要在子组件里面写<slot>(这里可以定义默认内容没传入东西就会显示)</slot>
<Person @send-toy="sendtoy" title="游戏推荐">
<ul>
<li v-for="g in games" :key="g.id">
{{ g.game }}
</li>
</ul>
</Person> //父组件写的内容
<div class="cont">
<h2>{{ title }}</h2>
<slot>默认内容</slot> //子组件写的内容,如果父组件没有写样式,就会默认呈现slot标签里面写的内容
8 具名插槽
可以设置不同的插槽,随意放置位置,但是需要起名字,用v-slot:来命名,可以用#来简写,子组件用name来表示是那个插槽
<Person @send-toy="sendtoy" title="游戏推荐">
<template #s2>
<ul>
<li v-for="g in games" :key="g.id">
{{ g.game }}
</li>
</ul>
</template>
<template #s1>
<h2>游戏推荐</h2>
</template>
</Person> //父组件
<div class="cont">
<slot name="s1">默认内容1</slot>
<slot name="s2">默认内容2</slot>
</div> //子组件
9 作用域插槽
可以给指定的插槽传输数据,用的是v-slot:的形式,传过来的数据是一个对象的形式,使用作用域插槽也可以定义名字的
<div class="cont">
<slot name="s1">默认内容1</slot>
<slot name="s2" :games="games">默认内容2</slot>
</div> //子组件传给父组件数据,games
<template v-slot:s2="{games}">
<ul>
<li v-for="g in games" :key="g.id"> //如果这里不解构的话,v-for 里面 写的是 g in games.games
{{ g.game }}
</li>
</ul>
</template>
<template v-slot:s1>
<h2>游戏推荐</h2>
</template>
二 其他api
1 shallowRef
只能改变浅层次的值,一般用来看是否发生整体的数据修改。比如说
let person = shallowRef([
name:'张三
age:18
])
function changeSum (){fsum.value += 1}
function changeName (){(person.value.name =李四 } //这个地方就不能修改,他是 person.value.name 这里有层次超过一个就不可以
function changeAge (){person.value.age += 1}
function changePerson (){person.value = (name: 'tony ' , age:100]} //这里可以修改
2 shallowReative
它其实和shallowRef一样的,使用他们可以增强性能。
3 readonly
定义了readonly只能读取数据,不可以修改数据,可以对数据进行保护,比如说
let sum1=ref(0)
let sum2=readonly(sum1) 这里的sum2 只读取了sum1 的值,sum1的值变化,sum2 也变化,但是无法改变sum2的值
4 shallowReadly
它和readonly差不多,但是它只限制第一次层次的只读,比如说你修改它第二层次的数据是可以修改的,
5 toRaw
作用:用于获取一个响应式对象的原始对象,toRaw 返回的对象不再是响应式的,不会触发视图更新
官网描述:这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。不建议保存对原始对象的持久引用,请谨慎使用。
外部系统时何时使用?--在需要将响应式对象传递给非 Vue 的库可到的是普通对象使用 toRaw 可以确保它们收到的是普通对象
6 markRaf
标记永远不会变为响应式对象
7 customRef
自定义ref,get是数据被调用的时候执行这个函数,set是当数据被修改的时候执行这个函数
export default function (initValue: string, dalay: number) {
let timer: any
let msg = customRef((track, trigger) => {
return {
get() {
track() //告诉vue,你要对msg数据持续关注,一旦msg变化就要去更新
return initValue
},
set(value) {
clearTimeout(timer)
timer = setTimeout(() => {
initValue = value
trigger() //通知vue数据更新完毕了
}, dalay)
}
}
})
return { msg }
}
8 Teleport
一种能够将我们组件html结构移动到指定位置的技术
<teleport to='body’ > // 这里的to就可以定义这个盒子传送,以那个盒子为基点,比如说这里写的body它定位是以body来定位,会脱离父盒子的限制
<div class="modal” V-show="isShow"><h2>我是一个弹窗</h2>
<p>我是弹窗中的一些内容</p>
<button @click="isShow = false">关闭弹窗</button>
</div>
</teleport>
9 Suspense
如果子组件是包含异步任务的,父组件要用Suspense去包裹一个template标签,定义插槽为默认插槽就可以获得子组件了
import { Suspense } from 'vue';
<Suspense>
<template v-slot:default>
<Chlid/>
</template> //这个插槽异步任务完成才出现
<template v-slot:fallback>
正在加载中......
</template> //这个插槽异步任务没完成的时候出现
</Suspense>