>

Hey,I'am Rander

vue-cli3.0 搭建项目模版教程(ts+vuex+axios)

2019-12-15 前端综合

关键字: Javascript

Tip: 为了避免浪费您的时间,本文符合满足以下条件的同学借鉴参考

1.本文模版不适用于小型项目,两三个页面的也没必要用vue
2.typescriptvue全家桶能够掌握和运用

此次项目模版主要涉及的技术框架:

1. vue2.5

2. vuex3.0

3. vue-router3.0

4. axios

5. typescript3.2

Tip: 由于vue-cli3.0帮我们简化了webpack的配置,我们只需要在根目录下的vue.config.js文件的chainWebpack进行配置即可。

接下来进入正题(前提是你已经安装并配置好了node环境)

.初始化项目

安装vue-cli3.0 

如果你之前安装的是vue-cli2.0版本的,那么你需要先卸载2.0版本,再安装3.0版本

// cnpm 为淘宝镜像

cnpm uninstall vue-cli -g // 卸载

cnpm install -g @vue/cli // 安装新版本

创建项目

vue create vue-cli3-tpl

选择Manually select features回车,按照下图所示选中(空格选中)回车安装插件


然后一路回车,放一下配置图


等安装完之后,进入项目并启动项目

cd vue-cli3-tpl

cnpm run serve

启动后显示如下,第一步完成。

.删除不必要的文件

1.删除assetscomponentsviews目录下的所有文件。
2.删除./src/store.ts
3.删除./src/router.ts

.添加并配置文件

1.添加文件夹并创建文件

1.在根目录下创建scripts文件夹,并添加template.jscomponent.js
2../src目录下创建api文件夹
3../src目录下创建config文件夹,并添加index.tsrequestConfig.ts
4../src目录下创建router文件夹,并添加index.tsrouter.ts
5../src目录下创建store文件夹,并添加index.tsmodule文件夹
6../src目录下创建types文件夹,并添加index.tscomponents文件夹和views文件夹
7../src目录下创建utils文件夹,并添加common.tsrequest.ts
8../src/assets目录下创建imagesscss两个文件夹,并在scss文件夹下添加common.scssvariables.scss

2.配置文件

首先配置一下根目录下tslint.json,编码习惯还是根据团队的要求来,我自己关闭了很多在我看来很鸡肋的东西,下面是个人的配置,仅供参考

{

  "defaultSeverity": "warning",

  "extends": [

    "tslint:recommended"

  ],

  "linterOptions": {

    "exclude": [

      "node_modules/**"

    ]

  },

  "rules": {

    "quotemark": false, // 字符串文字需要单引号或双引号。

    "indent": false, // 使用制表符或空格强制缩进。

    "member-access": false, // 需要类成员的显式可见性声明。

    "interface-name": false, // 接口名要求大写开头

    "ordered-imports": false, // 要求将import语句按字母顺序排列并进行分组。

    "object-literal-sort-keys": false, // 检查对象文字中键的排序。

    "no-consecutive-blank-lines": false, // 不允许连续出现一个或多个空行。

    "no-shadowed-variable": false, // 不允许隐藏变量声明。

    "no-trailing-whitespace": false, // 不允许在行尾添加尾随空格。

    "semicolon": false, // 是否分号结尾

    "trailing-comma": false, // 是否强象添加逗号

    "eofline": false, // 是否末尾另起一行

    "prefer-conditional-expression": false, // for (... in ...)语句必须用if语句过滤

    "curly": true, //for if do while 要有括号

    "forin": false, //用for in 必须用if进行过滤

    "import-blacklist": true, //允许使用import require导入具体的模块

    "no-arg": true, //不允许使用 argument.callee

    "no-bitwise": true, //不允许使用按位运算符

    "no-console": false, //不能使用console

    "no-construct": true, //不允许使用 String/Number/Boolean的构造函数

    "no-debugger": true, //不允许使用debugger

    "no-duplicate-super": true, //构造函数两次用super会发出警告

    "no-empty": true, //不允许空的块

    "no-eval": true, //不允许使用eval

    "no-floating-promises": false, //必须正确处理promise的返回函数

    "no-for-in-array": false, //不允许使用for in 遍历数组

    "no-implicit-dependencies": false, //不允许在项目的package.json中导入未列为依赖项的模块

    "no-inferred-empty-object-type": false, //不允许在函数和构造函数中使用{}的类型推断

    "no-invalid-template-strings": true, //警告在非模板字符中使用${

    "no-invalid-this": true, //不允许在非class中使用 this关键字

    "no-misused-new": true, //禁止定义构造函数或new class

    "no-null-keyword": false, //不允许使用null关键字

    "no-object-literal-type-assertion": false, //禁止object出现在类型断言表达式中

    "no-return-await": true, //不允许return await

    "arrow-parens": false, //箭头函数定义的参数需要括号

    "adjacent-overload-signatures": false, //  Enforces function overloads to be consecutive.

    "ban-comma-operator": true, //禁止逗号运算符。

    "no-any": false, //不需使用any类型

    "no-empty-interface": true, //禁止空接口 {}

    "no-internal-module": true, //不允许内部模块

    "no-magic-numbers": false, //不允许在变量赋值之外使用常量数值。当没有指定允许值列表时,默认允许-1,0和1

    "no-namespace": [true, "allpw-declarations"], //不允许使用内部modules和命名空间

    "no-non-null-assertion": true, //不允许使用!后缀操作符的非空断言。

    "no-parameter-reassignment": true, //不允许重新分配参数

    "no-reference": true, // 禁止使用/// <reference path=> 导入 ,使用import代替

    "no-unnecessary-type-assertion": false, //如果类型断言没有改变表达式的类型就发出警告

    "no-var-requires": false, //不允许使用var module = require("module"), import foo = require('foo')导入

    "prefer-for-of": true, //建议使用for(..of)

    "promise-function-async": false, //要求异步函数返回promise

    "max-classes-per-file": [true, 2], // 一个脚本最多几个申明类

    "variable-name": false,

    "prefer-const": false // 提示可以用const的地方

  }}

1. 打开./scripts/template.js,并添加以下内容

/*

 * @Description: 页面快速生成脚本

 * @Date: 2018-12-06 10:28:08

 * @LastEditTime: 2018-12-10 09:43:50

 */const fs = require('fs')const path = require('path')const basePath = path.resolve(__dirname, '../src')

const dirName = process.argv[2]const capPirName = dirName.substring(0, 1).toUpperCase() + dirName.substring(1)if (!dirName) {

    console.log('文件夹名称不能为空!')

    console.log('示例:npm run tep ${capPirName}')

    process.exit(0)}

/**

 * @msg: vue页面模版

 */const VueTep = `<template>

  <div class="${dirName}-wrap">

    {{data.pageName}}

  </div>

</template>


<script lang="ts" src="./${dirName}.ts"></script>


<style lang="scss">

  @import './${dirName}.scss'

</style>

`

// ts 模版const tsTep = `import { Component, Vue } from "vue-property-decorator"

import { Getter, Action } from "vuex-class"

import { ${capPirName}Data } from '@/types/views/${dirName}.interface'

// import {  } from "@/components" // 组件


@Component({})

export default class About extends Vue {

  // Getter

  // @Getter ${dirName}.author

    

  // Action

  // @Action GET_DATA_ASYN


  // data

  data: ${capPirName}Data = {

    pageName: '${dirName}'

  }


  created() {

    //

  }

    

  activated() {

    //

  }


  mounted() {

    //

  }


  // 初始化函数

  init() {

    //

  }

    

}`

// scss 模版const scssTep = `@import "@/assets/scss/variables.scss";


.${dirName}-wrap {

  width: 100%;

}`

// interface 模版const interfaceTep = `// ${dirName}.Data 参数类型

export interface ${capPirName}Data {

  pageName: string

}


// VUEX ${dirName}.State 参数类型

export interface ${capPirName}State {

  data?: any

}


// GET_DATA_ASYN 接口参数类型

// export interface DataOptions {}

`

// vuex 模版const vuexTep = `import { ${capPirName}State } from '@/types/views/${dirName}.interface'

import { GetterTree, MutationTree, ActionTree } from 'vuex'

import * as ${capPirName}Api from '@/api/${dirName}'


const state: ${capPirName}State = {

  ${dirName}: {

   author: undefined

  }

}


// 强制使用getter获取state

const getters: GetterTree<${capPirName}State, any> = {

  author: (state: ${capPirName}State) => state.${dirName}.author

}


// 更改state

const mutations: MutationTree<${capPirName}State> = {

  // 更新state都用该方法

  UPDATE_STATE(state: ${capPirName}State, data: ${capPirName}State) {

    for (const key in data) {

      if (!data.hasOwnProperty(key)) { return }

      state[key] = data[key]

    }

  }

}


const actions: ActionTree<${capPirName}State, any> = {

  UPDATE_STATE_ASYN({ commit, state: ${capPirName}State }, data: ${capPirName}State) {

    commit('UPDATE_STATE', data)

  },

  // GET_DATA_ASYN({ commit, state: LoginState }) {

  //   ${capPirName}.getData()

  // }

}


export default {

  state,

  getters,

  mutations,

  actions

}

`

// api 接口模版const apiTep = `import Api from '@/utils/request'


export const getData = () => {

  return Api.getData()

}

`


fs.mkdirSync(`${basePath}/views/${dirName}`) // mkdir


process.chdir(`${basePath}/views/${dirName}`) // cd views

fs.writeFileSync(`${dirName}.vue`, VueTep) // vue

fs.writeFileSync(`${dirName}.ts`, tsTep) // ts

fs.writeFileSync(`${dirName}.scss`, scssTep) // scss


process.chdir(`${basePath}/types/views`); // cd types

fs.writeFileSync(`${dirName}.interface.ts`, interfaceTep) // interface


process.chdir(`${basePath}/store/module`); // cd store

fs.writeFileSync(`${dirName}.ts`, vuexTep) // vuex


process.chdir(`${basePath}/api`); // cd api

fs.writeFileSync(`${dirName}.ts`, apiTep) // api


process.exit(0)

 

2. 打开./scripts/component.js,并添加以下内容

/*

 * @Description: 组件快速生成脚本

 * @Date: 2018-12-06 10:26:23

 * @LastEditTime: 2018-12-10 09:44:19

 */

const fs = require('fs')const path = require('path')const basePath = path.resolve(__dirname, '../src')

const dirName = process.argv[2]const capPirName = dirName.substring(0, 1).toUpperCase() + dirName.substring(1)if (!dirName) {

  console.log('文件夹名称不能为空!')

  console.log('示例:npm run tep ${capPirName}')

  process.exit(0)}

/**

 * @msg: vue页面模版

 */const VueTep = `<template>

  <div class="${dirName}-wrap">

    {{data.componentName}}

  </div>

</template>


<script lang="ts">

  import { Component, Vue, Prop } from "vue-property-decorator"

  import { Getter, Action } from 'vuex-class'

  import { ${capPirName}Data } from '@/types/components/${dirName}.interface'

  // import {  } from "@/components" // 组件


  @Component({})

  export default class About extends Vue {

    // prop

    @Prop({

      required: false,

      default: ''

    }) name!: string


    // data

    data: ${capPirName}Data = {

      componentName: '${dirName}'

    }


    created() {

      //

    }

    

    activated() {

      //

    }


    mounted() {

      //

    }


  }

</script>


<style lang="scss">

  @import "@/assets/scss/variables";


  .${dirName}-wrap {

    width: 100%;

  }

</style>

`

// interface 模版const interfaceTep = `// ${dirName}.Data 参数类型

export interface ${capPirName}Data {

  componentName: string

}

`


fs.mkdirSync(`${basePath}/components/${dirName}`) // mkdir


process.chdir(`${basePath}/components/${dirName}`) // cd views

fs.writeFileSync(`${dirName}.vue`, VueTep) // vue


process.chdir(`${basePath}/types/components`) // cd components

fs.writeFileSync(`${dirName}.interface.ts`, interfaceTep) // interface


process.exit(0)

3.打开./src/config/index.ts,并添加以下内容

/**

 * 线上环境

 */export const ONLINEHOST: string = 'https://xxx.com'

/**

 * 测试环境

 */export const QAHOST: string = 'http://xxx.com'

/**

 * 线上mock

 */export const MOCKHOST: string = 'http://xxx.com'

/**

 * 是否mock

 */export const ISMOCK: boolean = true

/**

 * 当前的host  ONLINEHOST | QAHOST | MOCKHOST

 */export const MAINHOST: string = ONLINEHOST

/**

 * 请求的公共参数

 */export const conmomPrams: any = {}

/**

 * @description token在Cookie中存储的天数,默认1天

 */export const cookieExpires: number = 1

4.打开./src/config/requestConfig.ts,并添加以下内容

export default {

  getData: '/mock/5c09ca373601b6783189502a/example/mock', // 随机数据 来自 easy mock

}

5.打开./src/router/index.ts,并添加以下内容

import Vue from 'vue'import Router from 'vue-router'import routes from './router'import { getToken } from '@/utils/common'


Vue.use(Router)

const router = new Router({

  routes,

  mode: 'history'})

// 登陆页面路由 nameconst LOGIN_PAGE_NAME = 'login'

// 跳转之前

router.beforeEach((to, from, next) => {

  const token = getToken()

  if (!token && to.name !== LOGIN_PAGE_NAME) {

    // 未登录且要跳转的页面不是登录页

    next({

      name: LOGIN_PAGE_NAME // 跳转到登录页

    })

  } else if (!token && to.name === LOGIN_PAGE_NAME) {

    // 未登陆且要跳转的页面是登录页

    next() // 跳转

  } else if (token && to.name === LOGIN_PAGE_NAME) {

    // 已登录且要跳转的页面是登录页

    next({

      name: 'index' // 跳转到 index 页

    })

  } else {

    if (token) {

      next() // 跳转

    } else {

      next({

        name: LOGIN_PAGE_NAME

      })

    }

  }})


// 跳转之后

router.afterEach(to => {

  //})

export default router

6.打开./src/router/router.ts,并添加以下内容

/**

 * meta 可配置参数

 * @param {boolean} icon 页面icon

 * @param {boolean} keepAlive 是否缓存页面

 * @param {string} title 页面标题

 */export default [

  {

    path: '/',

    redirect: '/index'

  },

  {

    path: '/login',

    name: 'login',

    component: () => import('@/views/login/login.vue'),

    meta: {

      icon: '',

      keepAlive: true,

      title: 'login'

    }

  },

  {

    path: '/index',

    name: 'index',