分享vue + vuex + typescript的一次项目代码重写

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/theoneEmperor/article/details/81124594

    俗话说一个项目,用代码重写十次,每次肯定收益匪浅。后续还会持续重构ssr等。

在vue里使用ts,一般分为两种情况:

  1.     在vue-cli 3.0以下的老项目中。
  2.     在最新的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-componentvue-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` 的运行效果将会跟 `[email protected]` 相同
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:

扫描二维码关注公众号,回复: 4899029 查看本文章
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-componentvue-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的github地址(敬请期待,srr中...)

个人感觉用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

猜你喜欢

转载自blog.csdn.net/theoneEmperor/article/details/81124594