分享vue + vuex + typescript的一次项目代码重写
俗话说一个项目,用代码重写十次,每次肯定收益匪浅。后续还会持续重构ssr等。在vue里使用ts,一般分为两种情况: 在vue-cli 3.0以下的老项目中。 在最新的vue-cli 3.0中。vue-cli 3.0在最新的vue-cli 3.0中使用typescript,可以说是非常方便了,因为添加了对ts的支持,用vue create 项目时,选第二项自定义...
俗话说一个项目,用代码重写十次,每次肯定收益匪浅。后续还会持续重构ssr等。
在vue里使用ts,一般分为两种情况:
- 在vue-cli 3.0以下的老项目中。
- 在最新的vue-cli 3.0中。
vue-cli 3.0
在最新的vue-cli 3.0中使用typescript,可以说是非常方便了,因为添加了对ts的支持,用vue create 项目时,选第二项自定义配置添加对ts的支持就行了,另外别忘了把ts-lint语法检测也加上。至于如何安装vue-cli 3.0,去官方文档看下就知道了。如果你想把这种配置作为默认配置,文档也给出了相应的配置如下,这样你直接点第一个选项就会自动配置了。
被保存的 preset 将会存在用户的 home 目录下一个名为
.vuerc
的 JSON 文件里。如果你想要修改被保存的 preset / 选项,可以编辑这个文件。在项目创建的过程中,你也会被提示选择喜欢的包管理器或使用淘宝 npm 镜像源以更快地安装依赖。这些选择也将会存入
~/.vuerc
。
项目初始化完后,就可以开箱即用了。看它的package.json文件,typescirpt 以及ts-loader帮你配置好了,还有vue-class-component,vue-property-decorator(点击进入github地址查看文档)这两个添加vue对ts支持的插件也安装好了,后者是前者的拓展版,一般选择后面那个即可,tsconfig.json和.d.ts文件也配置好了,差不多例子也会帮你写好了。当然例子所涉及的是远远不够的,可以去这两个插件的github仓库看下文档,使用起来非常简单,差不多是把以前vue那种黑盒子的写法去掉了一层包装加上了一层语法修饰器。详细的配置就放到下面的vue-cli 3.0以下步骤中写吧,也不用这么累赘了,毕竟下面的需要手动去配置。
vue-cli 3.0以下
首先初始化一个vue-cli 2.0的项目,文档也给出了相应的方法:
Vue CLI 3 和旧版使用了相同的
vue
命令,所以 Vue CLI 2 (vue-cli
) 被覆盖了。如果你仍然需要使用旧版本的vue init
功能,你可以全局安装一个桥接工具:npm install -g @vue/cli-init # `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同 vue init webpack my-project
没什么特殊要求,一路回车就好了,初始完项目,打开package.json文件看下其依赖,是不是特别的多,在看下script下的dev命令,是基于webpack-dev-server,也就是还是使用webpack加vue-loader就构成了vue-cli 2.0,所以插件需要一个一个装,并自动配置在package.json里。接下来就安装各种依赖了。
npm install typescript ts-loader --save-dev
装好之后,如何配置的教程,在ts-loader的npm包文档和ts的官方文档中写的很详细,下面我说说我自己重构项目所用到的吧!
先要把ts-loader配置进webpack中,去webpack.config.js用vue-cli2.0也就是build文件夹里找到webpack.base.conf.js:
resolve: {
extensions: ['.js', '.vue', '.json', '.ts'], // 这里加入.ts文件的解析,如果使用了tsx,一并加上
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
然后添加ts-loader:
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
appendTsSuffixTo: [/\.vue$/],
}
},
由于使用了语法检测,所以还需要这个文件里配置,再把入口文件改成.ts,去src目录下面把main.js改成main.ts:
const createLintingRule = () => ({
test: /\.(js|vue|ts|tsx)$/, // 配置好ts,tsx的语法检测支持
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
entry: {
app: './src/main.js' //改成.ts
},
接下来要把项目重新运行起来,就要去ts官方文档看看了。同上讲下项目所涉及到的。
TypeScript使用tsconfig.json
文件管理工程配置,所以需要在vue-cli第一层文件中加上这个文件。
文件的配置在ts官网项目配置也是做了很耐心的讲解,下面我讲下我所写的吧。
// tsconfig.json
{
// 需要编译的文件
"include": [
"src/**/*"
],
// 需要忽略编译的文件
"exclude": [
"node_modules"
],
// 编译器
"compilerOptions": {
// 包含的类型声明文件路径列表
"typeRoots": [
"node_modules/@types"
],
// 以严格模式解析
"strict": true,
// 允许从没有设置默认导出的模块中默认导入
"allowSyntheticDefaultImports": true,
// 启用装饰器
"experimentalDecorators": true,
// 禁用函数参数双向协变检查。
"strictFunctionTypes": false,
// 允许编译javascript文件
"allowJs": true,
// 采用的模块系统
"module": "esnext",
// 编译输出目标 ES 版本
"target": "es5",
// 如何处理模块
"moduleResolution": "node",
// 在表达式和声明上有隐含的any类型时报错
"noImplicitAny": true,
// 编译过程中需要引入的库文件的列表。
"lib": [
"dom",
"es5",
"es6",
"es7",
"es2015.promise"
],
"sourceMap": true,
// 给错误和消息设置样式,使用颜色和上下文。
"pretty": true
}
}
compilerOptions选项可以按照它给那个列表按需求加入,比如添加一些代码常量检测之类的。
如果你的项目里要使用一些npm包,第三方插件之类的,要为它们在ts中创建申明文件,比如你使用了vue。则需要创建个vue.vue-shims.d.ts。
declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
详细使用可以看下文档。
然后把上面提到的vue-class-component,vue-property-decorator(点击进入github地址查看文档)这两个插件装好就可以了,编写规则在它们的github仓库有说明,后者是前者的拓展版,一般选择后面那个即可。
到这里基本上就能疯狂的撸ts代码了,是不是感觉很刺激,个人还是推荐直接用vue-cli 3.0,先别说对ts的支持,整个项目看起来也是非常的干净。
下面我贴几部分用ts写的.vue文件作为参考吧!详细的还请各位大爷移步github仓库查看。
<template>
<div class="hello">
<form id="loginFrom" method="get" action="#" @submit.prevent>
<div class="input" id="nkdiv">
...
<div id="login-btn">
<my-button
:disabled="button.disabled"
:value="button.value"
:btnStyle="button.btnStyle"
@click.native="login"
/>
</div>
<router-link to="/reset"><span class="button">忘记密码?</span></router-link>
<router-link to="/register"><span class="button" id="register-btn">注册新用户</span></router-link>
</form>
</div>
</template>
<script lang='ts'>
import { Vue, Component } from "vue-property-decorator";
/**
* 这里使用一个vuex-class的插件,其实它并不支持用class类去写vuex,只是单纯的做了下vuex对ts的支持而已,
* https://github.com/ktsn/vuex-class
* 所以我自己做了一下简单的封装,让vuex拥有继承属性,但是在它github的下面有我真大佬写的vuex-class.js,是
* 支持类的写法的,欢迎大家去查看。https://github.com/lzxb/vuex-class.js
*/
// 这里用的是装饰器,分别对应vuex里面那几个map...的映射方法
import { Action, Mutation, Getter, namespace } from 'vuex-class';
import { Toast } from '../common/comjs';
// 表示连接的是login module。
const loginModule = namespace('login');
@Component({
components: {
// 这里写你引用的组件
},
/*由于vue-property-decorator并没有开放新增属性的权限,所以你使用的与之前data,methods等同级
的属性,只放到这里面才能生效,这里就相当与不用ts写的那个export里的环境,但是写在这里面,底下类
里的this上有该属性,但是拿不到*/
})
export default class login extends Vue {
// 表示映射的是login模块下mutation里的$isEmpty方法,其他类推
@loginModule.Mutation('$isEmpty') $isEmpty: any;
@loginModule.Getter('_isEmpty') isEmpty: any;
@loginModule.Action('userLogin') userLogin: any;
@loginModule.Mutation('$assignParams') $assignParams :any;
@loginModule.Getter('_res') res: any;
nickname: string = '';
password: string = '';
button: MyButton.Button<MyButton.BtnStyle> = {
disabled: false,
value: '登陆',
btnStyle: {
width: '7.75rem',
height: '1.175rem',
fontSize: '0.5rem'
}
}
created () {
if (!this.$route.query.nickname) return;
this.nickname = this.$route.query.nickname
}
async login () {
let params = {
nickname: this.nickname,
password: this.password
}
this.$isEmpty(params);
if (this.isEmpty) return Toast('', '用户名密码不能为空');
this.$assignParams(params);
this.button.disabled = true;
await this.userLogin();
setTimeout(() => {
this.button.disabled = false;
}, 1000);
if (this.res.data.token) {
...
}
Toast('', this.res.data);
}
}
基于vue-cli3.0的github地址(项目正在重构中,欢迎fork参与,讨论)
基于vue-cli2.0+ssr+pwa的github地址(使用了pwa离线缓存技术,欢迎start)
个人感觉用ts之后,代码风格很爽,代码提示齐全,基本只要在那条链上,只要一路点点点就可以写完了,用js的话时常会写错函数名,变量名之类的,因为提示很少。可以贴一段代码出来看看,真的贼爽。下面是vuex类的写法,特别推荐狼族大佬的vuex-class.js插件。
class View extends BaseLoaderData<ChatRoom.View.RequestParams, string> {
readonly namespaced: boolean = true;
public readonly state: ChatRoom.View.State = {
params: {
id: ''
},
res: { code: 0, data: '' },
requestStatus: 'unrequest'
};
async saveView(): Promise<this> {
this.$RequestStart();
const res = await this.api.saveView(this.state.params);
this.$RequestSuccess(res);
return this;
}
}
class ChatRoom extends VuexClass {
readonly namespaced: boolean = true;
articList: ArticList;
view: View;
modules: {
articList: ArticList;
view: View;
};
constructor() {
super(new chatroom());
this.articList = new ArticList();
this.view = new View(new chatroom());
this.modules = {
articList: this.articList,
view: this.view
};
}
}
export default ChatRoom;
欢迎交流,如果觉得有帮助,欢迎start。
更多推荐
所有评论(0)