Vue3 中的几个坑,你都见过吗?

news2024/11/19 1:39:24

Vue3 目前已经趋于稳定,不少代码库都已经开始使用它,很多项目未来也必然要迁移至 Vue3。本文记录我在使用 Vue3 时遇到的一些问题,希望能为其他开发者提供帮助。

1. 使用 reactive 封装基础数据类型

传统开发模式中,数据声明很简单。但是在 Vue 中有多个响应式变量声明方式,整体的使用规则如下:

使用 reactive 来封装 Object,Array,Map,Set 数据类型;

使用 ref 封装 String,Number,Boolean 类型。

如果使用 reactive 来封装基础数据类型,会产生警告,同时封装的值不会成为响应式对象。

<script setup>
import { reactive } from "vue";
const count = reactive(0);
</script>

但是,可以使用 ref 来封装 Object、Array 等数据类型,内部会调用 reactive。

2. 解构 reactive 对象

下面代码中,count 封装成了 reactive 对象,点击按钮时,count 会自增。

<template>
  Counter: {{ state.count }}
  <button @click="add">Increase</button>
 </template>


 <script>
 import { reactive } from "vue";
 export default {
  setup() {
   const state = reactive({ count: 0 });


   function add() {
    state.count++;
   }

   return {
    state,
    add,
   };
  },
 };
 </script>

如果需要使用 ES6 结构赋值对 state 进行结构,需要使用如下的代码:

<template>
  <div>Counter: {{ count }}</div>
  <button @click="add">Increase</button>
</template>

<script>
import { reactive } from "vue";
export default {
  setup() {
    const state = reactive({ count: 0 });

    function add() {
      state.count++;
    }

    return {
      ...state,
      add,
    };
  },
};
</script>

结构复制完成之后,点击按钮,效果如下:

代码看起来比较相似,而且根据以前的表现,逻辑是可以正常执行的。但事实上,Vue 的响应式追踪通过属性获取,这意味着我们不能去解构响应式对象,会导致引用连接丢失。这是响应式代理的限制之一。

3. 使用.value 造成的困惑

Ref 接受一个值并返回一个响应式对象,该值只有在内部对象.value 属性下可用。

const count = ref(0)

 console.log(count) // { value: 0 }
 console.log(count.value) // 0

 count.value++
 console.log(count.value) // 1

但是 ref 如果应用在 template 中,不需要对 ref 进行解包,也就是不需要使用.vue。

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

const count = ref(0)

function increment() {
  count.value++
}
</script>

<template>
  <button @click="increment">
    {{ count }} // 不需要调用.value
  </button>
</template>

需要注意的是,解包只作用于一级属性,下边的代码会返回 [object Object]

<script setup>
import { ref } from 'vue'
const object = { foo: ref(1) }
</script>
<template>
  {{ object.foo + 1 }}  // [object Object]
</template>

正确使用.value 需要时间,初学者偶尔会忘记它。在使用时,要注意只在合适的场景下使用它。

4. Emitted 事件

从 Vue 发布以来,子组件可以通过 emits 与父组件通信,只需要添加一个自定义的监听器来监听事件即可。

this.$emit('my-event')
<my-component @my-event="doSomething" />

Vue3 中,需要使用编译器宏 defineEmits 来声明 emits。

const emit = defineEmits(['my-event'])
 emit('my-event')
 </script>

在 setup 语法糖下,defineEmits 和 defineProps 会被自动引入。其它情况下,需要主动引入。

<script setup>
const props = defineProps({
  foo: String
})

const emit = defineEmits(['change', 'delete'])
// setup code
</script>

最后,由于 Vue3 中,事件必须声明,因此再需要使用.native 修饰符,该修饰符已被移除。

5. 声明组件选项

setup 不支持如下组件选项声明:

name
inheritAttrs
customOptions
如果需要继续使用这些属性,可以声明多个 script 脚本,如下所示:

<script>
  export default {
    name: 'CustomName',
    inheritAttrs: false,
    customOptions: {}
  }
</script>

<script setup>
  // script setup logic
</script>
6. 使用 Reactivity Transform

Reactivity Transform 是 Vue3 中一个预览属性,有一定的争议性,默认是禁用的。它主要用来简化组件的声明方式。这个想法是利用编译时转换来自动解包 ref,从而避免使用.value。从 Vue3.3 中已经删除该功能,作为一个扩展包提供。由于它不是 Vue 的核心部分,且目前风险还是比较多,建议先不要在此方面投入太多事件。感兴趣可以参考文章:Reactivity Transform

7. 定义异步组件

异步组件以前是通过将它们包含在方法中来声明的。

const asyncModal = () => import('./Modal.vue')

Vue3 中需要使用 defineAsyncComponent 来声明异步组件。

import { defineAsyncComponent } from 'vue'
 const asyncModal = defineAsyncComponent(() 
=> import('./Modal.vue'))
8. template 中使用不必要的包装元素
<!-- Layout.vue -->
<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>

Vue3 中支持多个根元素,不再需要使用外层 div 元素包裹。

<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>
9. 生命周期函数

所有组件生命周期函数都通过添加 on 前缀或完全更名实现,下图详细列出了具体的变化:
在这里插入图片描述

10. 产品文档

官方对文档已经做了更新,补充更新了 API,并包含很多有价值的注释、指南和最佳实践。即使你现在使用的是 Vue2,通过阅读新的文档也会学到一些新知识。

总结

每个框架都有学习曲线,Vue3 相对 Vue2 更加陡峭,在框架切换之间也会有一定的学习成本。但 Vue3 组合式 API 相对 Vue2 选项式 API 确实更加简洁易用。如果您在使用过程中有什么疑问,也欢迎留言交流。

本文翻译自文章:

https://fadamakis.com/10-mistakes-to-avoid-when-starting-with-vue-3-1d1ced8552ae

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

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

相关文章

[论文阅读]Visual Attention Network原文翻译

[论文链接]https://arxiv.org/abs/2202.09741 摘要 虽然一开始是被设计用于自然语言处理任务的&#xff0c;但是自注意力机制在多个计算机视觉领域掀起了风暴。然而&#xff0c;图像的二维特性给自注意力用于计算机视觉带来了三个挑战。&#xff08;1&#xff09;将图像视作一…

怎样获取字符串数组的长度_使用sizeof(array) / sizeof(array[0])

使用sizeof() C、C中没有提供直接获取数组长度的函数&#xff0c;对于存放字符串的字符数组提供了一个strlen函数获取长度&#xff0c;那么对于其他类型的数组如何获取他们的长度呢&#xff1f; 其中一种方法是使用sizeof(array) / sizeof(array[0]), 在C语言中习惯上在使用时…

Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例

Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例 点击封面跳转到Unity国际版下载页面 简介 在Unity中&#xff0c;性能优化是游戏开发过程中非常重要的一环。其中&#xff0c;Shader的优化对于游戏的性能提升起着至关重要的作用。…

redis缓存详解

一、Redisson分布式锁存在问题 1、基于redis实现的分布式锁&#xff0c;如果redis集群出现master宕机&#xff0c;而从节点没有接收到锁对应的key&#xff0c;被选举成新的master就可能存在被其它线程加锁成功则存在加锁问题 2、 基于上面的问题&#xff0c;可以把redis分为多…

SpringBoot国际化配置组件支持本地配置和数据库配置

文章目录 0. 前言i18n-spring-boot-starter1. 使用方式0.引入依赖1.配置项2.初始化国际化配置表3.如何使用 2. 核心源码实现一个拦截器I18nInterceptorI18nMessageResource 加载国际化配置 3.源码地址 0. 前言 写个了原生的SpringBoot国际化配置组件支持本地配置和数据库配置 背…

口袋参谋:99.99%商家都学的防骗技巧!

​99%的淘宝天猫商家&#xff0c;必然都要解决一个问题&#xff01;&#xff01;&#xff01; 如何让自己不被敲诈勒索且骗钱&#xff01; 直接看真实案例 看这个骗子&#xff0c;是如何赤裸裸诈骗商家的&#xff01; 如果你不想再当冤大头&#xff0c;告诉你一个99.99%有效…

SSM - Springboot - MyBatis-Plus 全栈体系(六)

第二章 SpringFramework 四、SpringIoC 实践和应用 3. 基于 注解 方式管理 Bean 3.1 实验一&#xff1a;Bean 注解标记和扫描 (IoC) 3.1.1 注解理解 和 XML 配置文件一样&#xff0c;注解本身并不能执行&#xff0c;注解本身仅仅只是做一个标记&#xff0c;具体的功能是框…

分类预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入分类预测

分类预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于SVM-Adaboost支持向量机结合Ada…

Python 图形化界面基础篇:理解 Tkinter 主事件循环

Python 图形化界面基础篇&#xff1a;理解 Tkinter 主事件循环 引言什么是 Tkinter 主事件循环&#xff1f; Tkinter 主事件循环的使用步骤1&#xff1a;导入 Tkinter 模块步骤2&#xff1a;创建 Tkinter 窗口对象步骤3&#xff1a;设置窗口标题和添加 GUI 元素步骤4&#xff1…

router-link 和 router-view的区别

router-link 实现路由之间的跳转 router-view&#xff08;路由出口组件 -> 渲染路径匹配到的视图组件&#xff09; 当你访问的地址与路由path相符时&#xff0c;会将指定的组件替换该router-view router-link router-link 点击实现路由跳转&#xff0c;to属性指向目标地址&…

期权开户需要多长时间?一天可以开好吗?

期权开户一般需要一天到一个月的时间不等。根据不同券商的要求&#xff0c;开户流程和时间可能会有所不同。一些券商会要求客户进行验资&#xff0c;考试&#xff0c;仿真交易等环节&#xff0c;因此需要花费一定的时间来审核和激活账户&#xff0c;下文介绍期权开户需要多长时…

Mybatis-Plus 批量插入数据时报错 java.lang.Object Not Found TableInfoCache

文章目录 前言问题回溯排查过程总结 前言 报错堆栈信息如下&#xff0c;基本是mybatis-plus源码中的一些东西&#xff1a; com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: java.lang.Object Not Found TableInfoCache.at com.baomidou.mybatisplus.core.to…

安装wps后,回收站右键菜单出现“恢复误删文件”,通过注册表的方式去掉。

免费的才是最贵的。垃圾流氓软件。 这个东西点开会给你下载一个叫金山数据恢复大师的看起来不知道多少年的老古董。 win R 输入regedit打开注册表按照路径寻找&#xff1a;HKEY_CLASSES_ROOT\CLSID{645FF040-5081-101B-9F08-00AA002F954E}\shellex\ContextMenuHandlers 大功…

黑马JVM总结(五)

&#xff08;1&#xff09;方法区 它是所有java虚拟机 线程共享的区&#xff0c;存储着跟类的结构相关的信息&#xff0c;类的成员变量&#xff0c;方法数据&#xff0c;成员方法&#xff0c;构造器方法&#xff0c;特殊方法&#xff08;类的构造器&#xff09; 方法区在虚拟机…

makefile之链接静态库

make之链接静态库 (1)方法一: 指定静态库全路径和全名 APP_S_LIBS ./app_lib/libhost.a $(CC) $(CFLAGS) $(SRCOBJ) $(APP_S_LIBS) -o $(TARGET) APP_HEAD_DIR -I./include #APP_LIBS_DIR -L ./app_lib#APP_S_LIBS -lhost APP_S_LIBS ./app_lib/libhost.aCFLAGS $(APP_…

线性代数的本质(一)

文章目录 向量空间向量及其性质基与维数向量的坐标运算 《线性代数的本质》 - 3blue1brown 高中数学A版选修4-2 矩阵与变换 《线性代数及其应用》(第五版) 《高等代数简明教程》- 蓝以中 向量空间 In the beginning Grant created the space. And Grant said, Let there be vec…

ClickHouse进阶(十二):Clickhouse数据字典-2-字典类型

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术,IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅…

buuctf crypto 【[GXYCTF2019]CheckIn】解题记录

1.打开文件&#xff0c;发现密文 2.一眼base64&#xff0c;解密一下 3.解密后的字符串没有什么规律&#xff0c;看了看大佬的wp&#xff0c;是rot47加密&#xff0c;解密一下&#xff08;ROT5、ROT13、ROT18、ROT47位移编码&#xff09;

第一章 计算机系统概述 五、中断和异常、系统调用

目录 一、中断的作用 二、中断的类型 1、内中断&#xff08;异常&#xff09; 2、外中断 三、中断机制的基本原理 四、系统调用 1、定义&#xff1a; 2、与库函数的区别 3、按功能分类 4、作用 一、中断的作用 1、“中断”是让操作系统内核夺回CPU使用权的唯一途径 …

防火墙防火墙

什么是防火墙 防火墙是一种网络安全设备或软件&#xff0c;用于监控和控制网络流量&#xff0c;以保护网络免受未经授权的访问、恶意攻击和数据泄露等威胁。 防火墙的作用 1. 访问控制&#xff1a;防火墙可以根据规则和策略&#xff0c;限制和过滤网络流量&#xff0c;只允许经…