本文主要是介绍vue-cli3.0 搭建项目模版教程(ts+vuex+axios)最详细的语法检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
之前写了一篇vue2.5+typescript+vuex+axios 搭建教程,随着vue-cli3.0的发布,最近琢磨着重新写一篇基于3.0搭建的教程,全面升级一下项目模版,趁着空闲期把demo搭建完了,今天特此写一篇教程,也用于自己备忘和查阅。
Tip: 为了避免浪费您的时间,本文符合满足以下条件的同学借鉴参考
1.本文模版不适用于小型项目,两三个页面的也没必要用vue
2.对typescript
、vue全家桶
能够掌握和运用
此次项目模版主要涉及的技术框架:
vue2.5
vuex3.0
vue-router3.0
axios
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.删除assets
、components
、views
目录下的所有文件。
2.删除./src/store.ts
。
3.删除./src/router.ts
三.添加并配置文件
1.添加文件夹并创建文件
1.在根目录下创建scripts
文件夹,并添加template.js
、component.js
2.在./src
目录下创建api
文件夹
3.在./src
目录下创建config
文件夹,并添加index.ts
、requestConfig.ts
4.在./src
目录下创建router
文件夹,并添加index.ts
、router.ts
5.在./src
目录下创建store
文件夹,并添加index.ts
和module
文件夹
6.在./src
目录下创建types
文件夹,并添加index.ts
、components
文件夹和views
文件夹
7.在./src
目录下创建utils
文件夹,并添加common.ts
和request.ts
8.在./src/assets
目录下创建images
和scss
两个文件夹,并在scss
文件夹下添加common.scss
和variables.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// datadata: ${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}`) // mkdirprocess.chdir(`${basePath}/views/${dirName}`) // cd views
fs.writeFileSync(`${dirName}.vue`, VueTep) // vue
fs.writeFileSync(`${dirName}.ts`, tsTep) // ts
fs.writeFileSync(`${dirName}.scss`, scssTep) // scssprocess.chdir(`${basePath}/types/views`); // cd types
fs.writeFileSync(`${dirName}.interface.ts`, interfaceTep) // interfaceprocess.chdir(`${basePath}/store/module`); // cd store
fs.writeFileSync(`${dirName}.ts`, vuexTep) // vuexprocess.chdir(`${basePath}/api`); // cd api
fs.writeFileSync(`${dirName}.ts`, apiTep) // apiprocess.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// datadata: ${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}`) // mkdirprocess.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'
})// 登陆页面路由 name
const 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',component: () => import('@/views/index/index.vue'),meta: {icon: '',keepAlive: true,title: 'index'}}
]
7.打开./src/store/index.ts
,并添加以下内容
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {//},mutations: {//},actions: {//},modules: {// }
})
8.打开./src/utils/common.ts
,在此之前先下载js-cookie
,并添加以下内容
// 下载js-cookie
cnpm i js-cookie --S
cnpm install @types/js-cookie --D
/** @Description: 公共函数* @Author: asheng* @Date: 2018-12-07 11:36:27* @LastEditors: asheng* @LastEditTime: 2018-12-12 13:37:30*/import Cookies from 'js-cookie'
import { cookieExpires } from '@/config' // cookie保存的天数/*** @Author: asheng* @msg: 存取token* @param {string} token*/
export const TOKEN_KEY: string = 'token'
export const setToken = (token: string) => {Cookies.set(TOKEN_KEY, token, { expires: cookieExpires || 1 })
}
export const getToken = () => {const token = Cookies.get(TOKEN_KEY)if (token) {return token} else {return false}
}/*** @param {String} url* @description 从URL中解析参数*/
export const getParams = (url: string) => {const keyValueArr = url.split('?')[1].split('&')let paramObj: any = {}keyValueArr.forEach(item => {const keyValue = item.split('=')paramObj[keyValue[0]] = keyValue[1]})return paramObj
}/*** 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性* 如果没有传入key这个参数,则判断obj对象是否有键值对*/
export const hasKey = (obj: any, key: string | number) => {if (key) {return key in obj} else {const keysArr = Object.keys(obj)return keysArr.length}
}/*** @msg: 获取系统当前时间* @param {string} fmt 时间格式 具体看代码* @return: string*/
export const getDate = (fmt: any) => {let time = ''const date = new Date()const o: any = {"M+": date.getMonth() + 1, // 月份 "d+": date.getDate(), // 日 "H+": date.getHours(), // 小时 "m+": date.getMinutes(), // 分 "s+": date.getSeconds(), // 秒 "q+": Math.floor((date.getMonth() + 3) / 3), // 季度 "S": date.getMilliseconds() // 毫秒 }if (/(y+)/.test(fmt)) {time = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length))}for (const k in o) {if (new RegExp("(" + k + ")").test(fmt)) {time = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)))}}return time
}/*** @msg: 获取系统当前时间* @param {string} date 时间* @param {string} fmt 时间格式* @return: string*/
export const formatDate = (date: any, fmt: string) => {let time = ''const o: any = {"M+": date.getMonth() + 1, // 月份 "d+": date.getDate(), // 日 "H+": date.getHours(), // 小时 "m+": date.getMinutes(), // 分 "s+": date.getSeconds(), // 秒 "q+": Math.floor((date.getMonth() + 3) / 3), // 季度 "S": date.getMilliseconds() // 毫秒 }if (/(y+)/.test(fmt)) {time = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length))}for (const k in o) {if (new RegExp("(" + k + ")").test(fmt)) {time = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)))}}return time
}// copy in the 'fx-fuli' utils
/*** 校验手机号是否正确* @param phone 手机号*/export const verifyPhone = (phone: string | number) => {const reg = /^1[34578][0-9]{9}$/const _phone = phone.toString().trim()let toastStr = _phone === '' ? '手机号不能为空~' : !reg.test(_phone) && '请输入正确手机号~'return {errMsg: toastStr,done: !toastStr,value: _phone}
}export const verifyStr = (str: string | number, text: string) => {const _str = str.toString().trim()const toastStr = _str.length ? false : `请填写${text}~`return {errMsg: toastStr,done: !toastStr,value: _str}
}// 截取字符串
export const sliceStr = (str: any, sliceLen: number) => {if (!str) { return '' }let realLength = 0const len = str.lengthlet charCode = -1for (let i = 0; i < len; i++) {charCode = str.charCodeAt(i)if (charCode >= 0 && charCode <= 128) {realLength += 1} else {realLength += 2}if (realLength > sliceLen) {return `${str.slice(0, i)}...`}}return str
}/*** JSON 克隆* @param {Object | Json} jsonObj json对象* @return {Object | Json} 新的json对象*/
export function objClone(jsonObj: any) {let buf: anyif (jsonObj instanceof Array) {buf = []let i = jsonObj.lengthwhile (i--) {buf[i] = objClone(jsonObj[i])}return buf} else if (jsonObj instanceof Object) {buf = {}for (let k in jsonObj) {buf[k] = objClone(jsonObj[k])}return buf} else {return jsonObj}
}
9.打开./src/utils/request.ts
,先下载axios
,并添加以下内容
// 下载axios
cnpm i axios --S
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
import { MAINHOST, ISMOCK, conmomPrams } from '@/config'
import requestConfig from '@/config/requestConfig'
import { getToken } from '@/utils/common'
import router from '@/router'declare type Methods = "GET" | "OPTIONS" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT"
declare interface Datas {method?: Methods[key: string]: any
}
const baseURL = process.env.NODE_ENV === 'production' ? MAINHOST : location.origin
const token = getToken()class HttpRequest {public queue: any // 请求的url集合public constructor() {this.queue = {}}destroy(url: string) {delete this.queue[url]if (!Object.keys(this.queue).length) {// hide loading}}interceptors(instance: any, url?: string) {// 请求拦截instance.interceptors.request.use((config: AxiosRequestConfig) => {// 添加全局的loading...if (!Object.keys(this.queue).length) {// show loading}if (url) {this.queue[url] = true}return config}, (error: any) => {console.error(error)})// 响应拦截instance.interceptors.response.use((res: AxiosResponse) => {if (url) {this.destroy(url)}const { data, status } = resif (status === 200 && ISMOCK) { return data } // 如果是mock数据,直接返回if (status === 200 && data && data.code === 0) { return data } // 请求成功return requestFail(res) // 失败回调}, (error: any) => {if (url) {this.destroy(url)}console.error(error)})}async request(options: AxiosRequestConfig) {const instance = axios.create()await this.interceptors(instance, options.url)return instance(options)}
}// 请求失败
const requestFail = (res: AxiosResponse) => {let errStr = '网络繁忙!'// token失效重新登陆if (res.data.code === 1000001) {return router.replace({ name: 'login' })}return {err: console.error({code: res.data.errcode || res.data.code,msg: res.data.errmsg || errStr})}
}// 合并axios参数
const conbineOptions = (_opts: any, data: Datas, method: Methods): AxiosRequestConfig => {let opts = _optsif (typeof opts === 'string') {opts = { url: opts }}const _data = { ...conmomPrams, ...opts.data, ...data }const options = {method: opts.method || data.method || method || 'GET',url: opts.url,header: { 'user-token': token },baseURL}return options.method !== 'GET' ? Object.assign(options, { data: _data }) : Object.assign(options, { params: _data })
}const HTTP = new HttpRequest()/*** 抛出整个项目的api方法*/
const Api = (() => {const apiObj: any = {}const requestList: any = requestConfigconst fun = (opts: AxiosRequestConfig | string) => {return async (data = {}, method: Methods = "GET") => {if (!token) {console.error('No Token')return router.replace({ name: 'login' })}const newOpts = conbineOptions(opts, data, method)const res = await HTTP.request(newOpts)return res}}Object.keys(requestConfig).forEach((key) => {apiObj[key] = fun(requestList[key])})return apiObj
})()export default Api as any
10.打开./src/main.ts
,引用common.scss
import "@/assets/scss/common.scss"
11.打开./src/App.vue
,按照如下修改(未贴代码表示不变
)
<template><div id="app"><keep-alive><router-view v-if="$route.meta.keepAlive"/></keep-alive><router-view v-if="!$route.meta.keepAlive"/></div>
</template>
12.还有非常重要
的一步,打开根目录下的vue.config.js
,如果没有就自己创建一个,放在根目录下,并添加以下内容
const path = require('path')const resolve = dir => {return path.join(__dirname, dir)
}// 线上打包路径,请根据项目实际线上情况
const BASE_URL = process.env.NODE_ENV === 'production' ? '/' : '/'module.exports = {baseUrl: BASE_URL,outputDir: 'dist', // 打包生成的生产环境构建文件的目录assetsDir: '', // 放置生成的静态资源路径,默认在outputDirindexPath: 'index.html', // 指定生成的 index.html 输入路径,默认outputDirpages: undefined, // 构建多页productionSourceMap: false, // 开启 生产环境的 source map?chainWebpack: config => {// 配置路径别名config.resolve.alias.set('@', resolve('src')).set('_c', resolve('src/components'))},css: {modules: false, // 启用 CSS modulesextract: true, // 是否使用css分离插件sourceMap: false, // 开启 CSS source maps?loaderOptions: {} // css预设器配置项},devServer: {port: 8080, // 端口proxy: 'https://www.easy-mock.com' // 设置代理}
}
13.打开根目录下的package.json
,在scripts
中添加如下代码
"scripts": {..."tep": "node scripts/template","com": "node scripts/component"
}
四.编写业务代码
1.编写page页
运行我们之前添加的脚本命令,创建page
,也就是运行之前写的template.js
这个脚本,实现快速创建我们所需要的page模版,而不需要一个一个的再创建,大大节省了时间,如果不用用脚本跑也是可以的,分别需要创建以下文件夹:
- 在
views
文件夹下创建login
文件夹,再向login
文件夹下添加login.vue
、login.ts
、login.scss
- 在
./src/api
下添加login.ts
- 在
./src/store/module
下添加login.ts
- 在
./src/types/views
下添加login.interface.ts
是不是非常繁琐,还可能搞错(不推荐,浪费时间 0.0
),而使用脚本只需要在命令行敲一条命令搞定(推荐
)如下(根据demo需求,我们创建两个页面index、login):
cnpm run tep index
cnpm run tep login
打开./src/views/login/login.ts
,发现报错,没有安装模块vuex-class
,安装一下就好了
cnpm i vuex-class --S
再运行创建组件脚本,随意创建一个test组件
cnpm run com test
ok,这时候发现./src/components
目录下创建了test组件,为了引用组件更方便看起来更优雅,我们在./src/components
目录下添加一个index.ts
,把所有组件都引入到这里,作为一个中转文件,如下:
import Test from './test/test.vue'export {Test
}
引用组件
上面创建好了组件后,打开./src/views/login/login.ts
,如下引用:
import { Test } from "@/components" // 组件@Component({components: {Test}
})
在./src/views/login/login.vue
中添加组件
<template><div class="login-wrap">{{data.pageName}}<div><Test></Test></div></div>
</template>
这时候页面显示为如下:
组件示意图
调用http请求示例
最后再说一下怎么调用http请求吧,在这之前,先重启一遍服务
cnpm run serve
按照我的步骤来,启动是不会报错的,如果报错,那么可以留言看到会回复,或者重新走一遍。
没问题的话,我们按照如下步骤:
1.打开./src/config/requestConfig.ts
文件添加接口,由于我们之前的添加过了,那么我们进行下一步。
2.打开./src/api/login.ts
文件添加请求函数,我们之前也写好了,跳过。
3.进入./src/store/module/login.ts
文件,把GET_DATA_ASYN
函数的注释打开。
4.在./src/store/index.ts
中的module添加login,如下:
// modules
import Login from './module/login'
import Index from './module/index'export default new Vuex.Store({...modules: {Login,Index}
}
完成上述动作后就可以在任意页面调用了,我们打开./src/views/index/index.ts
,如下调用:
export default class About extends Vue {@Action GET_DATA_ASYNcreated() {this.GET_DATA_ASYN()}
}
到现在有没有发现不管怎么样路由都到不了index
页面,是因为做了路由拦截,我们在cookies添加一个token,如下:
token
添加完之后,刷新就可以正常跳转到index
了,(顺带一句,对于需要登录的项目路由拦截是很有必要的),这时候就可以发现在network里面发现我们的接口请求成功了,如下:
接口请求成功示意图
篇幅比较长,终于写完了,有问题大家可以提,有更好的优化方法欢迎提出来,共同进步。
END
github源码地址:https://github.com/chenfangsheng/vue-cli3-tpl.git
作者:陈小生_1017
链接:https://www.jianshu.com/p/44500385abdd
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
这篇关于vue-cli3.0 搭建项目模版教程(ts+vuex+axios)最详细的语法检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!