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'
}) // 登陆页面路由 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 = 0
const len = str.length
let charCode = -1
for (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: any
if (jsonObj instanceof Array) {
buf = []
let i = jsonObj.length
while (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 } = res
if (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 = _opts
if (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 = requestConfig
const 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: '', // 放置生成的静态资源路径,默认在outputDir
indexPath: 'index.html', // 指定生成的 index.html 输入路径,默认outputDir
pages: undefined, // 构建多页
productionSourceMap: false, // 开启 生产环境的 source map?
chainWebpack: config => {
// 配置路径别名
config.resolve.alias
.set('@', resolve('src'))
.set('_c', resolve('src/components'))
},
css: {
modules: false, // 启用 CSS modules
extract: 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.vuelogin.tslogin.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_ASYN created() {
this.GET_DATA_ASYN()
}
}

到现在有没有发现不管怎么样路由都到不了index页面,是因为做了路由拦截,我们在cookies添加一个token,如下:

 
token

添加完之后,刷新就可以正常跳转到index了,(顺带一句,对于需要登录的项目路由拦截是很有必要的),这时候就可以发现在network里面发现我们的接口请求成功了,如下:

 
接口请求成功示意图

篇幅比较长,终于写完了,有问题大家可以提,有更好的优化方法欢迎提出来,共同进步。

原文链接: https://www.jianshu.com/p/44500385abdd

vue+ts搭建项目的更多相关文章

  1. 1.vue脚手架搭建项目

    前言: 在使用Vue-cli脚手架搭建项目之前,需要安装node.js和npm以及vue-cli. 开始搭建项目: 1.打开cmd win+R 2.转到要搭建的项目路径: g: cd Webapp/v ...

  2. Vue环境搭建-项目的创建-启动生命周期-组件的封装及应用

    vue项目环境的搭建 """ node >>> python:node是用c++编写用来运行js代码的 npm(cnpm) >>> p ...

  3. Vue脚手架搭建项目

    全局安装vue脚手架 $ npm install -g vue-cli 卸载方法 $ npm uninstall -g vue-cli 查看vue版本(注意:大写的V) $ vue -V 创建项目 $ ...

  4. 使用vue脚手架搭建项目并将px自动转化为rem

    一.安装node.js环境 二.node.js安装完成后使用npm安装vue脚手架vue-cli和安装webpack,我这里用cnpm cnpm i @vue/cli -g //全局安装脚手架3.0 ...

  5. vue cli搭建项目及文件引入

    cli搭建方法:需安装nodejs先 1.npm install -g cnpm --registry=https://registry.npm.taobao.org //安装cnpm,用cnpm下载 ...

  6. nodejs使用vue从搭建项目到发布部署

    都说是使用vue 脚手架自然用的是vue-cli npm install vue-cli -g 建立项目 vue init webpack demo //vue初始化 使用webpack 项目名称 这 ...

  7. 【vue】vue +element 搭建项目,mock模拟数据(纯干货)

    1.安装mockjs依赖 (c)npm install mockjs --save-dev 2.安装axios(Ajax) (c)npm install --save axios 3.项目目录 4.设 ...

  8. 使用VUE框架搭建项目基本步骤

    ps:初入Vue坑的小伙伴们,对于独立做一个项目可能不清楚需要使用哪些资源,这篇随笔希望对大家有所帮助. 第一步:参照vue的官方文档,建立一个vue的项目 # 全局安装 vue-cli $ npm ...

  9. vue+webpack搭建项目

    1.全局安装node.js 2.安装vue-cli 可以在项目目录安装 npm install -g vue-cli 使用vue-list命令选择webpack模板 vue init webpack ...

随机推荐

  1. O044、一张图秒懂 Nova 16种操作

    参考https://www.cnblogs.com/CloudMan6/p/5565757.html    

  2. 关于mysql installer 的安装和环境变量配置

    MySQL针对不同的用户提供了2中不同的版本: MySQL Community Server:社区版.由MySQL开源社区开发者和爱好者提供技术支持,对开发者开放源代码并提供免费下载. MySQL E ...

  3. TVM调试指南

    1. TVM安装 这部分之前就写过,为了方便,这里再复制一遍. 首先下载代码 git clone --recursive https://github.com/dmlc/tvm 这个地方最好使用--r ...

  4. umi+antdpro 2.3

    关于umi接管了路由之后的动态配置. 路由通过 router.js 配置文件自动生成. 在 models/ menu.js中可以获取到,但从这里获取到并过滤之后的其实不是路由配置. 正确过滤方式,通过 ...

  5. mongodb启用auth,使用密码登录

    更新操作: db.users.update({'currentVersion':3},{$set:{'currentVersion':5}}) 首先安装下载(略过) mongod 启动服务,有多重启动 ...

  6. mysql_jdbc连接说明

    mysql JDBC Driver 常用的有两个,一个是gjt(Giant Java Tree)组织提供的mysql驱动,其JDBC Driver名称(JAVA类名)为:org.gjt.mm.mysq ...

  7. SQL语句复习【专题二】

    SQL语句复习[专题二] 单行函数(日期.数学.字符串.通用函数.转换函数)多行函数.分组函数.多行数据计算一个结果.一共5个.sum(),avg(),max(),min(),count()分组函数  ...

  8. ANSIBLE自动化管理工具

    ansible 基础 自动化运维工具 官网:https://www.ansible.com/ 官方文档:https://docs.ansible.com/ ansible 特性 1. 模块化:调用特定 ...

  9. Hadoop_10_HDFS 的 DataNode工作机制

    1.DataNode的工作机制: 1.DataNode工作职责:存储管理用户的文件块数据  定期向namenode汇报自身所持有的block信息(通过心跳信息上报) (这点很重要,因为,当集群中发生某 ...

  10. manjaro 常用软件安装

    1.搜狗输入法 sudo pacman -S fcitx-sogoupinyin fcitx-configtool fcitx-im yay -Sa fcitx-qt4 sudo vim /etc/e ...