VueCli3構(gòu)建TS項(xiàng)目的方法步驟
使用vue-cli3構(gòu)建Typescript項(xiàng)目
import 和 require
require: 以同步的方式檢索其他模塊的導(dǎo)出 (開發(fā))
import: 動(dòng)態(tài)地加載模塊 (生產(chǎn))
相關(guān)文檔:module methods
vue-cli3
vue create project-name
vue-cli3配置, 生成目錄結(jié)構(gòu):
│ .browserslistrc
│ .gitignore
│ .postcssrc.js // postcss 配置
│ babel.config.js
│ cypress.json
│ package.json // 依賴
│ README.md
│ tsconfig.json // ts 配置
│ eslint.json // eslint 配置
│ yarn.lock
│
├─public // 靜態(tài)頁面
│ │ favicon.ico
│ │ index.html
│ │ manifest.json
│ │ robots.txt
│ │
│ └─img
│ └─icons
│
├─src // 主目錄
│ │ App.vue // 頁面主入口
│ │ main.ts // 腳本主入口
│ │ registerServiceWorker.ts // PWA 配置
│ │ router.ts // 路由
│ │ shims-tsx.d.ts // 相關(guān) tsx 模塊注入
│ │ shims-vue.d.ts // Vue 模塊注入
│ │ store.ts // vuex 配置
│ │
│ ├─assets // 靜態(tài)資源
│ │ logo.png
│ │
│ ├─components // 組件
│ │ HelloWorld.vue
│ │
│ └─views // 頁面
│ About.vue
│ Home.vue
│
└─tests // 測試用例
├─e2e
│ ├─plugins
│ │ index.js
│ ├─specs
│ │ test.js
│ └─support
│ commands.js
│ index.js
└─unit
HelloWorld.spec.ts
改造后的目錄結(jié)構(gòu):
│ .browserslistrc
│ .gitignore
│ .postcssrc.js // postcss 配置
│ babel.config.js
│ cypress.json
│ package.json // 依賴
│ README.md // 項(xiàng)目 readme
│ tsconfig.json // ts 配置
│ eslint.json // eslint 配置
│ vue.config.js // webpack 配置
│ yarn.lock
│
├─public // 靜態(tài)頁面
│ │ favicon.ico
│ │ index.html
│ │ manifest.json
│ │ robots.txt
│ │
│ └─img
│ └─icons
├─scripts // 相關(guān)腳本配置
├─src // 主目錄
│ │ App.vue // 頁面主入口
│ │ main.ts // 腳本主入口
│ │ registerServiceWorker.ts // PWA 配置
│ │ shims-tsx.d.ts
│ │ shims-vue.d.ts
│ │
│ ├─assets // 靜態(tài)資源
│ │ logo.png
│ │
│ ├─components
│ │ HelloWorld.vue
│ │
│ ├─filters // 過濾
│ ├─lib // 全局插件
│ ├─router // 路由配置
│ │ index.ts
│ │
│ ├─scss // 樣式
│ ├─store // vuex 配置
│ │ index.ts
│ │
│ ├─typings // 全局注入
│ ├─utils // 工具方法(axios封裝,全局方法等)
│ └─views // 頁面
│ About.vue
│ Home.vue
│
└─tests // 測試用例
├─e2e
│ ├─plugins
│ │ index.js
│ │
│ ├─specs
│ │ test.js
│ │
│ └─support
│ commands.js
│ index.js
│
└─unit
HelloWorld.spec.ts
eslint 和 tslint
tslint配置
關(guān)閉不能cosole:
"no-console": false
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "always",
"asyncArrow": "always"
}]
tslint分號的配置:
"semicolon": [true, "never"]
eslint配置
在項(xiàng)目中是使用eslint
規(guī)范空格:'indent': 0
路由改造
引入組件方式
dev使用require:
/**
* 開發(fā)環(huán)境載入文件
* @param fileName 文件路徑,不包括文件名
* @param viewPath 視圖目錄
*/
module.exports = (file: string, viewPath: string = 'views') => {
return require(`@/${viewPath}/${file}.vue`).default
}
prod使用import:
/**
* 生產(chǎn)環(huán)境載入文件
* @param fileName 文件路徑,不包括文件名
* @param viewPath 視圖目錄
*/
module.exports = (file: string, viewPath: string = 'views') => {
return import(`@/${viewPath}/${file}.vue`)
}
路由處理邏輯
改文件在app.vue中引入:
/**
* 路由處理邏輯
*/
import router from '@/router/index'
router.beforeEach((to: any, from: any, next: any) => {
if (to.name === 'login') {
next({name: 'home/index'})
} else {
next()
}
})
router-view
一個(gè)<router-view />對應(yīng)一個(gè)路由層級,下一級<router-view /> 對應(yīng)路由表中的children路由
router 中的meta
配置每個(gè)路由的單獨(dú)特性
title, keepalive, main, desc, icon, hidden, auth
keep-alive
vue中的<keep-alive></keep-alive>其它生命周期不執(zhí)行,只執(zhí)行:activated 和 deactivated
axios改造
npm i axios --save

typings
在根目錄創(chuàng)建typings文件,里面定義, 全局注入。
需要哪些接口引入哪些接口文件。
創(chuàng)建ajax.d.ts文件,并聲明后臺返回的數(shù)據(jù)格式。
declare namespace Ajax {
// axios return data
export interface AxiosResponse {
data: AjaxResponse
}
// reqposne interface
export interface AjaxResponse {
id: number
error: null | object
jsonrpc: string
result: any
}
}
使用,在src根目錄下都可以使用。
let res: Ajax.AxiosResponse = {
data: {"id": "1533610056745", "result": 1, "error": null, "jsonrpc": "2.0"}
}
cookies的處理
安裝cookies的包:npm i js-cookie --save
增加項(xiàng)目前綴,封裝cookie, localStorage, sessionStorage 增刪改等方法
/**
* 操作 cookie, localStorage, sessionStorage 封裝
*/
import Cookies from 'js-cookie'
import { isNil } from 'lodash'
const prefix = process.env.VUE_APP_PREFIX
/**
* ============ Cookie ============
*/
export function getCookie (name: string): string {
return Cookies.get(prefix + name)
}
export function setCookie (name: string, value: any, params= {}): void {
if (isEmpty(value)) return
Cookies.set(prefix + name, value, params)
}
export function removeCookie (name: string, params= {}): void {
Cookies.remove(prefix + name, params)
}
/**
* ============ localStorage ============
*/
export function setLocalStorage (name: string, value: any): void {
if (isEmpty(value)) return
window.localStorage.setItem(prefix + name, value)
}
export function getLocalStorage (name: string) {
return window.localStorage.getItem(prefix + name)
}
export function removeLocalStorage (name: string) {
window.localStorage.removeItem(prefix + name)
}
export function clearLocal () {
window.localStorage.clear()
}
/**
* ============ sessionStorage ============
*/
export function setSessionStorage (name: string, value: any): void {
if (isEmpty(value)) return
window.sessionStorage.setItem(prefix + name, value)
}
export function getSessionStorage (name: string) {
window.sessionStorage.getItem(prefix + name)
}
export function removeSessionStorage (name: string) {
window.sessionStorage.removeItem(prefix + name)
}
/**
* 判斷值是否為null或者undefined或者''或者'undefined'
* @param val value
*/
function isEmpty (val: any) {
if (isNil(val) || val === 'undefined' || val === '') {
return true
}
return false
}
fetch
對axios進(jìn)行二次封裝,增加請求前后的攔截
import axios from 'axios'
/**
* 創(chuàng)建 axios 實(shí)例
*/
const service = axios.create({
timeout: 3000
})
/**
* req 攔截器
*/
service.interceptors.request.use((config: object): object => {
return config
}, (error: any): object => {
return Promise.reject(error)
})
/**
* res 攔截器
*/
service.interceptors.response.use((response: any) => {
const res = response.data
if (res.error) {
if (process.env.NODE_ENV !== 'production') {
console.error(res)
}
return Promise.reject(res)
}
return Promise.resolve(res)
})
export default service
請求參數(shù)統(tǒng)一處理
/**
* 統(tǒng)一參數(shù)處理
* 請求url處理
*/
const qs = require('qs')
import { merge, isPlainObject } from 'lodash'
import { getCookie } from '@/utils/cookies'
/**
* 接口參數(shù)拼接
* @param opts 接口參數(shù)
* @param opsIdParams 是否傳遞opsId
* @param requestType post 還是 get 參數(shù)處理
* @param otherParams 是否傳有其它參數(shù)
* @example
* commonParams({
* 'method': cmdName.login,
* 'params': params
* }, false, undefined, false)
*/
export function commonParams (opts: object, opsIdParams: boolean= true, requestType: string= 'post', otherParams: boolean= true): object {
const params = {
json: JSON.stringify(merge({
id: new Date().getTime(),
jsonrpc: '2.0',
params: dealParams(opsIdParams, otherParams),
}, opts || {})),
}
return requestType === 'post' ? qs.stringify(params) : params
}
/**
* 請求接口的地址處理
* @param urlData 請求接口
* @param type 請求路徑
* @example url(cmdName.login)
*/
export function url (urlData: string, type: any = process.env.VUE_APP_API_PATH) {
// @example https://example.com + agsgw/api/ + auth.agent.login
return process.env.VUE_APP_API_URL + type + urlData
}
/**
* params 參數(shù)的處理
* @param opsIdParams 是否傳遞opsId
* @param otherParams 是否傳有其它參數(shù)
*/
function dealParams (opsIdParams: boolean, otherParams: boolean | object): object {
let obj: any = {}
// opsIdParams 默認(rèn)傳opsId
if (opsIdParams) {
obj.opsId = getCookie('token') || ''
}
// otherParams其他默認(rèn)參數(shù), 如sn
if (otherParams === true) {
// obj.sn = getCookie('switchSn') || ''
} else {
// 其他object
if (isPlainObject(otherParams)) {
obj = {...obj, ...otherParams}
}
}
return obj
}
接口名稱單獨(dú)作為一個(gè)文件
/**
* 后臺接口名稱
*/
const cmdName = {
login: 'auth.agent.login'
}
export default cmdName
組合文件
/**
* 組合請求http的請求
*/
import fetch from '@/utils/fetch'
import cmdName from './cmdName'
import { commonParams, url } from './commonParams'
export {
fetch,
cmdName,
commonParams,
url
}
導(dǎo)出的請求文件
import { fetch, cmdName, url, commonParams } from '@/api/common'
export function login (params: object) {
return fetch({
url: url(cmdName.login),
method: 'post',
data: commonParams({
method: cmdName.login,
params
})
})
}
使用接口方式
import * as API from '@/api/index'
API.login(params).then(res => {
})
store改造
vuex的作用:分離遠(yuǎn)程記錄加載到本地存儲(chǔ)(操作)和 檢索從store 中的getter

- 數(shù)據(jù)加載策略
- 細(xì)節(jié)/全局構(gòu)造請求
- 導(dǎo)航響應(yīng)
- 權(quán)限(配合router控制權(quán)限)
使用:
- 使用
module形式 - 全局的一些操作,方法,放入
store中,業(yè)務(wù)邏輯盡量少放,項(xiàng)目全局方法可以放入。例如:cookie,global cache
action(異步): api的操作, 調(diào)用方式:this.$store.dispatch(functionName, data)
mutations(同步): dom相關(guān)操作,方法名一般使用常量,
調(diào)用方式: this.$store.commit(mutationsName, data)
this.$store.getters[XXX] => this.$store.getters[namespaced/XXX]
this.$store.dispatch(XXX, {}) => this.$store.dispatch(namespaced/XXX, {})
this.$store.commit(XXX, {}) => this.$store.commit(namespaced/XXX, {})
組件內(nèi)的Vue
<template>
<div>
<div>用戶名:<input type="text" v-model="username" /></div>
<div>密碼:<input type="password" v-model="passwd" /></div>
<div>{{computedMsg}}</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Provide } from 'vue-property-decorator'
// 引入組件
@Component({
components: {
// input
}
})
export default class Login extends Vue {
// data
@Provide() private username: string = ''
@Provide() private passwd: string = ''
// methods
login (u: string, p: string) {
}
// computed
get computedMsg () {
return 'username: ' + this.username
}
// life cycle
mounted () {
}
}
</script>
other
公用組件: dateRange, pagination, icon-font, clock, proxyAutocomplete, dialog

全局注入
Vue.component(modal.name, modal) // dialog Vue.component(pagination.name, pagination) // 分頁 Vue.component(dateRange.name, dateRange) // 日期 Vue.component(proxyAutocomplete.name, proxyAutocomplete) // 遠(yuǎn)程模糊搜索 Vue.component(card.name, card) // el-tabs Vue.component(tabLoad.name, tabLoad) // el-tabs
在main.ts中引入公用組件文件夾下的useElement
import '@/components/useElement'
一些問題
不能直接new
// 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type. // 不能直接new一個(gè)函數(shù),通過重新as一個(gè)變量,或者new其原型的constructor 都可以解決 // const encodePsw = new Encode.prototype.constructor().encodePsw(this.passwd) const E = Encode as any const encodePsw = new E().encodePsw(this.passwd)
不能直接導(dǎo)入文件后再追加屬性或方法
import * as filters from '@/filters/index'
// 全局filter
const F = filters as any
Object.keys(filters).forEach(item => {
Vue.filter(item, F[item])
})
declare var Chart: any;
@Component({
selector: 'my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.scss']
})
export class MyComponent {
//you can use Chart now and compiler wont complain
private color = Chart.color;
}
vue.config.js
const path = require('path')
const debug = process.env.NODE_ENV !== 'production'
const VueConf = require('./src/assets/js/libs/vue_config_class')
const vueConf = new VueConf(process.argv)
module.exports = {
baseUrl: vueConf.baseUrl, // 根域上下文目錄
outputDir: 'dist', // 構(gòu)建輸出目錄
assetsDir: 'assets', // 靜態(tài)資源目錄 (js, css, img, fonts)
pages: vueConf.pages,
lintOnSave: true, // 是否開啟eslint保存檢測,有效值:ture | false | 'error'
runtimeCompiler: true, // 運(yùn)行時(shí)版本是否需要編譯
transpileDependencies: [], // 默認(rèn)babel-loader忽略mode_modules,這里可增加例外的依賴包名
productionSourceMap: true, // 是否在構(gòu)建生產(chǎn)包時(shí)生成 sourceMap 文件,false將提高構(gòu)建速度
configureWebpack: config => { // webpack配置,值位對象時(shí)會(huì)合并配置,為方法時(shí)會(huì)改寫配置
if (debug) { // 開發(fā)環(huán)境配置
config.devtool = 'cheap-module-eval-source-map'
} else { // 生產(chǎn)環(huán)境配置
}
Object.assign(config, { // 開發(fā)生產(chǎn)共同配置
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@c': path.resolve(__dirname, './src/components'),
'vue$': 'vue/dist/vue.esm.js'
}
}
})
},
chainWebpack: config => { // webpack鏈接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
if (debug) {
// 本地開發(fā)配置
} else {
// 生產(chǎn)開發(fā)配置
}
},
css: { // 配置高于chainWebpack中關(guān)于css loader的配置
modules: true, // 是否開啟支持‘foo.module.css'樣式
extract: true, // 是否使用css分離插件 ExtractTextPlugin,采用獨(dú)立樣式文件載入,不采用<style>方式內(nèi)聯(lián)至html文件中
sourceMap: false, // 是否在構(gòu)建樣式地圖,false將提高構(gòu)建速度
loaderOptions: { // css預(yù)設(shè)器配置項(xiàng)
css: {
localIdentName: '[name]-[hash]',
camelCase: 'only'
},
stylus: {}
}
},
parallel: require('os').cpus().length > 1, // 構(gòu)建時(shí)開啟多進(jìn)程處理babel編譯
pluginOptions: { // 第三方插件配置
},
pwa: { // 單頁插件相關(guān)配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
},
devServer: {
open: true,
host: '0.0.0.0',
port: 8080,
https: false,
hotOnly: false,
proxy: {
'/api': {
target: '<url>',
ws: true,
changOrigin: true
}
},
before: app => {}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue項(xiàng)目在IE瀏覽器頁面白屏且報(bào)錯(cuò)SCRIPT1010:缺少標(biāo)識符問題
Vue項(xiàng)目在谷歌瀏覽器中正常運(yùn)行,但在IE瀏覽器中出現(xiàn)問題,如白屏和控制臺報(bào)錯(cuò),解決過程包括檢查IE設(shè)置、調(diào)整編輯器配置、引入兼容性插件、使用productionSourceMap定位錯(cuò)誤、檢查插件依賴和版本,以及重新構(gòu)建項(xiàng)目2024-09-09
關(guān)于vue3.0使用axios報(bào)錯(cuò)問題
這篇文章主要介紹了vue3.0使用axios報(bào)錯(cuò)問題記錄,vue-cli3.0安裝插件的時(shí)候要注意區(qū)分vue-cli2.0的命令,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
Ant Design moment對象和字符串之間的相互轉(zhuǎn)化教程
這篇文章主要介紹了Ant Design moment對象和字符串之間的相互轉(zhuǎn)化教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
vue實(shí)現(xiàn)button按鈕的重復(fù)點(diǎn)擊指令方式
這篇文章主要介紹了vue實(shí)現(xiàn)button按鈕的重復(fù)點(diǎn)擊指令方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
vue父組件與子組件之間的數(shù)據(jù)交互方式詳解
最近一直在做一個(gè)vue移動(dòng)端商城的實(shí)戰(zhàn),期間遇到一個(gè)小小的問題,值得一說,下面這篇文章主要給大家介紹了關(guān)于vue父組件與子組件之間數(shù)據(jù)交互的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11
vue的axios使用post時(shí)必須使用qs.stringify而get不用問題
這篇文章主要介紹了vue的axios使用post時(shí)必須使用qs.stringify而get不用問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
vue 使用 echarts 繪制中國地圖的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue 使用 echarts 繪制中國地圖,內(nèi)容包括插入echarts所需模塊及完整的代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01
vue中radio根據(jù)動(dòng)態(tài)值綁定checked無效的解決
這篇文章主要介紹了vue中radio根據(jù)動(dòng)態(tài)值綁定checked無效的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
vue.js 使用v-if v-else發(fā)現(xiàn)沒有執(zhí)行解決辦法
這篇文章主要介紹了vue.js 使用v-if v-else發(fā)現(xiàn)沒有執(zhí)行解決辦法的相關(guān)資料,需要的朋友可以參考下2017-05-05

