项目背景:项目背景:项目背景:一个以前的项目( 刚入职实习的时候写的,用的vuecli2 ),然后这次要添加修改东西,看着代码看的头大,冲动之下就重构了( 想打死自己,写的啥玩意 ),刚好用下最近刚学的typescript,从搭建开始,一步步更新记录下,怕自己之后忘了再回过头来看看。( 顺便说一句,用起来有点别扭,不过还是挺爽的,期待vue3.0... )刚入职实习的时候写的,用的vuecli2想打死自己,写的啥玩意顺便说一句,用起来有点别扭,不过还是挺爽的,期待vue3.0...一.项目搭建:一.项目搭建:一.项目搭建:使用命令
vue create news 创建项目配置自定义,贴一下我自定义的安装依赖
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
// 主目录


├── 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 配置
├── 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的配置项具体可以看官网自己配置: https://www.tslang.cn/docs/handbook/compiler-options.htmlhttps://www.tslang.cn/docs/handbook/compiler-options.html4.初步修改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: [],
},
}
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社区已经有很多大佬写好了,前人种树,后人乘凉什么是声明文件:https://github.com/xcatliu/typescript-tutorial/blob/master/basics/declaration-files.mdhttps://github.com/xcatliu/typescript-tutorial/blob/master/basics/declaration-files.md声明文件搜索地址: microsoft.github.io/TypeSearch/microsoft.github.io/TypeSearch/untils 文件夹(可以放一些常用的工具函数,节流、防抖、localStorage等)
untils这个里面我存放了一些工具函数,date函数,axios的封装等styles 文件夹
(存放全局scss文件)styles这里面除了初始化一些样式外,我还定义了一些常亮,例如导航栏的高度,颜色等,便于
好改router 文件夹(懒加载)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

}

},

]
}
/* 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
文件夹api
文件夹根据不同模块的接口,去建不同的文件三.vue中typescript的写法三.vue中typescript的写法三.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(){}
}

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使用中的问题四.typescript使用中的问题四.typescript使用中的问题1.获取refs 写法:
let layoutList:any = this.$refs.layout as HTMLDivElement
let layoutList:any = this.$refs.layout as HTMLDivElement2.引用插件,且找不到声明文件或引用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;
}
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'

import * as myJson from '../../../public/test.json'
使用
myJson.default3.计算属性
get age() {

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

return this.aTagDatasF.filter(item => item.visible)
}4.@prop@Prop()private datas!: any感叹号是非null和非undefined的类型断言,所以上面的写法就是对datas这个属性进行非空断言
5.引入vue组件时,后面必须加
.vue6.定义接口类型,前面加 I,例如,接口尽量定义类型,规范管理
interface IUserInfo{

name:string,

index:number
}
interface IUserInfo{

name:string,

index:number
}7.定义全局变量(可以用vuex取代)在.ts文件里面

export var User:IUserInfo={


name:'111',

index:996
}
export var User:IUserInfo={


name:'111',

index:996
}其他页面import ,然后 就可以获取到这个值8.强行让ts不检测
//@ts-ignore
下一行不检测
//@ts-ignore
下一行不检测五.开始改造页面代码(开始吐槽自己)五.开始改造页面代码(开始吐槽自己)五.开始改造页面代码(开始吐槽自己)槽点1:组件切换以前的代码(部分片段)改造后:用component
用is去动态判断就行



槽点2:对象赋值以前的代码(部分片段):改造后:
//这样写是因为initObj还有别的key

for(let i in this.obj){

if(this.initObj(i)!=undefined){

this.initObj[i]=this.obj[i]

}
}

//或者

写一个函数,如果key值一样就赋值
//这样写是因为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;
}

//片段,有十几个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]()}

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({})
}
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})
}

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

const {City,County}=this.sizeTop

private async getData() {


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