Vue 3 新特性总结

2025-06-07

Vue 3 新特性总结

Vue-next(Vue 3)已经发布一段时间了。目前它处于候选发布阶段,这意味着开放 API 不会有太大变化。很高兴看到 Vue 已经稳定下来,可以顺利地融入我们的项目。

不得不说,Vue 2 已经足够惊艳了。但 Vue 3 的新功能很可能会让我们的项目更上一层楼。我猜 Vue 3 中最激动人心的功能莫过于 Composition API。尤雨溪本人也提到, Composition API 的设计灵感源自 React 的 Hooks。虽然 Hooks 和 Compositions 这两个 API 非常相似,但从代码层面来看,它们完全不同。我们暂且不讨论哪个更好或更有前景,因为我并不认为这两个框架哪个更胜一筹。

总而言之,很高兴看到 Vue 也能做到 React 能做到的事情。让我们仔细看看这些新功能。

TLDR;

访问https://pitayan.com/posts/vue-next-features/阅读原文。

1. 维特

这是尤雨溪的又一杰作,旨在替代Vue 开发中的Webpack (目前仅适用于 Vue)。正如其法语名称所暗示的那样,它的设计目标是快速。

Vite 入门

官方 repo 为我们提供了一种通过Vite创建 Vue 3 应用程序的简单方法。

Npm

$ npm init vite-app <project-name>
$ cd <project-name>
$ npm install
$ npm run dev
Enter fullscreen mode Exit fullscreen mode

$ yarn create vite-app <project-name>
$ cd <project-name>
$ yarn
$ yarn dev
Enter fullscreen mode Exit fullscreen mode

启动开发服务器

一切都发生在一眨眼的功夫。

 ❯ yarn dev
yarn run v1.22.4
$ vite
vite v1.0.0-rc.4

  Dev server running at:
  > Local:    http://localhost:3000/
  > Network:  http://192.168.3.2:3000/
  > Network:  http://10.80.67.216:3000/
Enter fullscreen mode Exit fullscreen mode

打开http://localhost:3000/

开发页面

vue-next-features

我创建了一个小应用程序来演示Vue 3 的新功能。如果你看一下项目,你会发现vue-next-featurespackage.json依赖项的简洁性会让你立刻爱上Vite。(我的意思是,谁不想从更简单的开始呢?)package.json

还有另一个Webpack捆绑在一起的 Vue 3 “Hello World” repo ( vue-next-webpack-preview ) 。它也是一个很好的游乐场。

vue-next-features

{
  ...,
  "dependencies": {
    "vite": "^1.0.0-rc.4",
    "vue": "^3.0.0-rc.5"
  },
  "devDependencies": {
    "@vue/compiler-sfc": "^3.0.0-rc.5"
  }
}
Enter fullscreen mode Exit fullscreen mode

vue-next-webpack-preview

{
  ...,
  "dependencies": {
    "vue": "^3.0.0-beta.2"
  },
  "devDependencies": {
    "@vue/compiler-sfc": "^3.0.0-beta.2",
    "css-loader": "^3.4.2",
    "file-loader": "^6.0.0",
    "mini-css-extract-plugin": "^0.9.0",
    "url-loader": "^4.0.0",
    "vue-loader": "^16.0.0-alpha.3",
    "webpack": "^4.42.1",
    "webpack-cli": "^3.3.11",¥
    "webpack-dev-server": "^3.10.3"
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Composition API

作为Vue.js最大的变化,Composition API 将成为你下一个最常用的功能。就像React Hooks一样,使用 Vue Composition API 将有助于获得更多的可定制性。

以下是 Vue 3 组合 API 的列表。(实际上还有更多……)

  • 反应性

    • computed reactive ref readonly
    • watch watchEffect unref toRefs
    • isRef isProxy isReactive isReadonly
    • customRef markRaw shallowReactive
    • shallowReadonly shallowRef toRaw
  • 生命周期钩子

    • onBeforeMount onBeforeUnmount onBeforeUpdate 
    • onMounted onUpdated onErrorCaptured 
    • onRenderTracked onRenderTriggered onUnmounted 
    • onActivated onDeactivated 

访问 Vue 3 官方文档了解有关这些 API 的更多信息。https
://v3.vuejs.org/api/composition-api.html

组件样式

在 Vue 2 中

使用配置模板定义组件内容。在 Vue 3 中,这种旧用法仍然可用。如果您更喜欢这种风格,可以继续使用。

<template>
  <button @click="count++">count: {{ count }}</button>
</template>

<script>
const multiplier = 2

export default {
  data () {
    return {
      count: 0
    }
  },
  computed: {
    result () {
      return this.count * multiplier
    }
  },
  mounted () {
    console.log(this.count)
  },
  watch: {
    count (val, oldVal) {
      console.log(val, oldVal)
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

在 Vue 3 中

要使用 Composition API,您需要setup在默认导出中添加一个属性。以下代码与上面的代码完全等效。

<template>
  <button @click="count++">count: {{ count }}</button>
</template>

<script>
import { computed, reactive, toRefs, onMounted, watch } from 'vue'

export default {
  setup () {
    const multiplier = 2

    const state = reactive({
      count: 0
    })

    const result = computed(() => {
      return state.count * multiplier
    })

    onMounted(() => {
      console.log(state.count)
    })

    watch(state.count, (val, oldVal) => {
      console.log(val, oldVal)
    })

    return {
      ...toRefs(state)
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

继续使用新的 API

您应该使用组合 API 而不是默认的 Vue 2 配置模板,原因有 4 个:

  • 增加源代码的可读性
  • 避免重复或冗余的逻辑
  • 将相似的逻辑分组
  • 重用逻辑

与 Vue 2 的配置风格相比,逻辑被精准地分解成更小的单元,以便您可以轻松地将相似的逻辑组合在一起。这样,也减少了跳转到不相关逻辑的机会。这无疑有助于提高生产力。

2. 高级反应性 API

我个人认为这与其他响应式 API 没什么不同。但它确实提供了处理诸如自定义钩子浅层修改等边缘情况的能力。根据 Vue 3 官方文档,它现在是基本响应式 API的一部分。

在Vue 组合 API文档中(是的,有一个仅针对组合 API 的文档),以下 API 被列为高级反应性 API

  • customRef:自定义钩子
  • markRaw:无法成为reactive
  • shallowReactive:对象的第一层reactive
  • shallowReadonly:对象的第一层readonly
  • shallowRef:对象的值不是reactive
  • toRaw:恢复reactive正常对象

你熟悉 吗Debounce?这里有一个 的官方演示customRef

import { customRef } from 'vue'

const useDebouncedRef = (value, delay = 200) => {
  let timeout
  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return value
      },
      set(newValue) {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
          value = newValue
          trigger()
        }, delay)
      },
    }
  })
}

export default {
  setup () {
    return {
      text: useDebouncedRef('some text')
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

3. v-enter-from / v-leave-from

在 Vue 2 中,<Transition>组件有助于处理组件animation/ transition。但组件属性v-enter-active v-enter v-enter-to对我来说相当模糊。有时我会搞不清楚哪个先发生。

现在在 Vue 3 中,这些过渡属性名称变得更加统一和直观。

  • v-enter=>v-enter-from
  • v-leave=>v-leave-from
<template>
  <transition name="fade">
    <div v-show="show">fade transition</div>
  </transition>
</template>

<script>
import { reactive, toRefs } from 'vue'
export default {
  setup () {
    const state = reactive({
      show: true
    })

    setTimeout(() => {
      state.show = false
    }, 1000)

    setTimeout(() => {
      state.show = true
    }, 2000)

    return {
      ...toRefs(state)
    }
  }
}
</script>

<style>
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.fade-enter-to,
.fade-leave-from {
  opacity: 1;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 2000ms;
}

</style>
Enter fullscreen mode Exit fullscreen mode

过渡顺序:

  1. v-enter-from(腹部)
  2. v-enter-active
  3. v-enter-to
  4. v-leave-from(V 离开)
  5. v-leave-active
  6. v-leave-to

我相信这更容易理解,不是吗?

4. 允许多个根元素

Vue 2 在多个根元素上会抛出错误。模板中的所有元素都必须嵌套在一个根元素内。

<!-- Error -->
<template>
  <div>pitayan</div>
  <div>blog</div>
</template>

<!-- One Root Element only -->
<template>
  <div>
    <div>pitayan</div>
    <div>blog</div>
  </div>
</template>

Enter fullscreen mode Exit fullscreen mode

Vue 3 移除了这种烦人的用法。我觉得当你真的不想把元素嵌套在“容器”父元素中时,这非常有用。有时你可能只需要把这些裸元素插入到正确的位置。

这与React Fragments类似,有助于缓解嵌套问题。

<!-- Vue 3 Multiple Root Element -->
<!-- Okay -->
<template>
  <div>pitayan</div>
  <div>blog</div>
</template>
Enter fullscreen mode Exit fullscreen mode

5.“过滤器”已弃用(已删除)

我想很多人会觉得这filters可能是 Vue.js 的一个很棒的功能。它确实在 Vue 的模板引擎中运行良好。(例如,数据格式化/计算等)。

让我们看看 Vue 3 文档如何解释filters删除的原因:

虽然这看起来很方便,但它需要一种自定义语法,打破花括号内的表达式“只是 JavaScript”的假设,这既有学习成本,也有实施成本。

我相信没有 对开发来说没什么坏处filters,尽管迁移到 Vue 3 可能会花费你额外的时间。在我的项目中, 的出现filters相当罕见,因为我可以轻松地用method或替换这个功能computed。因为在我看来,method/computed比 更易读filters

<template>
  <!-- Deprecated (removed) & Error -->
  <span>{{ count | double }}</span>

  <!-- If you have to use fiter, make it a function -->
  <span>{{ double(count) }}</span>
</template>

<script>
import { ref } from 'vue'

export default {
  // Not working
  filters: {
    double (val) {
      return val * 2
    }
  },
  setup () {
    const count = ref(1)
    return {
      count,
      double: val => val * 2
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

6. 新的异步组件:Suspense

这或许是 Vue 3 中唯一一个在正式发布后可能会有所改动的功能。它的灵感同样来自于React Suspense。所以在我看来,使用场景应该是一样的。

悬疑实验片

你还记得之前在 Vue 2 中是如何渲染异步数据的吗?我想答案应该是v-if“/” 。v-else

<template>
  <div>
    <div v-for="i in items" :key="i">{{ i }}</div>
    <div v-else>loading...<div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      items: null
    }
  },
  mounted () {
    this.items = await new Promise(resolve => {
      setTimeout(() => {
        return resolve(['one', 'two'])
      }, 3000)
    })
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

使用Suspense组件,你无需自己处理条件。通过设置defaultandfallback槽,Suspense组件将自动处理异步事件。

<template>
  <suspense>
    <template #default>
      <div v-for="i in items" :key="i">{{ i }}</div>
    </template>

    <template #fallback>
      Loading...
    </template>
  </suspense>
</template>

<script>
export default {
  async setup () {
    const items = await new Promise(resolve => {
      setTimeout(() => {
        return resolve(['one', 'two'])
      }, 3000)
    })

    return {
      items
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

7. 在其他地方显示:传送

这是基于React Portals 的另一个很酷的东西。它提供了将组件插入目标 DOM 节点的功能。

我们在 Vue 2 中插入自定义组件<body>(当然有一个 Vue 第三方插件PortalVue提供这样的功能):

import Vue from 'vue'

const Ctor = Vue.extends({
  template: `<div>hello world</div>`
})

const vm = new Ctor({ ... }).$mount()

document.body.appendChild(vm.$el)

Enter fullscreen mode Exit fullscreen mode

要在 Vue 3 中使用此功能,请包装目标组件<Teleport>并在属性中定义目标节点(querySelector)to

<template>
  <Teleport to="body">
    <div>Pitayan</div>
  </Teleport>
</template>
Enter fullscreen mode Exit fullscreen mode

8. 允许多个 v-model

v-model用于表单元素甚至自定义组件中的数据双向绑定。在 Vue 2 中,一个自定义组件v-model在标签中只能有一个。

<template>
  <my-input-form v-model="input" />
</template>
Enter fullscreen mode Exit fullscreen mode

Vue 3 消除了该限制并允许您拥有多个,v-model以便您可以为更多输入元素分别指定绑定。

<template>
  <my-input-form
    v-model:first="inputFirst"
    v-model:second="inputSecond"
    />
</template>
Enter fullscreen mode Exit fullscreen mode

9. 全局 API

Vue 3 提供了一些新的 API 来帮助我们更好地控制组件和实例。

创建应用程序

在 Vue 2 中,Vue可以用作构造函数来返回实例对象。在 Vue 3 中,你可以使用createApp函数来代替。两者的行为实际上是相同的。

// Vue 2
import Vue from 'vue'
import App from '@/src/App'

new Vue({
  el: '#app',
  components: {
    App
  }
})
Enter fullscreen mode Exit fullscreen mode
// Vue 3
import { createApp } from 'vue'
import App from '@/src/App'

const app = createApp(App)
Enter fullscreen mode Exit fullscreen mode

extend component那么像 mixin和 这样的全局方法怎么样directive

相同,但您需要使用实例方法。

// Global methods
app.extend()
app.component()
app.mixin()
app.directive()
Enter fullscreen mode Exit fullscreen mode

下一个刻度

我认为nextTick这是一个经常使用的 API,因为很多逻辑实际上是异步的,它们需要安排到下一个 DOM 更新周期。

在 Vue 2 中,nextTick是一个实例方法。

export default {
  ...,
  mounted () {
    this.$nextTick(() => {
      console.log('pitayan')
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

Vue 3 允许您将其用作nextTick独立函数。

// nextTick function type
export declare function nextTick(fn?: () => void): Promise<void>;
Enter fullscreen mode Exit fullscreen mode
// An official doc Example
import { nextTick } from 'vue'

export default {
  setup () {
    const message = ref('Hello, Pitayan!')

    const changeMessage = async newMessage => {
      message.value = newMessage
      await nextTick()
      console.log('Now DOM is updated')
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

其他辅助函数

当你需要额外的控件来处理更抽象的场景时,这些新的 API 将非常有用。我个人认为它们可以在第三方库中频繁使用。

  • h:返回虚拟节点
  • createRenderer:可用于跨环境目的的自定义渲染器
  • 定义组件:输入传入的对象
  • DefineAsyncComponent:必要时加载异步组件
  • resolveComponent:解析当前实例范围内的组件
  • resolveDynamicComponent:解析当前实例范围内的动态组件
  • resolveDirective:directive从当前实例范围获取
  • withDirectives:适用directiveVNode

结论

我很高兴也很荣幸能够见证 Vue.js 2.x => 3.x 的成长。Vue 团队总结了 Vue 2 原生无法实现的功能,并将其融入 Vue 3 中。我发现 Vue 3 中有很多我们熟悉的代码库。

不难看出,Vue 3 是一个更加稳健的框架。它提供了一种全新且更简单的源代码组织方式,同时代码体积更小、运行速度更快。借助 Vue 3Typescript及其新功能(例如 Composition API),项目结构可以与以往大不相同。我相信这对前端社区来说是一个积极的影响。

这就是 Vue 3 的新功能的全部内容。

如果您觉得这篇文章很棒,请分享到社交网络。感谢您的阅读。

参考


原文刊登于Pitayan.com

https://pitayan.com/posts/vue-next-features/

文章来源:https://dev.to/pitayan/vue-3-new-features-summary-2cie
PREV
帮助你的团队更加专注
NEXT
从初学者到向 HackerOne 提交 5 份报告