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. springMvc改造springboot2.0踩坑

    1. 支持jsp applicaiton.proerties添加配置 #指定视图解析路径前缀 spring.mvc.view.prefix=/WEB-INF/jsp/ #指定视图解析后缀 spring ...

  2. Power BI 报表服务器中的行级别安全性 (RLS)

    在 Power BI Desktop 中定义角色和规则 你可以在 Power BI Desktop 中定义角色和规则. 发布到 Power BI 时,它还会发布角色定义. 若要定义安全角色,请执行以下 ...

  3. HttpWorkerRequest应用简介

    1. Using HttpWorkerRequest for getting headers1.使用HttpWorkerRequest获取headers信息 First, the HttpWorker ...

  4. 前段js实时判断会话是否超时

    前端自行判断页面是否超时 jsp从后台获取到回话时间var sessionTime="${sessionTime}"; js中 //实时判断会话是否超时 var lastSessi ...

  5. EF Code First 数据迁移操作

    打开执行命令窗体 1.EF Code First创建数据库 PM> Install-Package EntityFramework 2.EF Code First数据库迁移 2.1.生成数据库 ...

  6. Centos 7.0 界面

    执行:systemctl get-default //显示默认的界面方式 multi-user.target //命令行界面 graphical.target //图形化界面 执行:systemctl ...

  7. CentOS7连接无线网络

    背景  CentOS7.6最小化安装,没有网线,幸好有无线网卡.下面我们直接进入主题.  附:安装教程 主题--连接无线网络 最小化安装后,裸机没有ifconfig,没有iw,最可怕的是没有网线 但我 ...

  8. docker镜像pull不下来最终解决方法

    pull镜像wordpress下来,但是出现如下错误: # docker pull wordpress:latest Error response from daemon: Get https://r ...

  9. 合并K个sorted list

    合并k个已经排好序的数列是面试中也比较容易被问到的一个算法,有很多种解决,其中第一时间比较容易想到的解法如下: 对于这三组从小到大的数列: 如此循环,最终就将三个已经排序的数列的数字按从小到大的顺序排 ...

  10. Python numpy.ZIP 安装问题

    今天在python上安装numpy,按照网上教程,安装pip,然后命令行直接:pip install numpy  .但是一直因为资源问题下载失败. 后来下载了一个numpy-1.11.2.zip 安 ...