分享 15 个 Vue3 全家桶开发的避坑经验 上

简介: 分享 15 个 Vue3 全家桶开发的避坑经验 上


网络异常,图片无法展示
|

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

最近入门 Vue3 并完成 3 个项目,遇到问题蛮多的,今天就花点时间整理一下,和大家分享 15 个比较常见的问题,基本都贴出对应文档地址,还请多看文档~

已经完成的 3 个项目基本都是使用 Vue3 (setup-script 模式)全家桶开发,因此主要分几个方面总结:

  • Vue3
  • Vite
  • VueRouter
  • Pinia
  • ElementPlus

一、Vue3

1. Vue2.x 和 Vue3.x 生命周期方法的变化

文档地址:v3.cn.vuejs.org/guide/compo…

Vue2.x 和 Vue3.x 生命周期方法的变化蛮大的,先看看:

2.x 生命周期 3.x 生命周期 执行时间说明
beforeCreate setup 组件创建前执行
created setup 组件创建后执行
beforeMount onBeforeMount 组件挂载到节点上之前执行
mounted onMounted 组件挂载完成后执行
beforeUpdate onBeforeUpdate 组件更新之前执行
updated onUpdated 组件更新完成之后执行
beforeDestroy onBeforeUnmount 组件卸载之前执行
destroyed onUnmounted 组件卸载完成后执行
errorCaptured onErrorCaptured 当捕获一个来自子孙组件的异常时激活钩子函数

目前 Vue3.x 依然支持 Vue2.x 的生命周期,但不建议混搭使用,前期可以先使用 2.x 的生命周期,后面尽量使用 3.x 的生命周期开发。

由于我使用都是 script-srtup模式,所以都是直接使用 Vue3.x 的生命周期函数:

// A.vue
<script setup lang="ts">
import { ref, onMounted } from "vue";
let count = ref<number>(0);
onMounted(() => {
  count.value = 1;
})
</script>

每个钩子的执行时机点,也可以看看文档: v3.cn.vuejs.org/guide/insta…

2. script-setup 模式中父组件获取子组件的数据

文档地址:v3.cn.vuejs.org/api/sfc-scr…

这里主要介绍父组件如何去获取子组件内部定义的变量,关于父子组件通信,可以看文档介绍比较详细: v3.cn.vuejs.org/guide/compo…

我们可以使用全局编译器宏defineExpose宏,将子组件中需要暴露给父组件获取的参数,通过 {key: vlaue}方式作为参数即可,父组件通过模版 ref 方式获取子组件实例,就能获取到对应值:

// 子组件
<script setup>
    let name = ref("pingan8787")
    defineExpose({ name }); // 显式暴露的数据,父组件才可以获取
</script>
// 父组件
<Chlid ref="child"></Chlid>
<script setup>
    let child = ref(null)
    child.value.name //获取子组件中 name 的值为 pingan8787
</script>

注意

  • 全局编译器宏只能在 script-setup 模式下使用;
  • script-setup 模式下,使用宏时无需 import可以直接使用;
  • script-setup 模式一共提供了 4 个宏,包括:definePropsdefineEmitsdefineExposewithDefaults

3. 为 props 提供默认值

definedProps 文档:v3.cn.vuejs.org/api/sfc-scr… withDefaults 文档:v3.cn.vuejs.org/api/sfc-scr…

前面介绍 script-setup 模式提供的 4 个全局编译器宏,还没有详细介绍,这一节介绍 definePropswithDefaults

使用 defineProps宏可以用来定义组件的入参,使用如下:

<script setup lang="ts">
let props = defineProps<{
    schema: AttrsValueObject;
    modelValue: any;
}>();
</script>

这里只定义props属性中的 schemamodelValue两个属性的类型, defineProps 的这种声明的不足之处在于,它没有提供设置 props 默认值的方式。

其实我们可以通过 withDefaults 这个宏来实现:

<script setup lang="ts">
let props = withDefaults(
  defineProps<{
    schema: AttrsValueObject;
    modelValue: any;
  }>(),
  {
    schema: [],
    modelValue: ''
  }
);
</script>

withDefaults 辅助函数提供了对默认值的类型检查,并确保返回的 props 的类型删除了已声明默认值的属性的可选标志。

4. 配置全局自定义参数

文档地址:v3.cn.vuejs.org/guide/migra…

在 Vue2.x 中我们可以通过 Vue.prototype 添加全局属性 property。但是在 Vue3.x 中需要将 Vue.prototype 替换为 config.globalProperties 配置:

// Vue2.x
Vue.prototype.$api = axios;
Vue.prototype.$eventBus = eventBus;
// Vue3.x
const app = createApp({})
app.config.globalProperties.$api = axios;
app.config.globalProperties.$eventBus = eventBus;

使用时需要先通过 vue 提供的 getCurrentInstance方法获取实例对象:

// A.vue
<script setup lang="ts">
import { ref, onMounted, getCurrentInstance } from "vue";
onMounted(() => {
  const instance = <any>getCurrentInstance();
  const { $api, $eventBus } = instance.appContext.config.globalProperties;
  // do something
})
</script>

其中 instance内容输出如下:

网络异常,图片无法展示
|

5. v-model 变化

文档地址:v3.cn.vuejs.org/guide/migra…

当我们在使用 v-model指令的时候,实际上 v-bindv-on 组合的简写,Vue2.x 和 Vue3.x 又存在差异。

  • Vue2.x
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />

在子组件中,如果要对某一个属性进行双向数据绑定,只要通过 this.$emit('update:myPropName', newValue) 就能更新其 v-model绑定的值。

  • Vue3.x
<ChildComponent v-model="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event"/>

script-setup模式下就不能使用 this.$emit去派发更新事件,毕竟没有 this,这时候需要使用前面有介绍到的 definePropsdefineEmits 两个宏来实现:

// 子组件 child.vue
// 文档:https://v3.cn.vuejs.org/api/sfc-script-setup.html#defineprops-%E5%92%8C-defineemits
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
const emit = defineEmits(['update:modelValue']); // 定义需要派发的事件名称
let curValue = ref('');
let props = withDefaults(defineProps<{
    modelValue: string;
}>(), {
    modelValue: '',
})
onMounted(() => { 
  // 先将 v-model 传入的 modelValue 保存
  curValue.value = props.modelValue;
})
watch(curValue, (newVal, oldVal) => {
  // 当 curValue 变化,则通过 emit 派发更新
  emit('update:modelValue', newVal)
})
</script>
<template>
    <div></div>
</template>
<style lang="scss" scoped></style>

父组件使用的时候就很简单:

// 父组件 father.vue
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
let curValue = ref('');
watch(curValue, (newVal, oldVal) => {
  console.log('[curValue 发生变化]', newVal)
})
</script>
<template>
    <Child v-model='curValue'></Child>
</template>
<style lang="scss" scoped></style>

6. 开发环境报错不好排查

文档地址:v3.cn.vuejs.org/api/applica…

Vue3.x 对于一些开发过程中的异常,做了更友好的提示警告,比如下面这个提示:

网络异常,图片无法展示
|

这样能够更清楚的告知异常的出处,可以看出大概是 <ElInput 0=......这边的问题,但还不够清楚。 这时候就可以添加 Vue3.x 提供的全局异常处理器,更清晰的输出错误内容和调用栈信息,代码如下

// main.ts
app.config.errorHandler = (err, vm, info) => {
    console.log('[全局异常]', err, vm, info)
}

这时候就能看到输出内容如下:

网络异常,图片无法展示
|

一下子就清楚很多。 当然,该配置项也可以用来集成错误追踪服务 SentryBugsnag

推荐阅读:Vue3 如何实现全局异常处理?

7. 观察 ref 的数据不直观,不方便

当我们在控制台输出 ref声明的变量时。

const count = ref<numer>(0);
console.log('[测试 ref]', count)

会看到控制台输出了一个 RefImpl对象:

网络异常,图片无法展示
|

看起来很不直观。我们都知道,要获取和修改 ref声明的变量的值,需要通过 .value来获取,所以你也可以:

console.log('[测试 ref]', count.value);

这里还有另一种方式,就是在控制台的设置面板中开启 「Enable custom formatters」选项。

网络异常,图片无法展示
|

网络异常,图片无法展示
|

这时候你会发现,控制台输出的 ref的格式发生变化了:

网络异常,图片无法展示
|
更加清晰直观了。

这个方法是我在《Vue.js 设计与实现》中发现的,但在文档也没有找到相关介绍,如果有朋友发现了,欢迎告知~


目录
相关文章
|
5天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
107 64
|
5天前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
|
1月前
|
存储 JavaScript 前端开发
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
【10月更文挑战第21天】 vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
vue3的脚手架模板你真的了解吗?里面有很多值得我们学习的地方!
|
2月前
|
API
vue3知识点:provide 与 inject
vue3知识点:provide 与 inject
34 4
vue3知识点:provide 与 inject
|
23天前
|
JavaScript
Vue基础知识总结 4:vue组件化开发
Vue基础知识总结 4:vue组件化开发
|
27天前
|
JavaScript 前端开发 开发者
Vue 3中的Proxy
【10月更文挑战第23天】Vue 3中的`Proxy`为响应式系统带来了更强大、更灵活的功能,解决了Vue 2中响应式系统的一些局限性,同时在性能方面也有一定的提升,为开发者提供了更好的开发体验和性能保障。
54 7
|
28天前
|
前端开发 数据库
芋道框架审批流如何实现(Cloud+Vue3)
芋道框架审批流如何实现(Cloud+Vue3)
47 3
|
27天前
|
JavaScript 数据管理 Java
在 Vue 3 中使用 Proxy 实现数据双向绑定的性能如何?
【10月更文挑战第23天】Vue 3中使用Proxy实现数据双向绑定在多个方面都带来了性能的提升,从更高效的响应式追踪、更好的初始化性能、对数组操作的优化到更优的内存管理等,使得Vue 3在处理复杂的应用场景和大量数据时能够更加高效和稳定地运行。
43 1
|
27天前
|
JavaScript 开发者
在 Vue 3 中使用 Proxy 实现数据的双向绑定
【10月更文挑战第23天】Vue 3利用 `Proxy` 实现了数据的双向绑定,无论是使用内置的指令如 `v-model`,还是通过自定义事件或自定义指令,都能够方便地实现数据与视图之间的双向交互,满足不同场景下的开发需求。
47 1
|
29天前
|
前端开发 JavaScript
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef