由于vue3.0已经发布beta版本,vue3.0将会支持typescript,加上之前angular2.0已经支持typescript。纵观几个框架,TS已经是一个趋势。能够熟练掌握TS并可以应用到项目中去,就可以成为前端开发中的优势。因为vue2.0对TS不太友好,所以就一直搁置没有去重构。vue3.0在休息时间也准备重构一下自己得项目,在实践中不断摸坑。

1.使用vue-cli快速搭建项目

本人工作项目中使用得vue-cli3,所以打算用vue-cli3脚手架来搭建整个项目,与vue-cli2不同的是webpack集成到vue.config.js里面了,所以还是比较方便得,当然萝卜白菜各有所爱,完全看自己的喜欢怎么舒服怎么来了。
1.初始化项目以及配置项
在这里插入图片描述
在这里插入图片描述
安装相对应得配置项
在这里插入图片描述
然后等待自动安装,等到搭建完之后,大致框架结构就是这样。

2.目录文件说明

* public: 静态资源文件
* node_modules: 安装的依赖
* src:项目源码
   - api: 存放所有的api请求,按照模块编写,入口文件为`index.js`
   - assets:静态文件目录
   - components:公共组件目录,目标命名为大驼峰,自动注册
   - store:vuex目录 
   - router:项目主路由
   - views:项目html文件
   - App.vue: 页面入口
   - main.ts: 脚本入口
   - shims-tsx.d.ts: 相关tsx模块注入
   - shims-vue.d.ts: Vue 模块注入
* .env.development:开发环境变量文件
* .env.production:生产环境变量文件
* .env.test:测试环境变量文件
* babel-config.js: babel配置
* package.json: 依赖
* tsconfig.json: ts依赖
* vue.config.js:项目webpack集成配置文件 (自己创建 )

项目中vue.config.js文件 借鉴大佬的vueconfig.js配置

const path = require('path')

function resolve(dir) {
   return path.join(__dirname, dir)
}

const webpack = require('webpack')
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const LodashModuleReplacementPlugin = require("lodash-webpack-plugin");
const isPro = process.env.NODE_ENV === 'production';
module.export = {
   publicPath: "./",//公共路径
   outputDir: 'dist',//打包输出文件目录
   productionSourceMap: false,
   lintOnSave: false,//
   devServer: {
       overlay: {
           warning: false,
           errors: false
       },
       // port: PORT, //端口号
       https: false,
       hotOnly: false,
       proxy: { // 配置跨域
           '/api': {
               //要访问的跨域的api的域名
               target: `${DEV_URL}/`,
               ws: true,
               secure: false,
               changOrigin: true,
               pathRewrite: {
                   '^/api': ''
               }
           }
       },
   },
   chainWebpack: () => { },
   configureWebpack:config=>{
       config.resolve = {
           extensions: ['.js', '.vue', '.json', ".css"],
           alias: {
               'vue$': 'vue/dist/vue.esm.js',
               '@': resolve('src'),
               "assets": resolve('src/assets')
           }
       }
       if (isPro) {
           return {
               plugins: [
                   //使用包分析工具
                   new BundleAnalyzerPlugin()
               ]
           }
       }
       if (process.env.NODE_ENV === 'production') {
           config.plugins.push(
               new CompressionWebpackPlugin({
                   filename: '[path].gz[query]',
                   algorithm: 'gzip',
                   test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'), //匹配文件名
                   threshold: 10240, //对10K以上的数据进行压缩
                   minRatio: 0.8,
                   deleteOriginalAssets: false, //是否删除源文件
               }),
           )
       }
   },
   pluginOptions: {
       // ...第三方插件
   }


}

接下来就cd到当前目录,执行yarn serve 或者npm run serve
在这里插入图片描述
然后安装UI框架

cnpm i element-ui -S

由于本项目使用的组件不多,为了优化,采用按需加载

cnpm install babel-plugin-component -D

安装完后修改babel.config.js

module.exports = {
  // presets: [
  //   '@vue/cli-plugin-babel/preset'
  // ]
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

可以新建plugin 在main.ts引用插件
接下里就完善一下项目的结构
Route目录( 安装进度条)

 cnpm install --save nprogress 
 cnpm install --save-dev @types/nprogress

3.构建路由模块

路由主要采用懒加载,本项目只是简单设计 没有做权限Rbac权限设计如图所示:
路由

4.状态管理Vuex

官方文档 https://championswimmer.in/vuex-module-decorators/
因为vue2.x版本vuex对ts的兼容性不是很好,为了达到状态管理模块,这里要额外引用一个类库vuex-module-decorators,它是基于vue-class-component 所做的拓展,它提供了一系列的装饰器,让vue+ts结合的项目达到状态管理的作用。

cnpm install -D vuex-module-decorators

import { VuexModule, Module, Mutation, Action, getModule, } from 'vuex-module-decorators';
import { login } from '@/api/user'
import store from '@/store'

export interface UserInfo {
    userName:string,
    userPwd:string,
    roles:string[]

}

@Module({ name: 'user', dynamic: true, store })
//参数对比
// 参数一:module名称,开启命名空间后会以name为命名空间
// 参数二:是否使用动态加载,简而言之只有在用到当前的module才会加载,详细可以看vuex官网。本篇博客必须选择true,这也是为什么index.ts一直不用修改的原因,如果设置为false会有很大的变动,如果您真的需要这么做,可以自己研究一下。
// 参数三:是否开启命名空间,如果你的模块很多,强烈建议开启
// 参数四:挂载的store目标
class User extends VuexModule implements UserInfo {
    public userName: string = ''
    public userPwd: string = ''
    public roles: string[] = []

    @Mutation
    private SET_ROLES(roles:string[]) {
        this.roles = roles
    }

    @Action
    public async Login(params:any){
     console.log(params)
      let {userName,userPwd,validCode} =params
      const {data} = await login({userName,userPwd,validCode})
      console.log(data)
    }
}
export const UserModule = getModule(User)

上面的代码相当于普通vuex以下代码

import { login } from '@/api/index'
import { setStore, removeStore } from '@/assets/js/storage'
import Vue from 'vue'
const user = {
state: {
  token: '',
  name: '',
  roles: [],
},
mutations: {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  },
  SET_LOGOUT(state) {
    state.token = null;
    state.userInfo = null;
  },
  SET_NAME:(state,name)=>{
    state.name = name;
  }
},
actions: {
  SET_LOGOUT({ commit }) {
    removeStore('token');
    removeStore('userInfo');
    commit('SET_LOGOUT');
  },
  Login({ commit }, userInfo) {
    console.log(userInfo)
    return new Promise((resolve, reject) => {
      login(userInfo).then(response => {
        const result = response.object;
        commit('SET_TOKEN', result.userInfo.userToken),
        commit('SET_NAME', result.userInfo.userName)
        setStore('token', result.userInfo.userToken);
        setStore('userInfo', result.userInfo);
        resolve()
      })
      //  commit('SET_TOKEN','2113165465456465465');
      //  commit('SET_ROLES', ['1','2'])
      //  
    }).catch(error => {
      reject(error)
    })
  }
}
}

export default user

同时写在vuex的方法在vue页面调用的时候

import { Component, Vue } from "vue-property-decorator";
import { Form as ElForm, Input } from 'element-ui'
import {UserModule} from '@/store/modules/user'
import {validCode} from '@/api/user'
@Component({
 name: "login",
})
export default class extends Vue {
 private loginForm = {
   userName: "admin",
   userPwd: "1234567",
   validCode:''
 }
 private loginRules = {
   userName: [{ required: true, trigger: "blur" }],
   userPwd: [{ required: true, trigger: "blur" }]
 }
 private loading = false
 private capsTooltip = false
 private passwordType = "password"
 mounted() {
   // if (this.loginForm.userName === "") {
   //   this.$refs.userName.focus();
   // } else if (this.loginForm.userPwd === "") {
   //   this.$refs.userPwd.focus();
   // }
 }
 created(){
   this.refreshCode();
 }
 private async refreshCode() {
      const { object } = await validCode()
     this.loginForm.validCode = object
      console.log(this.loginForm)
 }
 private handleLogin() {
   (this.$refs.loginForm as ElForm).validate(async (valid: boolean) => {
     if (valid) {
       await UserModule.Login({
         ...this.loginForm,
       });
     } else {
       return false;
     }
   });
 }

在页面使用ts的时候基本上template模板编译基本上不会改变 ,script 会加上lang=ts 有点类似于java语言的感觉写到这里基本上一个项目的架构搭建起来了。后续会继续更新内容未展示的 Watch Prop等方法。

代码借鉴:花裤衩的代码结构https://gitee.com/panjiachen/vue-element-admin

Logo

前往低代码交流专区

更多推荐