在此前我使用的前端框架是 Angular,使用过 TypeScript 后你就会讨厌 JS 了,我学习 Vue 时的最新版本是 2.5,相信大部分同学都不会认为 Vue 那样又细又长的代码很美观吧,简单看了一些网络博客后,我毅然决然引入了 TypeScript 进行开发,本文仅整理记录我自己遇到的一些坑。 使用 Cli 脚手架是一个比较方便的工具,这里需要注意的是@vue/cli和vue-cli是不一样的,推荐使用npm i -g @vue/cli安装。 安装完成后,可以直接使用vue create your-app创建项目,你可以选择使用默认配置亦或是自己手动选择配置,按提示一步一步向下走即可,它会根据你的选择自己创建比如tsconfig.json等等配置文件。这里推荐使用less开发样式,sass老是在安装的过程中出问题。 当然你也可以使vue ui命令启动一个本地服务,它是一个 Vue 项目管理器,提供了一个可视化的页面供你管理自己的项目,它的样子如下图所示,还是比较清新的。 使用 vue-property-decorator Vue 官方维护了 vue-class-component 装饰器,vue-property-decorator 则是在vue-class-component基础上增强了更多结合Vue特性的装饰器,它可以让 Vue 组件语法在结合了 TypeScript 语法后变得更加扁平化。 截止本文时间,vue-property-decorator共提供了 11 个装饰器和 1 个Mixins方法,下面用@Prop举个例子,是不是看起来引起极度舒适。 import { Vue, Component, Prop } from 'vue-property-decorator' @Component export default class YourComponent extends Vue { @Prop(Number) readonly propA: number | undefined @Prop({ default: 'default value' }) readonly propB!: string @Prop([String, Boolean]) readonly propC: string | boolean | undefined } // 上面的内容将会被解析成如下格式 export default { props: { propA: { type: Number }, propB: { default: 'default value' }, propC: { type: [String, Boolean] } } } 使用 Vuex 关于怎么使用Vuex此处就不再做过多说明了,需要注意的一点是,如果你需要访问$store属性的话,那么你必须得继承Vue类,坑的地方是在某些情况下即使你没有继承Vue,它也能通过编译,只有在程序运行起来的时候才报错。 class ExampleApi extends Vue { public async getExampleData() { if (!this.$store.state.exampleData) { const res = await http.get('url/exampleData'); if (res.result) { this.$store.commit('setExampleData', res.data); return res.data; } else { promptUtil.showMessage('get exampleData failed', 'warning'); } } else { return this.$store.state.exampleData; } } } 使用自己的配置(含代理) vue.config.js是一个可选的配置文件,如果项目的根目录中存在这个文件,那么它会被@vue/cli-service自动加载,它的配置项说明可以查看配置参考。 我们再开发过程中都会使用代理来转发请求,代理的配置也是在这个文件中,它的官方说明在devserver-proxy中,下面是一个简单的vue.config.js文件例子。 module.exports = { filenameHashing: true, outputDir: 'dist', assetsDir: 'asserts', indexPath: 'index.html', productionSourceMap: false, transpileDependencies: [ 'vue-echarts', 'resize-detector' ], devServer: { hotOnly: true, https: false, proxy: { "/statistics": { target: "http://10.7.213.186:3889", secure: false, pathRewrite: { "^/statistics": "", }, changeOrigin: true }, "/mail": { target: "http://10.7.213.186:8888", secure: false, changeOrigin: true } } } } 让 Vue 识别全局方法和变量 我们在项目中都会使用一些第三方 UI 组件,比如我自己就使用了 Element,但是在使用它的$message、$notify等方法时就直接报错了,究其原因就是$message等属性并没有在 Vue 实例中声明。 官方对此给出了很明确的解决方案,使用的是 TypeScript 的 模块补充特性,可以查看增强类型以配合插件使用。既然知道是因为没有声明导致的错误,那我们就给它声明一下好了,在src/shims-vue.d.ts文件中添加如下代码即可,如果没有该文件请自行创建。 看到网上也有一部分人说的是src/vue-shim.d.ts,反正不管是怎么命名这个文件的,它们的作用是一样的。 declare module 'vue/types/vue' { interface Vue { $message: any, $confirm: any, $prompt: any, $notify: any } } 这里顺道提一下,src/shims-vue.d.ts文件中的如下代码是为了让你的 IDE 明白以.vue结尾的文件是什么玩意儿。 declare module '*.vue' { import Vue from 'vue'; export default Vue; } 路由懒加载 Vue Router 官方有关于路由懒加载的说明,但不知道为什么官方给的这个说明在我的项目里面都没有生效,但使用require.ensure()按需加载组件可以生效。 // base-view 是模块名,写了相同的模块名则代码会被组织到同一个文件中 const Home = (r: any) => require.ensure([], () => r(require('@/views/home.vue')), layzImportError, 'base-view'); // 路由加载错误时的提示函数 function layzImportError() { alert('路由懒加载错误'); } 上面的方式会在编译的时候把文件自动分成多个小文件,编译后的文件会以你自己命名的模块名来命名,如果代码之间有相互依赖,依赖部分代码编译后的文件会以两个模块名相连后进行命名。 但是需要注意的是,这样拆分小文件之后引入了另外一个新的问题,因为客户端会缓存这些编译后的 js 文件,如果功能 A 同时依赖了a.js和b.js两个文件,但用户在使用其它功能时已经把a.js缓存到本地了,使用功能 A 时需要请求b.js文件,这时程序就很容易报错,因为此时在客户端这两个文件不是同一个版本,所以可能导致a.js调用b.js中的方法已经被删了,进而导致客户端页面异常。 关于引入第三方包 项目在引入第三方包的时候经常会报出各种奇奇怪怪的错误,这里仅提供我目前找到的一些解决办法。 /* 引入 jquery 等库可以尝试下面这种方式 只需要把相应的 js 文件放到指定文件夹即可 **/ const $ = require('@/common/js/jquery.min.js'); const md5 = require('@/common/js/md5.js'); 引入一些第三方样式文件、UI 组件等,如果引入不成功可以尝试建一个 js 文件,将导入语句都写在 js 文件中,然后再在main.ts文件中导入这个 js 文件,这个方法能解决大部分的问题。例如我先建了一个lib.js,然后在main.ts中引入lib.js就没有报错。 // src/plugins/lib.js import Vue from 'vue'; // 树形组件 import 'vue-tree-halower/dist/halower-tree.min.css'; import {VTree} from 'vue-tree-halower'; // 饿了么组件 import Element from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; // font-awesome 图标 import '../../node_modules/font-awesome/css/font-awesome.css'; import VueCookies from 'vue-cookies'; import VueJWT from 'vuejs-jwt'; Vue.use(VueJWT); Vue.use(VueCookies); Vue.use(VTree); Vue.use(Element); // src/main.ts import App from '@/app.vue'; import Vue from 'vue'; import router from './router'; import store from './store'; import './registerServiceWorker'; import './plugins/lib'; Vue.config.productionTip = false; new Vue({ router, store, render: (h) => h(App), }).$mount('#app'); 因为第三方包写的各有特点,在引入不成功的时候基本也只能是见招拆招,当然如果你的功底比较深厚,你也可以自己写一个index.d.ts文件,实在不行的话,那个特殊的组件不使用 TypeScript 来写也能解决,我目前还没有找一个可以完全解决第三方包引入错误的方法,如果您已经有相关的方法了,希望能与你一起探讨交流。
Read More ~