Vue2+TypeScript+CompositionAPI实践

4,000 阅读3分钟

前言

本文介绍用vue2.6x+TypeScript+CompositionAPI开发web页面。

选择vue2,是因为我们的网页需要支持IE11,但是同时,我们又非常向往vue3那种组合式API的开发方式,所以我们用上@vue/composition-api这个插件。

如果条件允许,请直接上vue3,毕竟本文的这个方案,很多vue3的优秀新功能都没有,都算不上平替。都2022年了,还不用vue3?本文的方案也算是一种无奈之举。

最后,为了进一步写出规范的代码,减少出错的可能,我们再用上TypeScript,TypeScript的使用,处理更好的类型判断,最最重要的,是更好的面向接口编程。

将会学到

  • vue2+TypeScript
  • vue2的组合式API插件@vue/composition-api

开始实践

创建vue2 的ts项目

首先我们用vue-cli创建一个vue2的ts项目,创建时选择自定义,一路勾选上TypeScript、ESLint、vue2。这样,我们就得到了vue2+TypeScript的工程。

引入组合式API

安装@vue/composition-api。

npm install --save--dev @vue/composition-api

在main.ts加入@vue/composition-api插件。

import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)

改写.vue文件的ts代码。

使用defineComponent定义组件,以HomeView为示例。

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <h2>{{ dataMsg }}</h2>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent } from '@vue/composition-api'

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: String
  },
  setup (props, context) {
    console.log('context', context)
    const dataMsg = ref('This is data msg')
    return {
      dataMsg
    }
  }
})
</script>

使用组合式API的注意事项

使用defineComponent为vue实例提供更好的类型推导

export default {}{}是简单的Object类型,ts无法针对性的提示我们vue组件需要哪些属性,export default defineComponent({}){}作为defineComponet的参数,通过对参数的类型提示,可以实现对vue组件的类型提示。

具体原理参考这篇文章Vue 中的 defineComponent

@vue/composition-api和vue3组合式api相比的限制

参考限制

getCurrentInstance不总是能获取到

getCurrentInstance用于访问当前内部组件的实例,但是不总是能访问的到。

WARNING

getCurrentInstance 只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用 getCurrentInstance。请不要把它当作在组合式 API 中获取 this 的替代方案来使用。

getCurrentInstance 只能setup生命周期钩子中调用。

参考下面的例子:

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance() // 有效

    const id = useComponentId() // 有效

    const handleClick = () => {
      getCurrentInstance() // 无效
      useComponentId() // 无效

      internalInstance // 有效
    }

    onMounted(() => {
      getCurrentInstance() // 有效
    })

    return () =>
      h(
        'button',
        {
          onClick: handleClick
        },
        `uid: ${id}`
      )
  }
}

在组合式api中是用vue-router

由于setup中没有this,vue-router4.x给vue3提供了额外的方法可以获取router和route。

//vue3 + vue-router4.x
import { useRouter, useRoute } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    const route = useRoute()

    function pushWithQuery(query) {
      router.push({
        name: 'search',
        query: {
          ...route.query,
        },
      })
    }
  },
}

但是在vue2的vue-router3.x中没有相关的方法,我们可以自己export出一个 useRouter和useRoute方法,暴露出router和route。

//vue2 + @vue/composition-api + vue-router3.x
import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from './routes';

Vue.use(VueRouter);

const router = new VueRouter({
  routes,
});

export const useRouter = () => router;
export const useRoute = () => router.currentRoute;

export default router;

总结

该方案作者也是刚刚用起来,具体还会遇到什么坑,作者遇到再记录下,会继续补充这个文档,敬请关注。。。

参考文献

@vue/composition-api

vue3组合式API

Vue Router 和 组合式 API

Vue 中的 defineComponent