首页
Javascript
Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于
公司注册

Vue3对比Vue2,删除了哪些东西,有哪些改进和变化?

2022年11月22日 发布 阅读(1777) 作者:Jerman

一、工具上的变化

  • IDE
    建议使用vscode,官网也有讲 WebStorm
  • 语法检查
    • vue2推荐vscode vetur
    • vue3推荐vscode volar
    • 如果vetur和volar有同时安装,那么vue3需要禁用vetur
  1. // .vscode/settings.json
  2. {
  3. "vetur.validation.template": false,
  4. "vetur.validation.script": false,
  5. "vetur.validation.style": false
  6. }

二、vue源码上的变化

  • vue3源码使用了Typescript实现,更好的支持了Typescript https://www.typescriptlang.org/
  • Proxy 替换掉 Object.defineProperty
    • Proxy代理的是整个对象,Object.defineProperty只代理某些属性
    • Proxy可以监听对象上新增的属性,Object.defineProperty不可以
    • Proxy可以监听数组的新增修改,Object.defineProperty不可以(长度的变化都不行,导致数据的一些方法不能被监听,只能用$set)
  • 响应式的改变
    通过ref实现,速度更快,由refreactive替换写在data中的数据(底层也是要转换成ref或reactive的)
  • 引入了tree-shaking,减少了打包体积
  • 编译的优化,引入了Block概念,把节点分为了静态(不需要跟踪)和动态(需要跟踪)

三、新增内置组件/属性

四、生命周期函数

参考:https://cn.vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram

vue2 option apivue3 option apivue 3 composition api
beforeCreatebeforeCreate不再需要,代码可直接置于setup中
createdcreated不再需要,代码可直接置于setup中
beforeMountbeforeMountonBeforeMount
mountedmountedonMounted
beforeUpdatebeforeUpdateonBeforeUpdate
updatedupdatedonUpdated
beforeDestroy改为—> beforeUnmountonBeforeUnmount
destroyed改为—> unmountedonUnmounted
errorCapturederrorCapturedonErrorCaptured
-新增—> renderTrackedonRenderTracked
-新增—> renderTriggeredonRenderTriggered

五、minxin

六、模板

  • vue3中模板可以有多个根节点(div),vue2只能有1个
  • vue3中v-if和v-for可以写一起,v-if的优先级更高
  • vue3去掉了.sync,直接使用v-model即可

七、API

Vue2—->Vue3的变化细节

  1. //vue2
  2. const asyncComponent = () => import('./asyncComponent.vue')
  3. // 或者
  4. const asyncComponent = {
  5. component: () => import('./asyncComponent.vue')
  6. }
  1. //vue3 ,需要使用defineAsyncComponent 声明
  2. // ... 像使用其他一般组件一样使用 AsyncComp
  3. import { defineAsyncComponent } from 'vue'
  4. const AsyncComp = defineAsyncComponent(() => {
  5. // 必须返回一个Promise对象
  6. return new Promise((resolve, reject) => {
  7. // ...从服务器获取组件
  8. resolve(/* 获取到的组件 */)
  9. })
  10. })
  1. //vue2的component改成了loader
  2. //vue3 高级用法
  3. const AsyncComp = defineAsyncComponent({
  4. // 加载函数
  5. loader: () => import('./Foo.vue'),
  6. // 加载异步组件时使用的组件
  7. loadingComponent: LoadingComponent,
  8. // 展示加载组件前的延迟时间,默认为 200ms
  9. delay: 200,
  10. // 加载失败后展示的组件
  11. errorComponent: ErrorComponent,
  12. // 如果提供了一个 timeout 时间限制,并超时了
  13. // 也会显示这里配置的报错组件,默认值是:Infinity
  14. timeout: 3000
  15. })
  1. // vue2
  2. <template>
  3. <label>
  4. <input type="text" v-bind="$attrs" v-on="$listeners" />
  5. </label>
  6. </template>
  7. <script>
  8. export default {
  9. inheritAttrs: false
  10. }
  11. </script>
  1. //vue3
  2. <template>
  3. <label>
  4. <input type="text" v-bind="$attrs" />
  5. </label>
  6. </template>
  7. <script>
  8. export default {
  9. inheritAttrs: false
  10. }
  11. </script>
  1. // vue2
  2. const Comp = Vue.extend({
  3. props: ['username'],
  4. template: '<div>{{ username }}</div>'
  5. })
  6. new Comp({
  7. propsData: {
  8. username: 'Evan'
  9. }
  10. })
  1. // vue3必须使用createApp方法
  2. const app = createApp(
  3. {
  4. props: ['username'],
  5. template: '<div>{{ username }}</div>'
  6. },
  7. { username: 'Evan' }
  8. )
  • props 默认值函数不可访问this对象,但可以使用inject
  1. //vue3
  2. import { inject } from 'vue'
  3. export default {
  4. props: {
  5. theme: {
  6. default (props) {
  7. // `props` 是传递给组件的原始值。
  8. // 在任何类型/默认强制转换之前
  9. // 也可以使用 `inject` 来访问注入的 property
  10. // 使用inject后,实例中可直接使用this.theme调用
  11. return inject('theme', 'default-theme')
  12. }
  13. }
  14. }
  15. }
  • 自定义指令 https://v3-migration.vuejs.org/zh/breaking-changes/custom-directives.html
    created - 新增!在元素的 attribute 或事件监听器被应用之前调用。
    bind → beforeMount
    inserted → mounted
    beforeUpdate:新增!在元素本身被更新之前调用,与组件的生命周期钩子十分相似。
    update → 移除!该钩子与 updated 有太多相似之处,因此它是多余的。请改用 updated。
    componentUpdated → updated
    beforeUnmount:新增!与组件的生命周期钩子类似,它将在元素被卸载之前调用。
    unbind -> unmounted
  1. // vue3
  2. const MyDirective = {
  3. created(el, binding, vnode, prevVnode) {}, // 新增
  4. beforeMount() {},
  5. mounted() {},
  6. beforeUpdate() {}, // 新增
  7. updated() {},
  8. beforeUnmount() {}, // 新增
  9. unmounted() {}
  10. }
  • Data选项的变化
    • 不再支持直接使用Object,只接受返回objectfunction
  • emits变化
    emits可以跟props一样,可以声明组件可触发的事件(vue2不可以显性的声明)
  1. // vue3
  2. <template>
  3. <div>
  4. <p>{{ text }}</p>
  5. <button v-on:click="$emit('accepted')">OK</button>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. props: ['text'],
  11. emits: ['accepted']
  12. }
  13. </script>
  • 事件API
    • VUE3在实例中移除了 $on$off$once 方法,只保留了$emit
    • eventBus里可以实现$on$off$once 方法,不推荐使用(难以维护)
  1. // eventBus.js
  2. import emitter from 'tiny-emitter/instance'
  3. export default {
  4. $on: (...args) => emitter.on(...args),
  5. $once: (...args) => emitter.once(...args),
  6. $off: (...args) => emitter.off(...args),
  7. $emit: (...args) => emitter.emit(...args),
  8. }
  1. 替代Even Bus的方案
  1. Props 和事件应该是父子组件之间沟通的首选。兄弟节点可以通过它们的父节点通信。
  2. provide / inject 允许一个组件与它的插槽内容进行通信。这对于总是一起使用的紧密耦合的组件非常有用。
  3. provide / inject 也能够用于组件之间的远距离通信。它可以帮助避免“prop 逐级透传”,即 prop 需要通过许多层级的组件传递下去,但这些组件本身可能并不需要那些 prop
  4. Prop 逐级透传也可以通过重构以使用插槽来避免。如果一个中间组件不需要某些 prop,那么表明它可能存在关注点分离的问题。在该类组件中使用 slot 可以允许父节点直接为它创建内容,因此 prop 可以被直接传递而不需要中间组件的参与。
  5. 全局状态管理,比如 Pinia
  1. // vue3使用globalProperties 注册
  2. // main.js
  3. const app = createApp(App)
  4. app.config.globalProperties.$filters = {
  5. currencyUSD(value) {
  6. return '$' + value
  7. }
  8. }
  9. // 所有组合可使用
  10. <template>
  11. <h1>Bank Account Balance</h1>
  12. <p>{{ $filters.currencyUSD(accountBalance) }}</p>
  13. </template>
2.x 全局 API3.x 实例 API (app)
Vue.configapp.config
Vue.config.productionTip移除 (见下方)
Vue.config.ignoredElementsapp.config.compilerOptions.isCustomElement (见下方)
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use (见下方)
Vue.prototypeapp.config.globalProperties (见下方)
Vue.extend移除 (见下方)

所有其他不全局改变行为的全局 API 现在都是具名导出,文档见全局 API Treeshaking

  1. //vue2
  2. <!-- 键码版本 -->
  3. <input v-on:keyup.13="submit" />
  4. <!-- 别名版本 -->
  5. <input v-on:keyup.enter="submit" />
  6. Vue.config.keyCodes = {
  7. f1: 112
  8. }
  9. <!-- 键码版本 -->
  10. <input v-on:keyup.112="showHelpText" />
  11. <!-- 自定义别名版本 -->
  12. <input v-on:keyup.f1="showHelpText" />
  1. //vue3 直接使用键名,中线连接
  2. <!-- Vue 3 v-on 上使用按键修饰符 -->
  3. <input v-on:keyup.page-down="nextPage">
  4. <!-- 同时匹配 q Q -->
  5. <input v-on:keypress.q="quit">
  1. - 渲染函数 https://v3-migration.vuejs.org/zh/breaking-changes/render-function-api.html
  2. - 就一点`h`函数不再是从参数中获取,是从全局导入
  1. // Vue 3 渲染函数示例
  2. import { h } from 'vue'
  3. export default {
  4. render() {
  5. return h('div')
  6. }
  7. }
  1. <!-- 模板 -->
  2. <div id="red" v-bind="{ id: 'blue' }"></div>
  3. <!-- 结果 -->
  4. <div id="red"></div>
  1. - vue3中看先后顺序,在后面的覆盖前面的
  1. <!-- 模板 -->
  2. <div id="red" v-bind="{ id: 'blue' }"></div>
  3. <!-- 结果 -->
  4. <div id="blue"></div>
  5. <!-- 模板 -->
  6. <div v-bind="{ id: 'blue' }" id="red"></div>
  7. <!-- 结果 -->
  8. <div id="red"></div>
  1. // 不使用deep时,只有整个数组被替换才会触发watch
  2. // 在vue2时,watch数组不需要使用deep,在vue2中,deep只是用在Object上
  3. watch: {
  4. bookList: {
  5. handler(val, oldVal) {
  6. console.log('book list changed')
  7. },
  8. deep: true
  9. },
  10. }
  1. //vue2
  2. // 修改数据
  3. vm.msg = 'Hello'
  4. // DOM 还没有更新
  5. Vue.nextTick(function () {
  6. // DOM 更新了
  7. })
  1. // vue3
  2. // 需要引入
  3. // 以传递一个回调函数作为参数,或者 await 返回的 Promise
  4. <script>
  5. import { nextTick } from 'vue'
  6. export default {
  7. data() {
  8. return {
  9. count: 0
  10. }
  11. },
  12. methods: {
  13. async increment() {
  14. this.count++
  15. // DOM 还未更新
  16. console.log(document.getElementById('counter').textContent) // 0
  17. await nextTick()
  18. // DOM 此时已经更新
  19. console.log(document.getElementById('counter').textContent) // 1
  20. }
  21. }
  22. }
  23. </script>
  24. <template>
  25. <button id="counter" @click="increment">{{ count }}</button>
  26. </template>
版权声明:本站文章除特别声明外,均采用署名-非商业性使用-禁止演绎 4.0 国际 许可协议,如需转载,请注明出处