由于vue3.0已经发布beta版本,vue3.0将会支持typescript,加上之前angular2.0已经支持typescript。纵观几个框架,TS已经是一个趋势。能够熟练掌握TS并可以应用到项目中去,就可以成为前端开发中的优势。因为vue2.0对TS不太友好,所以就一直搁置没有去重构。vue3.0在休息时间也准备重构一下自己得项目,在实践中不断摸坑。
本人工作项目中使用得vue-cli3,所以打算用vue-cli3脚手架来搭建整个项目,与vue-cli2不同的是webpack集成到vue.config.js里面了,所以还是比较方便得,当然萝卜白菜各有所爱,完全看自己的喜欢怎么舒服怎么来了。
1.初始化项目以及配置项
安装相对应得配置项
然后等待自动安装,等到搭建完之后,大致框架结构就是这样。
* 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
路由主要采用懒加载,本项目只是简单设计 没有做权限Rbac权限设计如图所示:
官方文档 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