vue3.5保证你看得明明白白

news/2025/1/20 12:30:34/文章来源:https://www.cnblogs.com/IwishIcould/p/18668565

子组件中设置默认属性

<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}</h3><h3>{{ userInfo }} </h3></div>
</template><script setup>
// 在<script setup>defineProps其实可以不用显示导入,因为编译器会自动处理
import {defineProps} from 'vue'
defineProps({total:{type:Number,default:10},userInfo:{type:Object,required: true,default:()=> {return {name: '罗峰[金角巨兽]',age: 100}}}
})

为啥解构失去响应式

解构会让基本数据类型失去响应式。引用数据类型则不会失去响应式。
为啥基本数据类型解构就会失去响应式呢?
回答:因为Vue3使用了Proxy作为响应式的底层实现,而基本数据类型不是可观察的,无法被Proxy拦截。

验证解构失去响应式

// 父组件
<template><div class="art-page"><button @click="changeHandler">改变</button><child :total="total" :userInfo="userInfo"></child></div>
</template><script setup>
import child from '@/components/child.vue'
import { ref,reactive } from 'vue';
let total=ref(100)
let userInfo =reactive({name: '张三', age:30})
const changeHandler = ()=>{total.value += 1000userInfo.age += 1
}
</script>
// 子组件
<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}</h3><h3>{{ userInfo }} </h3><button @click="getValueHandler">获取值</button></div>
</template><script setup>
import {defineProps, toRefs} from 'vue'
let props = defineProps({total:{type:Number,default:10},userInfo:{type:Object,required: true,default:()=> {return {name: '罗峰[金角巨兽]',age: 100}}}
})
// 基本数据类型解构失去响应式
const { total, userInfo} =props
const getValueHandler = ()=>{console.log('total', total)console.log('userInfo',userInfo)
}
</script>

vue3.5之前使用toRefs或toRef解构不会失去响应式

// 子组件
<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}--{{ totalValue }}</h3><h3>{{ userInfo }} --{{ userInfoObj }}</h3><button @click="getValueHandler">获取值</button></div>
</template><script setup>
import {defineProps, toRefs, toRef} from 'vue'
let props = defineProps({...代码不变,省略
})
// 普通结构失去响应式
const { total, userInfo} =toRefs(props)const totalValue = toRef(props, 'total');
const userInfoObj = toRef(props, 'userInfo')const getValueHandler = ()=>{console.log('total', total)console.log('userInfo',userInfo)
}
</script>

vue3.5直接解构不会失去响应式(不需要使用toRefs或者toRef)

<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}</h3><h3>{{ userInfo }} </h3><button @click="getValueHandler">获取值</button></div>
</template>
<script setup>
import {defineProps } from 'vue'
// vue3.5之后直接解构不会失去响应式
const { total, userInfo} = defineProps({total:{type:Number,default:10},userInfo:{type:Object,required: true,default:()=> {return {name: '罗峰[金角巨兽]',age: 100}}}
})
const getValueHandler = ()=>{console.log('total', total)console.log('userInfo',userInfo)
}
</script>

vue3.5 解构的时候直接设置默认值

我们刚刚是这样写默认值的,是不是感觉有点麻烦。

const { total, userInfo} = defineProps({total:{type:Number,default:10},userInfo:{type:Object,required: true,default:()=> {return {name: '罗峰[金角巨兽]',age: 100}}}
})

vue3.5vue3.5 解构的时候直接设置默认值,与es6的函数设置默认值一样了

<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}</h3><h3>{{ userInfo }} </h3><button @click="getValueHandler">获取值</button></div>
</template><script setup>
import {defineProps, toRefs, toRef} from 'vue'
// vue3.5 解构的时候直接设置默认值
const { total=10, userInfo= {name: '罗峰[金角巨兽]', age: 100} } = defineProps({total:{type:Number,// default:10},userInfo:{type:Object,required: true,// default:()=> {//   return {//     name: '罗峰[金角巨兽]',//     age: 100//   }// }}
})
const getValueHandler = ()=>{console.log('total', total)console.log('userInfo',userInfo)
}
</script>

解构后如何监听

<template><div class="child-page"><h1>我是子组件</h1><h3>{{ total }}</h3><h3>{{ userInfo }} </h3></div>
</template><script setup>
import {defineProps, toRefs, toRef, watch} from 'vue'
const { total=10, userInfo= {name: '罗峰[金角巨兽]', age: 100}} = defineProps({total:{type:Number,},userInfo:{type:Object,required: true,}
})
// 需要监听解构后的属性,我们要这样写,把它包装在getter中
watch(()=>total, (newValue, oldValue)=>{console.log('total', newValue)
})
</script>

监听解构后的属性,如果这样写会报错

watch(total, (newValue, oldValue)=>{console.log('total', newValue)
})

项目会提示:total" is a destructured prop and should not be passed directly to watch(). Pass a getter () => total instead.
大概意思是:total”是一个解构的道具,不应该直接传递给watch()。请传递一个getter()=>total。

vue3.5新增 useTemplateRef

useTemplateRef函数的用法很简单:
只接收一个参数key,这个字符串表示你要获取哪一个节点, 返回值是一个ref变量。
为啥会有这个方法?
我猜想的是通过原来通过ref获取DOM节点会让人分不清楚是变量还是DOM节点。

useTemplateRef 获取DOM节点

<template><div class="art-page">// 我要获取这个节点<div ref="divNode">我是div</div><button @click="getNodeHandler">获取div节点</button></div>
</template>
<script lang="ts" setup>
import { useTemplateRef } from 'vue'
// useTemplateRef接受的是一个字符串,这个字符串表示你要获取哪一个节点
const divNode = useTemplateRef<HTMLElement>("divNode");
const getNodeHandler=()=>{if(divNode.value){divNode.value.innerText = '通过dom来赋值';}// 等价与 divNode.value && (divNode.value.innerText = '通过dom来赋值');
}
</script>

hooks中使用 useTemplateRef

// hooks文件
import { useTemplateRef } from 'vue'
export default function useRef(eleKey:string, contValue:string){const elementNode = useTemplateRef<HTMLElement>(eleKey);function setNodeElement(){console.log(elementNode.value);if(elementNode.value){elementNode.value.innerText = contValue;}}return { setNodeElement}
}
// 使用的文件
<template><div class="art-page"><div ref="divNode">我是div</div><button @click="getNodeHandler">获取div节点</button></div>
</template>
<script lang="ts" setup>
import useRef from '@/hooks/useNode'
const { setNodeElement } = useRef('divNode', '哈哈-这个是hooks');
const getNodeHandler = ()=>{setNodeElement()
}
</script>

Vue 3.5新增useId 函数

useId是Vue3.5中引入的一个函数,用于生成唯一的ID。
它的主要用途是为组件或DOM元素中唯一的标识符,
避免在 SSR(服务器端渲染)或客户端渲染中因ID重复而导致的问题。
唯一性的前提是:必须在同一个createApp中才是唯一的,如果项目中有多个createApp,那么id就重复了。

多个createApp那么id就重复

// src\main.ts 文件
import { createApp, h, onMounted, useId } from "vue";
createApp({setup(){onMounted(()=>{console.log('app1', useId())})return ()=> h('div', 'hello world')}
}).mount('#app')createApp({setup(){onMounted(()=>{console.log('app2', useId())})return ()=> h('div', 'hello world')}
}).mount('#app')

这个时候我们发现:app1和app2的id是重复的。

多个createApp如何解决id重复问题

我们可以加一个前缀就可以把这个问题给解决了

import { createApp, h, onMounted, useId } from "vue";
createApp({setup(){onMounted(()=>{console.log('app1', useId())})return ()=> h('div', 'hello world')}
}).mount('#app')
let app2 = createApp({setup(){onMounted(()=>{console.log('app2', useId())})return ()=> h('div', 'hello world')}
})
// 给app2加上一个前缀
app2.config.idPrefix = 'app2'
app2.mount('#app')

vue内置组件 Teleport

Vue内置 它可以将Teleport组件的内容移动到指定元素下。
在Teleport组件传送时,vue3.4之前要求目标元素在组件挂载时已经存在。
也就是说: 移动到目标元素必须在Teleport组件的前面。
Vue 3.5 引入了 defer 属性,允许传送的内容到后才渲染目标元素。

目标元素必须在Teleport组件的前面才能渲染

<template><div class="art-page"><Teleport to="#target-node"><h1>我是传送的h1</h1><h1> 等会会被传送</h1></Teleport ><p>我是分割线==========我是分割线</p>// 现在目标元素在Teleport组件的后面,这样渲染会失败的<div id="target-node"></div><p>我是分割线==========我是分割线</p></div>
</template>

那怎么处理这个问题呢?

有的小伙伴会说:这个简单,我把目标元素放在Teleport组件的前面就行了。
确实:这样是可以的。换一下位置。
在vue3.5的版本中,我们只需要使用defer属性即可。

vue3.5中defer属性的作用

以通过 defer 来延迟 Teleport 的挂载。
它会等到同一更新周期中的所有其他 DOM 内容都渲染完毕后,再挂载到目标容器下。

延迟传送(defer Teleport)

<template><div class="art-page"><Teleport defer to="#target-node"><h1>我是传送的h1</h1><h1> 等会会被传送</h1></Teleport ><p>我是分割线==========我是分割线</p><div id="target-node"></div><p>我是分割线==========我是分割线</p></div>
</template>

onWatcherCleanup

该函数将在观察程序失效并即将重新运行时调用。
意思是说:它允许我们在观察的目标发生变化之前执行一些清理工作。
这样我们就可以取消网络请求、移除事件监听器等
onWatcherCleanup的注意点:
1,仅在 Vue 3.5+ 中支持。
2,并且必须在同步执行 watchEffect effect 函数或 watch 回调函数时调用,
你不能在异步函数中的 await 语句之后调用它。

点击按钮3次,就会发送3次请求。

<template><div class="art-page"><button @click="num++">点击按钮</button></div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
let num =ref(0)
watch(num, ()=>{setTimeout(function(){console.log( '我会模拟发送请求', num.value)}, 2000)
})
</script>

10-触发3次.jpg
通过上面的图片,我们发现在1s内点击按钮3次
那么请求就会执行3次,这样并不好。
我们只希望触发最后一次请求。
这个时候我们的主角onWatcherCleanup就闪亮登场了。

vue3.5让它只发送一次请求

<template><div class="art-page"><button @click="num++">点击按钮</button></div>
</template><script lang="ts" setup>
import { onWatcherCleanup, ref, watch } from 'vue';let num =ref(0)
watch(num, ()=>{let timer= setTimeout(function(){console.log( '我会发送请求执行', num.value)}, 2000)// onWatcherCleanup(()=>{clearTimeout(timer)})
})

vue3.5之前的处理办法,使用watch的第3个参数来处理

<template><div class="art-page"><button @click="num++">点击按钮</button></div>
</template>
<script lang="ts" setup>
import { onWatcherCleanup, ref, watch } from 'vue';
let num =ref(0)
watch(num, (newValue,oldValue, onCleanup)=>{let timer= setTimeout(function(){console.log( '我会发送请求执行', num.value)}, 2000)// onCleanup(()=>{clearTimeout(timer)})
})
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/872078.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工作时间离岗智能识别监测系统

工作时间离岗智能识别监测系统基于YOLOX和RNN的深度学习算法,工作时间离岗智能识别监测系统系统利用现场已有的监控摄像机识别监控画面中的人员位置和行为特征。通过深度学习算法的处理,系统能够自动识别员工是否离岗,并计算离岗时间。一旦员工离岗时间超出预设的安全阈值,…

RADXA 5B 开启 USB OTG 网络(虚拟网卡)

RADXA 5B 开启 USB OTG 网络(虚拟网卡)按照官方文档进行配置, 会不成功 确保 USB-A 接口主板上, 插入 USB3.0 下方接口(按着主板)配置设备树 Overlays打开系统配置工具sudo rsetup依次选择 Overlays -> 警告Yes -> Manage overlays -> 空格选中Set OTG port 1 to Peri…

一架小飞机有 4 排座位,每排有 3 个座位。已经有八名乘客登机,他们在这些座位中随机就坐

问题111: 一架小飞机有 4 排座位,每排有 3 个座位。已经有八名乘客登机,他们在这些座位中随机就坐.一架小飞机有 4 排座位,每排有 3 个座位。已经有八名乘客登机,他们在这些座位中随机就坐. 接下来要登机的是一对夫妻. 问这对夫妻能够坐在同一排的 2 个相邻座位上的概率是多…

用效率驱动增长:直播团队如何协同工作?

一、企业增长离不开效率提升 在直播电商领域,企业的增长速度往往与团队运营效率息息相关。一个高效的直播团队不仅可以降低运营成本,还能快速响应市场需求,抓住增长机遇。然而,大多数团队仍在效率优化上存在不足。二、直播团队效率低下的常见问题- 1. 任务堆积:未能合理分…

2025年安卓苹果手机有哪些好用的日记本app推荐?

进入2025年,有很多人想要直接在手机上随手写每天的日记,那么安卓或苹果手机上有哪些好用的日记本app推荐呢? 今天来介绍四款简单又好用的手机版写日记的app软件,总有一款是适合你的。 一、手机系统自带便签/备忘录/笔记工具 不管你用的是哪款手机,手机上都有系统自带的便签…

Silicon Labs C8051F020 单片机 USB Debug Adapter适配器调试无法连接问题

在做单片机大作业,使用Keil,使用USB连接开发板。想要进入到调试或烧录功能时总是报错: Cannot connect to the selected USB debug adapterToolStick base adapter. Please check that the device is plugged in and not already in use 如图:首先按照老师发的教程逐个复查…

C# PriorityQueue优先队列

namespace PriorityQueueDemo {public class Task{public string Name { get; set; } }public class TaskPriorityComparer : IComparer<(int, int)>{public int Compare((int, int) x, (int, int) y){// 首先比较紧急程度,然后比较重要性int compareUrgency = x.Item1.…

如何修改网站后台登录地址以避免触发安全规则?

在某些情况下,网站后台登录地址可能会触发安全规则,导致无法正常登录。可以通过修改后台登录地址来避免这种情况。以下是具体步骤:修改目录名称:将后台目录名称修改为不包含敏感关键词的名称,例如将admin修改为admin-。 更新配置文件:确保所有配置文件中的后台路径指向新…

Vue2_了解核心概念和一个示例工程

本文做了简要的 Vue2 核心概念和示例工程介绍,包括两种 Vue 实例的挂载方式,并对比两者的区别;简单介绍了响应式,包括 data 对象内的数据,使用计算属性,使用 v-model 双向绑定,使用了 button 和 input 做了交互Vue2_了解核心概念和一个示例工程 写文的目的是为了梳理知识…

如何解决FTP连接超时问题?

在使用FTP连接时,如果遇到超时问题,可能是由于网络配置或服务器设置不当导致的。以下是具体步骤:检查FTP端口:确保FTP端口(默认为21)在服务器防火墙中已开放。 检查本地网络:确保本地网络连接正常,尝试更换网络环境后重新连接。 使用替代FTP地址:如果使用的是特定的FT…

如何下载文件到电脑桌面?

将文件从远程服务器下载到本地电脑桌面的操作看似简单,但对于初次接触此类任务的朋友来说,仍需掌握一些基本技巧。下面我们将详细介绍几种常用的下载方法,帮助您顺利完成操作。 方法一:通过FTP客户端下载 FTP(文件传输协议)是一种广泛应用于互联网上的标准协议,用于在客…

网站登录无响应,如何排查和解决?

您好,当您在尝试登录网站时遇到无响应的情况,这可能是由多种因素引起的。为了帮助您更有效地解决问题,我们将从以下几个方面进行详细分析,并提供相应的解决方案。 1. 服务器状态检查 首先,确保您的云服务器处于正常运行状态。服务器的意外重启或负载过高都可能导致网站无法…