四.记一次用ts+vuecli4重构项目

2,721

项目背景:

一个以前的项目(刚入职实习的时候写的,用的vuecli2),然后这次要添加修改东西,看着代码看的头大,冲动之下就重构了(想打死自己,写的啥玩意),刚好用下最近刚学的typescript,从搭建开始,一步步更新记录下,怕自己之后忘了再回过头来看看。(顺便说一句,用起来有点别扭,不过还是挺爽的,期待vue3.0...

     

一.项目搭建:

  1. 使用命令   vue create news 创建项目
  2. 配置自定义,贴一下我自定义的安装依赖     

      ts+vuex+router这几个肯定是要的,这里的css我选择的是scss,unit测试也来一个

       之后一些的选项就自己选择

3. 搭建好后目录就是这样

├── public                          // 静态页面

├── src                             // 主目录

    ├── assets                      // 静态资源

    ├── components                  // 组件

    ├── views                       // 页面

    ├── App.vue                     // 页面主入口

    ├── main.ts                     // 脚本主入口

    ├── router.ts                   // 路由

    ├── shims-tsx.d.ts              // 相关 tsx 模块注入

    ├── shims-vue.d.ts              // Vue 模块注入

    └── store.ts                    // vuex 配置

├── tests                           // 测试用例

├── .eslintrc.js                    // eslint 相关配置

├── .gitignore                      // git 忽略文件配置

├── babel.config.js                 // babel 配置

├── postcss.config.js               // postcss 配置

├── package.json                    // 依赖

└── tsconfig.json                   // ts 配置

想着为了以后更好的维护,就修改了一下目录结构

├── public                          // 静态页面

├── src                             // 主目录

    ├── api                         // 接口

    ├── assets                      // 静态资源

    ├── filters                     // 过滤

    ├── store                       // vuex 配置

    ├── styles                      // 样式

    ├── utils                       // 工具方法(axios封装,全局方法等)

    ├── views                       // 页面

    ├── App.vue                     // 页面主入口

    ├── main.ts                     // 脚本主入口

    ├── router.ts                   // 路由

    ├── shime-global.d.ts           // 相关 全局或者插件 模块注入

    ├── shims-tsx.d.ts              // 相关 tsx 模块注入

    ├── shims-vue.d.ts              // Vue 模块注入, 使 TypeScript 支持 *.vue 后缀的文件

├── tests                           // 测试用例

├── .eslintrc.js                    // eslint 相关配置

├── postcss.config.js               // postcss 配置

├── .gitignore                      // git 忽略文件配置

├── babel.config.js                 // preset 记录

├── package.json                    // 依赖

├── README.md                       // 项目 readme

├── tsconfig.json                   // ts 配置

└── vue.config.js                   // webpack 配置

tsconfig.js是ts的配置项

具体可以看官网自己配置:www.tslang.cn/docs/handbo…

4.初步修改vue.config.js

const path = require("path");
const webpack = require('webpack');

function resolve(dir) {
  return path.join(__dirname, dir)
}
const router='http://xxx.xxx.xxx'

module.exports = {
  publicPath: "./",    //基本路径
  outputDir: 'dist',  //打包时生成的文件夹
  lintOnSave: process.env.NODE_ENV === 'development',  
  productionSourceMap: process.env.NODE_ENV === 'development', 
  devServer: {
    port: 8080,
    open: true,
    proxy: {
      '/test': {
        target: router,
        changeOrigin: true
      }
    }
  },
  configureWebpack: {
    name: process.env.VUE_APP_NAME,
    resolve: {
      alias: {
        '@': resolve('src'),
      }
    },
    externals: {},
    plugins: [],
  },
}

至此,项目初步搭建完成,然后就开始封装安装插件

二. 安装插件和基本内容填充

这里我使用 的element-ui,echarts, babel-polyfill,jquery等

这里有个注意的,在typescript 中使用jquery,echarts等插件的 时候,必须要安装对应的声明
文件,当然typescripe社区已经有很多大佬写好了,前人种树,后人乘凉

什么是声明文件:

github.com/xcatliu/typ…

声明文件搜索地址:microsoft.github.io/TypeSearch/


  • untils文件夹(可以放一些常用的工具函数,节流、防抖、localStorage等)                    
      这个里面我存放了一些工具函数,date函数,axios的封装等
  • styles文件夹  (存放全局scss文件)

      这里面除了初始化一些样式外,我还定义了一些常亮,例如导航栏的高度,颜色等,便于          好改

  •   router文件夹(懒加载)
     因为这个系统权限之类的并没有很复杂,路由也不是很多,就没有按模块引入,就直接写了。

 /* webpackChunkName: "login" */   /*这里名字是什么,打包出来的名字就是什么*/ 
{
    path: '/',
    name: 'login',   
    component: () => import(/* webpackChunkName: "login" */ '@/views/login/index.vue'),
    meta: {
      title:'登录页'
      keepAlive: false,
    }
  },
  {
    path: "/home",
    name: "home",
    redirect: "/homepage",       
    component: () => import(/* webpackChunkName: "home" */"@/views/Home.vue"),
    children: [
      {
        path: "/homepage",
        component: () => import(/* webpackChunkName: "homepage" */ "@/views/homepage/index.vue"),
        name: "homepage",
        meta: {
          title: "首页", keepAlive: true
        }
      }, 
    ]
}

  • api  文件夹

  根据不同模块的接口,去建不同的文件

三.vue中typescript的写法

typescript的写法和vue差不多,只是script的区别,例:

import { Component, Prop, Vue, Watch } from 'vue-property-decorator'
@Component({  
    name: 'homepage', 
    components: {}
})

export class MyComponent extends Vue {  
 @Prop({ default: '' }) private name!: string 
 @Watch('name', { deep: true })  
 changeName(newVal,olVal){}

   //data
   private count:number=5
   private arr:string[]=[]
   mounted(){}

   //methods
    private test(){}
}

四.typescript使用中的问题

1.获取refs 

写法:

let layoutList:any = this.$refs.layout as HTMLDivElement

2.引用插件,且找不到声明文件或引用Json文件

在shims-vue.d.ts 文件中声明,再在组件中引用

declare module "*.json" { 
    const value: any;  
    export default value;
}
declare module "vue-count-to" {  
    const count: any;  
    export default count;
}

页面里面

import * as myJson from '../../../public/test.json'

使用  myJson.default

3.计算属性

get  age() { 
    return this.aTagDatasF.filter(item => item.visible)
}

4.@prop

@Prop()private datas!: any

感叹号是非null和非undefined的类型断言,所以上面的写法就是对datas这个属性进行非空断言

5.引入vue组件时,后面必须加  .vue

6.定义接口类型,前面加 I,例如,接口尽量定义类型,规范管理

interface IUserInfo{
   name:string,
   index:number
}

7.定义全局变量(可以用vuex取代)

在.ts文件里面  

export var User:IUserInfo={    
    name:'111',
    index:996
}

其他页面import ,然后 就可以获取到这个值

8.强行让ts不检测

//@ts-ignore    下一行不检测


五.开始改造页面代码(开始吐槽自己)

槽点1:组件切换

以前的代码(部分片段)


改造后:用component   用is去动态判断就行  

<div class="haveClick>
   <component :is="echartsIndex" :obj="obj"/>
</div>


槽点2:对象赋值

以前的代码(部分片段):


改造后:

//这样写是因为initObj还有别的key

for(let i in this.obj){
   if(this.initObj(i)!=undefined){ 
      this.initObj[i]=this.obj[i]
   }
}

//或者   
 写一个函数,如果key值一样就赋值


槽点3:switch case 判断

之前的代码:

 //片段,有十几个case

optionList:['饼图','柱状图','折线图','...']

筛选下拉后,aa为index
switch (aa) {
       case 0:  this.getData() break;
       case 1:  this.avgBqzs() break;
       case 2:  this.areaCount() break;
       case 3:  this.yiqing() break;
       case 4:  this.avgFinish() break;
  }

修改后:

private optionList=[{
   title:'饼图',  
   type:'getData'
},{ 
   title:'柱状图',
   type:'avgBqzs'}
 ......
] 
下拉后,用change事件获取  item (这里就不获取index了)
例如:
changeSelect(item:any){
    //当然这里不能通过ts的编译   @ts-ignore
   this[item.type]()}

六.个人项目规范

1.尽量不要使用for,使代码观赏性更高

   forEach 遍历 , map转换,filter 过滤

2.调接口使用 尽量 async和await来调用接口

例如:

private async getData() {   
   const { data } = await getTransactions({})
}

3.只需要部分筛选条件的时候用解构去获取值

public sizeTop={
  id:'',
  City:'',
  County:'',
  time:''
}

const {City,County}=this.sizeTop

 private async getData() {    
    const { data } = await getTransactions({City,County})
 }


 路漫漫其修远兮,吾将上下而求索

 希望早日成为大佬