首页 > 其他分享 >vue3.5保证你看得明明白白

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

时间:2025-01-20 12:31:45浏览次数:1  
标签:const log 明明白白 保证 userInfo vue3.5 import console total

子组件中设置默认属性

<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>

标签:const,log,明明白白,保证,userInfo,vue3.5,import,console,total
From: https://www.cnblogs.com/IwishIcould/p/18668565

相关文章

  • 一文让你对mysql索引底层实现明明白白
    作者:京东零售韩航云开篇:图片是本人随笔画的,有点粗糙,望大家谅解,如有不对的地方,请联系本人,感谢一、索引到底底是什么.索引是帮助mysql高效获取数据的排好序的数据结构.索引是存储在文件里的.数据结构:二叉树HASHBTREE  如果没有索引的话,循环一条一条的找,找一次就是一......
  • don‘t sleep一款阻止系统意外中断,保证工作娱乐安全运行的软件!
    软件介绍给大家分享一款大小仅500多KB,用于防止系统进入关机、重启、待机、睡眠、休眠、注销、屏幕保护等状态功能的软件,避免工作或者娱乐受到打扰。软件主要由阻止和允许功能构成。例如当你在下载、暂时离开、工作的时候使用阻止功能可以避免系统进入不同的电源管理模式......
  • Xbox:Xbox游戏测试与质量保证技术教程_2024-07-19_21-13-40.Tex
    Xbox:Xbox游戏测试与质量保证技术教程游戏测试基础游戏测试的重要性游戏测试是游戏开发过程中不可或缺的一环,它确保游戏在发布前能够提供给玩家一个流畅、无bug、且具有高度娱乐性的体验。测试的重要性在于:确保游戏质量:通过测试,可以发现并修复游戏中的各种问题,如图形错误......
  • 在Java并发编程中保证操作的原子性的方法
    在Java并发编程中,保证操作的原子性是确保数据一致性和程序正确性的关键。以下是几种常见的方法及其使用场景:1. synchronized 关键字实现原理:synchronized关键字用于同步代码块或方法,以确保同一时间只有一个线程可以执行该代码块或方法。它通过内部锁机制来实现,当一个线程......
  • 底层分析为什么CAS不保证可见性
    这些都是笔者辛苦总结,若是对你有用,就点赞收藏支持一下笔者,也是对笔者所写的肯定,谢谢大家!目录总线锁定机制缓存锁定机制(MESI协议) 伪代码展示 缓存一致性维护 两种机制的协同工作示例在CPU缓存架构,CAS只保证比较和交换这个操作是原子的,不保证值的可见性,每个CPU都有......
  • Spring AMQP-保证消息的可靠性
    1.消息发送者的可靠性保证消息的可靠性可以通过发送者重连和发送者确认来实现发送者重连发送者重连机制就是在发送信息的时候如果连接不上mq不会立即结束,而是会在一定的时间间隔之类进行重新连接,连接的次数和时间都是由我们在配置文件中指定的,具体的就是通过retry属性来......
  • 你是如何保证多浏览器的兼容?
    在前端开发中,保证多浏览器的兼容性是一个至关重要的任务。以下是一些具体的策略和方法,以确保网站或应用程序在各种浏览器上都能正常运行:一、明确目标浏览器确定受众:根据目标受众和用户统计数据,确定需要支持的主要浏览器版本。聚焦重点:这有助于开发人员聚焦于最重要的兼容性问......
  • 如何保证团队内部一致的代码风格?
    保证团队内部一致的代码风格是提升代码可读性和可维护性的重要手段。以下是一些建议,以帮助你在前端开发团队中保持一致的代码风格:选择并遵循一种代码风格指南:例如,AirbnbJavaScript风格指南、GoogleJavaScript风格指南等。这些指南详细规定了如何命名变量、如何格式化代码、......
  • 如何保证用户的使用体验
    性能优化方面页面加载速度优化代码结构:精简HTML、CSS和JavaScript代码。例如,去除冗余的标签和样式,压缩代码以减少文件大小。可以使用工具如HTMLMinifier(用于HTML压缩)、CSSNano(用于CSS压缩)和UglifyJS(用于JavaScript压缩)。这样在用户访问页面时,文件能够更快地被浏览器下载和解......
  • redis是如何保证数据安全的?
    一、redis单线程        redis的内存读写操作是单线程的,保证操作的线程安全。redis6之后,redis的读写操作是多线程的,但核心的内存计算操作仍然是单线程的。面试官:Redis是单线程还是多线程?(你为何怎么说都不对?)_redis5和redis6的区别-CSDN博客二、Redis的持久化    ......