听说Vue2.7支持Vue3语法

822 阅读4分钟

前言

前段时间将一个由vue-cli搭建的vue2项目进行了技术上的大调整,首先将构建工具调整为vite,并记录了升级过程中遇到的问题及解决方案,感兴趣的同学可以瞅一瞅我的另一篇文章——【vue-cli迁移vite,速度直接起飞 - 掘金】,做完升级之后就想,vite都用上了,能不能将vue2也进行下升级?后面经过分析,发现目前项目中使用的UI框架并不支持vue3,由于这个UI库是上面要求使用的,不太可能更换,所以如果升级到vue3的话风险会比较大。难道就只能到此结束吗?那肯定不是,不然怎那么会有这篇文章。

后面在一次偶然的机会或者同事大佬的提示下,发现vue2.7版本是可以支持大部分常用的vue3的语法的,这不是想使用vue3的语法而又不能升级版本的福音吗,于是我决定将开始不久的项目进行重构,在vue2.7版本下换成vue3语法,接下来将记录下是怎么使用的,给自己做个回顾和记录,不然过不了多久可能都忘了,同时也希望对有缘人能有所帮助。

vue3语法支持情况

支持的如下:

这里主要需要注意下不支持的点,如果想了解更详细的支持情况,可以看看版本发布文档:github.com/vuejs/vue/b…

怎么使用vue3语法

简单的了解了下支持情况,接下来看看具体怎么使用吧,有时候只有在使用中才能发现问题

基本用法

下面将以一个简单的示例来说明下setup、ref、reactive、computed、watch等的使用,这些都是vue2.7可以正常的支持的语法,这里就不作详细介绍了,想了解更多的可以瞅一瞅vue3的官方文档。

<script lang="ts" setup>  // setup
  import { ref, reactive, computed, watch } from 'vue';

  // props 的使用
  const props = defineProps<{
      id: string
  }>()
    
  // ref的使用
  const count = ref(0);
  console.log(count.value); // 输出 0
  count.value++; // 修改 count 的值为 1

  // reactive的使用
  const state = reactive({
    count: 0,
    message: 'Hello, Vue 3!',
  });
  console.log(state.count); // 输出 0
  state.count++; // 修改 count 的值为 1

  // computed 使用
  const plusOne = computed(() => count.value + 1)

  // watch使用
  watch(() => count.value, (val) => {
    state.count = val
  })

  // emits 触发自定义事件
  const $emits = defineEmits(['update'])
  function updateData() {
    // ...
    $emits('update')
  }

  // expose 暴露公共属性,方便外部调用
  function show(){
    // ...
  }
  defineExpose({
    show
  })
</script>

全局方法

在 Vue 3 中,可以通过 app.config.globalProperties 方法来定义全局方法

import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App);

app.config.globalProperties.$hello = function(name) {
  alert(`Hello, ${name}!`);
};

app.mount('#app');

很明显,上面这些方法vue2.7中应该是不支持的,那么需要怎么定义全局方法呢,我目前也没有找到比较好的方式,目前是直接挂在window下面的,应该问题不大

获取this(vue对象实例)

vue2中,我们到处都可以看到this的身影,也就是vue对象实例,但是在vue3中得setup中,正常情况下一般都是用不到this的,那么万一需要用怎么获取呢,请看示例

<script setup>
  import { getCurrentInstance } from 'vue'
  // proxy 就是vue实例
  const { proxy } = getCurrentInstance()
</script>

获取DOM元素的引用

在vue2中我们可以通过$refs来访问到DOM元素的引用,想必大家看完上面的获取this的方法已经有答案了

<template>
  <button ref="button">click me</button>
</template>
<script setup>
  import { getCurrentInstance } from 'vue'
  
  const { proxy } = getCurrentInstance()
  const buttonDom = proxy.$refs.button
</script>

上面的方式看起来挺不错的,没毛病,但是呢,人家都把this都藏起来了,你非得把它找出来,这不是找打吗,明显不合理,下面推荐另一种更优雅的方式

<template>
  <button ref="button">click me</button>
</template>
<script setup>
  import { ref } from 'vue'
  
  const button = ref(null) 
</script>

是不是很简单,只要声明一个和button的ref属性值同名的响应式变量就可以了,等页面渲染完就会关联上了

vue-router组合API(useRoute、useRouter等)

vue2.7需要使用useRoute和useRouter,对vue-router的版本有一定的要求,需要兼容vue2版本同时又又支持这两个组合api,还好vue-router比较友好,提供了这么一个版本,可能是为vue2.7量身定制的把。

可以使用vue-router的3.6.4版本,然后就可以愉快的使用useRoute和useRouter了

<script setup>
  import { useRoute, useRouter } from 'vue-router/composables'
  const $route = useRoute()
  const $router = useRouter()
</script>

useStore (vuex的组合api)

vuex就没有vue-router那么友好了,并没有提供既兼容vue2又支持组合api的版本,这时候就需要自己封装了,这里我直接去看了眼vuex的useStore的源码,发现是用provide和reject实现的,这里我们就不用其他花里胡哨的方法了,直接参考的人家方式就就行。

封装useStore方法

import store from './store'
// 这里还有n行代码...
new Vue({
    router,
    store,
    provide () {
        return {
            store
        }
    },
    render: h => h(App)
})
import { inject } from 'vue'

export function useStore (key?:string): any {
  return inject(key || 'store')
}

使用useStore

import { useStore } from '@/utils/vuexApi'
const $store = useStore()

结语

好了,暂时就想到这么些,今天就扯到这里吧,相信了解上面的这些基本使用,应该能满足大部分开发的需求了。