子组件中设置默认属性

<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 += 1000
userInfo.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>

vue3.5保证你看得明明白白的更多相关文章

  1. Vue3.2中的setup语法糖,保证你看的明明白白!

    vue3.2 到底更新了什么? 根据原文内容的更新的内容主要有以下 5 块: 1.SSR:服务端渲染优化.@vue/server-renderer包加了一个ES模块创建, 与Node.js解耦,使在非 ...

  2. 国庆总结:echarts自定义颜色主题,保证你看的明明白白

    为什么需要使用颜色主题 随着用户审美越来越高,不再是过去那样只注重功能. 所以对界面的颜色样式都具有一定的审美要求 此时颜色是否好看就非常重要了 因为人都是视觉动物 对界面的第一印象肯定都是颜色. 如 ...

  3. vue下一代状态管理Pinia.js 保证你看的明明白白!

    1.pinia的简单介绍 Pinia最初是在2019年11月左右重新设计使用Composition API的 Vue 商店外观的实验. 从那时起,最初的原则相同,但 Pinia 适用于 Vue 2 和 ...

  4. vue混入mixin的使用,保证你看的明明白白!

    场景描述 有些时候,我们发现有些组件部分功能代码是几乎是一样的. 这个时候,我们就可以将相同的逻辑代码抽离出来 此时我们的主角混入mixin就登场了 下面我们有a-test和b-test两个组件,点击 ...

  5. node使用node-xlsx实现excel的下载与导入,保证你看的明明白白

    需求简介 很多时候,我们都会有这样一个业务. 将列表中的数据导出为excel. 这样做的目的是为了方便查看,同时可以保存在本地归档. 还可以将导出的Excel后的数据进行加工. node-xlsx 的 ...

  6. 面试题——20+Vue面试题整理

    0.那你能讲一讲MVVM吗? MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel. Model层代表数据模型,View代表UI组件, ...

  7. ES6 新特性

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015. 也就是说,ES6就是ES2015. ...

  8. 最常用的ES6特性(转)

    最常用的ES6特性 let, const, class, extends, super, arrow functions, template string, destructuring, defaul ...

  9. java 大数据处理类 BigDecimal 解析

    这两天,由于我的必修课概率论里经常要用到排列组合的计算,感觉很麻烦,加上现代智能手机的计算器是没有这方面功能的. 所以,就自己动手写了个安卓的 排列组合 计算器,用了一天,发现有很大的问题,阶乘达百亿 ...

  10. 算法:KMP算法

    算法:KMP排序 算法分析 KMP算法是一种快速的模式匹配算法.KMP是三位大师:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,所以取首字母组成KMP. 少部分图片来自孤~影 ...

随机推荐

  1. 参与 2024 第四季度官方 Flutter 开发者调查

    Flutter 3.24 和 Dart 3.5 稳定版发布 已有三月之久,今年最后一次开发者调查也如约而至! 自 Flutter 3.24 正式发布以来,团队通过一系列补丁更新不断优化平台稳定性和开发 ...

  2. P4119 Ynoi2018 未来日记

    P4119 Ynoi2018 未来日记 lxl 出的题好 duliu 啊. 感谢来自 fr200110217102 的博客 题解 P4119 [Ynoi2018未来日记]. 下标分块+值域分块+并查集 ...

  3. ARC127E Priority Queue

    ARC127E Priority Queue 分析性质+dp. 思路 由于每次加入的数肯定是一个 \(a\) 的排列,但这个角度不好考虑. 设 \(\{a\}\) 为最终状态的集合,其中 \(a_i& ...

  4. Dell 塔式t440 安装centos (Non-Raid 成功版)

    前情提要 这篇文章是2021年我发布在csdn上,最近搬到博客园了,我把这篇文章重新整理发布下.有的图带有水印 csdn@at_the_Moment正常的,这就是我在csdn的账号. 提前声明一下这是 ...

  5. npm安装包出现Invalid Version,npm list报错UNMET DEPENDENCY报错

    执行 npm install 出现报错 2097 verbose stack TypeError: Invalid Version: 2097 verbose stack at new SemVer ...

  6. SpringMVC源码剖析(四)- DispatcherServlet请求转发的

    SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即"service"阶段.在"service"阶段中,每一次Http请求到来 ...

  7. python项目依赖管理之poetry

    poetry,是一个强大的Python项目依赖管理工具,旨在简化和优化项目的依赖管理过程.它提供了一种简单且一致的方式来定义.安装和管理项目所需的依赖项.本文将详细介绍poetry库的安装方法.使用方 ...

  8. 关于elementUI的table报错RangeErr Maximum call stack size exceeded

    项目中需要做一个功能,在表格中如果存在二级列表,点击箭头之后请求后台接口,展开显示二级列表的内容.点击箭头拿到了数据,但是后台会报错如下图,且数据展示不出来 上网查了下,意思是堆栈溢出,这个提示让我十 ...

  9. JDBC基础知识

    常见连接数据库工具: 图形化工具:点击.拖拽就可以操作数据库,对用户友好,简单对数据操作,复杂数据库操作爱莫能助 JDBC(驱动程序):调用jar包接口 窗口(命令行):输入完整SQL语句对复杂数据库 ...

  10. spring gateway 学习

    为什么需要使用网关 1.实现统一认证 2.统一一个域名,解决调用困难. 3.协议转换 将不友好的协议转成友好的协议. spring cloud gateway 是什么 是spring cloud 的第 ...