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


    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>
    
    • 1
    • 2
    • 3
    • 4

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

    2. 解构 reactive 对象

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

    <template>
      Counter: {{ state.count }}
      <button @click="add">Increasebutton>
     template>
    
    
     <script>
     import { reactive } from "vue";
     export default {
      setup() {
       const state = reactive({ count: 0 });
    
    
       function add() {
        state.count++;
       }
    
       return {
        state,
        add,
       };
      },
     };
     script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    <template>
      <div>Counter: {{ count }}div>
      <button @click="add">Increasebutton>
    template>
    
    <script>
    import { reactive } from "vue";
    export default {
      setup() {
        const state = reactive({ count: 0 });
    
        function add() {
          state.count++;
        }
    
        return {
          ...state,
          add,
        };
      },
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

    代码看起来比较相似,而且根据以前的表现,逻辑是可以正常执行的。但事实上,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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    但是 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    <script setup>
    import { ref } from 'vue'
    const object = { foo: ref(1) }
    script>
    <template>
      {{ object.foo + 1 }}  // [object Object]
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    4. Emitted 事件

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

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

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

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

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

    <script setup>
    const props = defineProps({
      foo: String
    })
    
    const emit = defineEmits(['change', 'delete'])
    // setup code
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    5. 声明组件选项

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

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

    <script>
      export default {
        name: 'CustomName',
        inheritAttrs: false,
        customOptions: {}
      }
    </script>
    
    <script setup>
      // script setup logic
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    6. 使用 Reactivity Transform

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

    7. 定义异步组件

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

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

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

    import { defineAsyncComponent } from 'vue'
     const asyncModal = defineAsyncComponent(() 
    => import('./Modal.vue'))
    
    • 1
    • 2
    • 3
    8. template 中使用不必要的包装元素
    
    <template>
      <div>
        <header>...header>
        <main>...main>
        <footer>...footer>
      div>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    <template>
      <header>...header>
      <main v-bind="$attrs">...main>
      <footer>...footer>
    template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    9. 生命周期函数

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

    10. 产品文档

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

    总结

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

    本文翻译自文章:

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

  • 相关阅读:
    网络安全(黑客)自学
    突破“三个九”!离子阱量子计算再创新高
    perl删除目录下过期的文件
    【Linux】权限管理
    私域增长 | 私域会员:9大连锁行业15个案例集锦
    【matplotlib基础】--绘图配置
    【访问控制】—>《熟练使用ACL进行上网行为管理》
    iOS开发之iOS15.6之后拉流LFLiveKit,画面模糊及16.1马赛克问题
    Python零基础入门篇 · 21】:构造函数、类属性和实例属性的访问
    【React】Lodash---groupBy() 分组
  • 原文地址:https://blog.csdn.net/anxin_wang/article/details/132809263