超全 Vue3新特性总结

news2025/7/14 16:33:40

Vue3 应用-技术分享与交流

新特性篇

Vue3 组合式 API VS Vue2 选项式 API

选项式 API 面临的问题:

我们在处理业务逻辑时,需要在 data computed method watch 中分别进行代码编写,碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。我们必须不断地“跳转”相关代码的选项块,让维护变得困难,也不利于代码的可读性。

在这里插入图片描述
在这里插入图片描述

组合式 API 优势

1.更好的逻辑复用

组合式 API 最基本的优势是它使我们能够通过组合函数来实现更加简洁高效的逻辑复用。在选项式 API 中我们主要的逻辑复用机制是 mixins,而组合式 API 解决了 mixins 的所有缺陷。

2.更灵活的代码组织

大部分代码都自然地被放进了对应的选项里

3.更好的类型推导

近几年来,越来越多的开发者开始使用 TypeScript 书写更健壮可靠的代码,TypeScript 还提供了非常好的 IDE 开发支持。大多数时候,用 TypeScript 书写的组合式 API 代码和用 JavaScript 写都差不太多!这也让许多纯 JavaScript 用户也能从 IDE 中享受到部分类型推导功能。

4.更小的生产包体积

搭配 <script setup> 使用组合式 API 比等价情况下的选项式 API 更高效,对代码压缩也更友好

数据响应式原理 Proxy 相对于 Object.defineProperty

proxy 的性能本来比 defineProperty 好,proxy 可以拦截属性的访问、赋值、删除等操作,不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性。

可以监听数组变化

可以劫持整个对象

操作时不是对原对象操作,是 new Proxy 返回的一个新对象

可以劫持的操作有 13 种

diff 更高效

vue3.x 中标记和提升所有的静态节点,diff 的时候只需要对比动态节点内容

小结

vue3 性能更高, 体积更小, 更利于复用, 代码维护更方便

<script setup> 语法糖

  • <\script setup> 中的代码会在每次组件实例被创建的时候执行
  • 顶层的绑定会被暴露给模板
    当使用 <script setup> 的时候,任何在<script setup>声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容) 都能在模板中直接使用
  • 使用组件
<script setup>
import MyComponent from './MyComponent.vue'
</script>
<template>
  <MyComponent />
</template>
  • 动态组件
<script setup>
import Foo from './Foo.vue'
import Bar from './Bar.vue'
</script>
<template>
  <component :is="Foo" />
  <component :is="someCondition ? Foo : Bar" />
</template>

从已知的角度出发

生命周期钩子

setup 代替了 beforeCreate,created,如果在 options api 中书写,会在 beforeCreate 之前执行

mounted、beforeMount、beforeUpdate、updated ,都改成 onxxx

beforeDestroy 改成 onBeforeUnmount;

destroyed 改成 onUnmounted

VUE 生命周期
在这里插入图片描述

onBeforeMount()	beforeMount	在组件被挂载之前被调用
onMounted()	mounted	在组件挂载完成后执行
onBeforeUpdate()	beforeUpdate	在组件即将因为响应式状态变更而更新其 DOM 树之前调用
onUpdated()	updated	在组件因为响应式状态变更而更新其 DOM 树之后调用
onBeforeUnmount	beforeDestroy	在组件实例被卸载之前调用
onUnmounted()	destroyed	在组件实例被卸载之后调用
onErrorCaptured()	errorCaptured	在捕获了后代组件传递的错误时调用

nextTick

import { nextTick } from "vue";
// DOM更新完毕之后执行回调的两种写法
nextTick(() => {
  console.log("DOM更新完毕");
});
await nextTick();
console.log("DOM更新完毕");

双向绑定 v-model

  • 修饰符 .lazy
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
  • 修饰符 .number
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.number="age" />
  • 修饰符 .trim
<!-- 自动去除用户输入内容中两端的空格 -->
<input v-model.trim="msg" />

响应式

  • 基础类型 ref
<template>
  <div>{{ count }}</div>
</template>

<script setup>
const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1
</script>
  • reactive 定义复杂数据类型的响应式


<template>
  <div>{{userInfo.name}}</div>
</template>

<script setup>
import {reactive} from 'vue'

const userInfo = reactive({
    name:''
})
</script>
  • toRef()
    当我们在渲染数据时,不希望用到前缀时,可以使用组合 toRef()

    toRef()是函数,转换响应式对象中的某个属性为单独响应式数据,他们之间依然相互绑定
<div>{{ name }}</div>;

import { reactive } from "vue";

const userInfo = reactive({
  name: "",
});
const name = toRef(userInfo, "name");
  • shallowRef()
    ref() 的浅层作用形式
const state = shallowRef({ count: 1 });

// 不会触发更改
state.value.count = 2;

// 会触发更改
state.value = { count: 2 };

组件传参

  • 父-子
// 父组件
<template>
  <Child :name="name" />
</template>
// 子组件
<script setup>
const props = defineProps({
  name: { type: String, default:'', required: true }
})
</script>
  • 子-父
// 子组件
<script setup>
const emit = defineEmits(['updateName'])
emit('updateName', name.value)
</script>

// 父组件
<template>
  <Child  @updateName="handleUpdate" />
</template>
<script setup>
const handleUpdate=()={
  //TODO
}
</script>
  • 父组件调用子组件方法传参
// 子组件
<script setup>
import { ref,defineExpose } from 'vue'
const emit = defineEmits(['updateName'])
const changeName = (val) => {
  console.log(val)
}
// 将方法、变量暴露给父组件使用,父组件才可通过ref API拿到子组件暴露的数据
defineExpose({
  changeName
})
</script>

//父组件
<template>
  <Child ref="childElementRef" />
</template>

<script setup>
import { ref,onMounted } from 'vue'
import Child from './Child.vue'
const childElementRef = ref()
onMounted(() => {
  console.log(childElementRef.value.changeName()) // DOM 元素将在初始渲染后分配给 ref
})
</script>

依赖注入 provide 和 inject(没变化)

  • demo
// 父级/祖先 组件
<script lang="ts" setup>
import { provide,computed } from 'vue'
const message = ref('hello')
provide('message',message)
</script>

// 后代组件接收参数
<script lang="ts" setup>
import { inject,Ref,ref } from 'vue'
const r = inject<Ref<string>>('message',ref('defaultMessage'))
// r.value
</script>

计算属性

  • 简单用法
<template>
  <span>{{ nextYear }} </span>
</template>
<script lang="ts" setup>
import { ref, reactive, computed} from 'vue'
const year = ref<number>(2022)
const nextYear  = computed(() => {
  return year.value++
})
</script>

  • 重写 get set
const nextYear = computed({
  get() {
    return year.value++;
  },
  set(value) {
    return (year = value + 2);
  },
});

watch

  • watch options 参数配置

    watch(WatcherSource, Callback, [WatchOptions])
    参数:
    WatcherSource:想要监听的响应式数据。
    Callback:执行的回调函数,入参(newValue,oldValue)。
    [WatchOptions]:deep、immediate、flush 可选。

deep:当需要对对象等引用类型数据进行深度监听时,设置 deep: true,默认值是 false。
immediate:默认情况下 watch 是惰性的,设置 immediate: true 时,watch 会在初始化时立即执行回调函数一次。
flush:控制回调函数的执行时机,。它可设置为 pre、post 或 sync。

pre:默认值,当监听的值发生变更时,优先执行回调函数(在 dom 更新之前执行)。
post:dom 更新渲染完毕后,执行回调函数。
sync:一旦监听的值发生了变化,同步执行回调函数(建议少用)。

  • 基本用法 监听单个数据 ref
<script lang="ts" setup>
import { watch, ref } from 'vue';
const hidden = ref<boolean>(false)
watch(hidden, (newValue, oldValue) => {
  console.log(`${oldValue} -> ${newValue}`)
})
</script>
  • 引用类型 ref 直接深度监听

    只能获取到新值,而获取不到旧的值

const count = ref({
  a: 1,
  b: 2,
});
const handleClick = function () {
  count.value.a = 5;
};
watch(
  count,
  (newValue, oldValue) => {
    console.log("值发生了变更", newValue, oldValue);
  },
  { deep: true }
);
/*
使用深拷贝解决不能获取旧值问题
watch(
  () => {
    return { ...count.value };
  },
  (newValue, oldValue) => {
    console.log('值发生了变更', newValue, oldValue);
  },
  { deep: true }
)
*/
  • 监听单个数据:reactive
const single = reactive({ count: 1, test: 2 });
const handleClick = function () {
  single.count++;
};
watch(
  () => single.count,
  (newValue, oldValue) => {
    console.log("值发生了变更", newValue, oldValue);
  },
  { immediate: true }
);
  • 监听引用类型数据:reactive
<script setup>
import { ref, reactive, watch } from 'vue';
const single = reactive({ count: 1, test: { a: 1, b: 2 } });
watch(
  single,
  (newValue, oldValue) => {
    console.log('值发生了变更', newValue, oldValue);
  },
  { immediate: true }
);
</script>

过滤器

Vue3 filter 过滤器已作废

替代方案 函数或计算属性

全局过滤器方案

const app = createApp(App)

// 给当前app的全局属性上挂载一个过滤器对象
app.config.globalProperties.$filters = {
  currencyUSD(value) {
    return '$' + value
  }
}
// 使用
<template>
  <p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>

自定义指令

<script setup>中,任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令

<template>
  <input v-focus />
</template>
<script setup>
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

  • 全局注册
const app = createApp({});

// 使 v-focus 在所有组件中都可用
app.directive("focus", {
  /* ... */
});
  • 指令钩子函数
const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {},
};

事件修饰符

  • .stop 阻止事件冒泡
  • .prevent 阻止默认事件
  • .capture 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理
  • .once 点击事件将只会触发一次

其他

  • v-memo
    如果 valueA 和 valueB 都保持不变,这个
    及其子项的所有更新都将被跳过。实际上,甚至虚拟 DOM 的 vnode 创建也将被跳过
<div v-memo="[valueA, valueB]">...</div>

自定义hooks

定义

Hooks本质是一个函数,用来处理复用代码逻辑的一些封装

Vue自定义Hooks有哪些作用?

1.业务密集型模块,用来实现逻辑分离,使主界面代码更清晰
2.相比于mixin,数据来源可追溯,代码逻辑清晰,不存在命名冲突等问题。
3.降低代码耦合,实现代码高复用

它有哪些特点

1.状态共享
2.内部可使用vue组合式API及生命周期钩子等
3.命名以use开头
4.需要暴露出响应式数据或者方法供外部使用

Hooks实现,“useMousePosition”实现了鼠标点击时,获取鼠标点x,y坐标

在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

百度工程师浅谈分布式日志

作者 | 文库基础架构 导读 我们做软件开发时&#xff0c;或多或少的会记录日志。由于日志不是系统的核心功能&#xff0c;常常被忽视&#xff0c;定位问题的时候才想起它。本文由浅入深的探讨不起眼的日志是否重要&#xff0c;以及分布式架构下的日志运维工具应该具备哪些能力&…

【单目标优化算法】海鸥优化算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

如何使用ODX描述诊断会话和安全等级

ODX 2.2是由ASAM&#xff08;自动化及测量系统标准协会&#xff09;提出的诊断标准&#xff0c;是一种基于XML语言的开放式诊断数据格式&#xff0c;已在国际上得到广泛使用。目前ODX诊断标准也已被国内各大OEM采用&#xff0c;但在ODX数据开发阶段&#xff0c;ODX诊断数据库的…

1.1 数据库简介

文章目录1.什么是数据库2.数据库分类3.关系型数据库和非关系型数据库4.关系型数据库4.1 Mysql数据库4.2 MySQL数据的存放1.什么是数据库 我们可以简单将数据库理解为一个存储数据&#xff0c;管理数据的仓库&#xff1b; 仓库中有许多的货架&#xff08;数据表&#xff09;&a…

JSP 字库销售管理系统myeclipse定制开发sqlserver数据库网页模式java编程jdbc

一、源码特点 JSP 字库销售管理系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为SQLServer2008&#x…

【RecBole-GNN/源码】RecBole-GNN中NCL源码解析

如果觉得我的分享有一定帮助&#xff0c;欢迎关注我的微信公众号 “码农的科研笔记”&#xff0c;了解更多我的算法和代码学习总结记录。或者点击链接扫码关注【RecBole-GNN/源码】RecBole-GNN中NCL源码解析 【RecBole-GNN/源码】RecBole-GNN中NCL源码解析 原文&#xff1a;ht…

【教程】GitStats代码统计工具(附GitLab API相关)

使用GitStats进行代码统计 官方文档&#xff1a;GitStats - git history statistics generator GitStats是基于Git的数据统计生成器&#xff0c;输出格式为HTML&#xff0c;可直接在浏览器打开查看&#xff0c;展现为图表形式的可视化数据&#xff0c;内容包括&#xff1a; 常…

Spring Boot MyBatis-Plus 连接 Oracle 数据库 自动生成代码

IDEA 创建SpringBoot项目 项目创建移步 IDEA创建SpringBoot项目 添加依赖 <!--MyBatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</vers…

归因分析笔记21 可解释的机器学习-李宏毅讲座

视频链接: https://www.bilibili.com/video/BV1Wv411h7kN/?p96&vd_source7259e29498a413d91ab48c04f9329855 课件链接: https://view.officeapps.live.com/op/view.aspx?srchttps%3A%2F%2Fspeech.ee.ntu.edu.tw%2F~hylee%2Fml%2Fml2021-course-data%2Fxai_v4.pptx&…

【数据结构与算法】数据结构的基本概念,时间复杂度

&#x1f349;内容专栏&#xff1a;【数据结构与算法】 &#x1f349;本文脉络&#xff1a;数据结构和算法的基本概念&#xff0c;时间复杂度 &#x1f349;本文作者&#xff1a;Melon西西 &#x1f349;发布时间 &#xff1a;2023.2.21 目录 一、引入&#xff1a; 二、数据结…

一键恢复和重装系统的区别是什么

如果电脑出现系统故障问题的时候&#xff0c;我们的电脑系统还原和系统重装都是很好的解决方法之一&#xff0c;不过是二者之间是有区别的。那么我们的电脑系统还原和系统重装有什么区别呢?现在就跟大家聊聊电脑一键恢复和重装系统的区别有哪些。 工具/原料&#xff1a; 系统…

P6软件应用的核心收益

卷首语 提供了多用户、多项目的功能模块&#xff0c;支持多层次项目等级划分&#xff0c;资源分配计划&#xff0c;记录实际数据&#xff0c;自定义视图&#xff0c;并具有用户定义字段的扩展功能。 利用最佳实践&#xff0c;建立企业模板库 P6软件支持用户使用模板编制项目…

Arduino-交通灯

LED交通灯实验实验器件&#xff1a;■ 红色LED灯&#xff1a;1 个■ 黄色LED灯&#xff1a;1 个■ 绿色LED灯&#xff1a;1 个■ 220欧电阻&#xff1a;3 个■ 面包板&#xff1a;1 个■ 多彩杜邦线&#xff1a;若干实验连线1.将3个发光二极管插入面包板&#xff0c;2.用杜邦线…

Sqoop介绍_以及安装_测试---大数据之Apache Sqoop工作笔记001

这个sqoop主要是用来,把数据从mysql中导入到hdoop中,去看看介绍吧. sql to hadoop 然后我们来看看sqoop,可以看到这里稳定版本是1.4.7 然后1.4.7 跟centos6.8 不是太好配置 这里用了1.4.6 但是如果用1.4.7 和centos7 还行 可以看看官网,这里sqoop1 跟sqoop2 这里标注了s…

【论文笔记】Manhattan-SDF == ZJU == CVPR‘2022 Oral

Neural 3D Scene Reconstruction with the Manhattan-world Assumption 本文工作&#xff1a;基于曼哈顿世界假设&#xff0c;重建室内场景三维模型。 1.1 曼哈顿世界假设 参考阅读文献&#xff1a;Structure-SLAM: Low-Drift Monocular SLAM in Indoor EnvironmentsIEEE IR…

【原创】java+swing+mysql宿舍管理系统设计与实现

今天我们主要来介绍如何使用swing图形化gui工具和mysql数据库去开发一个学生宿舍管理系统&#xff0c;这样一个比较经典的项目&#xff0c;学生宿舍管理系统&#xff0c;相信都很多人都不同程度的写过&#xff0c;从实现上来说不难。 功能分析&#xff1a; 学生宿舍管理系统&…

mysql中利用sql语句修改字段名称,字段长度等操作(亲测)

在网站重构中&#xff0c;通常会进行数据结构的修改&#xff0c;所以添加&#xff0c;删除&#xff0c;增加mysql表的字段是难免的&#xff0c;有时为了方便&#xff0c;还会增加修改表或字段的注释&#xff0c;把同字段属性调整到一块儿。这些操作可以在phpmyadmin或者别的mys…

Lazada选品推荐,这些爆品成了东南亚开年大赢家

小编今日整理了最新快消行业情报&#xff0c;带您解读东南亚市场玩具、母婴、美妆、食品、宠物类目的最新热销品类和发展方向&#xff0c;宠物。赶在大促前为商家朋友们助力一波&#xff01;STEM玩具、精细化拟人化宠物食品、便携香水……一大波商机正在赶来&#xff01;准备好…

编译链接实战(9)elf符号表

文章目录符号的概念符号表探索前面介绍了elf文件的两种视图&#xff0c;以及两种视图的各自几个组成部分&#xff1a;elf文件有两种视图&#xff0c;链接视图和执行视图。在链接视图里&#xff0c;elf文件被划分成了elf 头、节头表、若干的节&#xff08;section&#xff09;&a…

C++项目——高并发内存池(2)——thread_cache的基础功能实现

1.并发内存池concurrent memory pool 组成部分 thread cache、central cache、page cache thread cache&#xff1a;线程缓存是每个线程独有的&#xff0c;用于小于64k的内存的分配&#xff0c;线程从这里申请内存不需要加锁&#xff0c;每个线程独享一个cache&#xff0c;这…