一、安裝
【1.1】安裝Node
3.x需要node.js版本為8.9版或者更高的版本,點(diǎn)擊這里可以安裝node
安裝過node后,輸入下面命令行查詢你的node版本:
node -v
如果當(dāng)前版本不夠,可以輸入下面命令行來把node版本更新到最新的穩(wěn)定版本
先清除npm緩存:npm cache clean -f
然后安裝n模塊:npm install -g n
升級(jí)node.js到最新穩(wěn)定版:n stable
如果是mac 在命令前面加sudo:sudo n stable
【1.2】卸載舊版本
如果你之前已經(jīng)全局安裝過舊版本的vue-cli,需要先卸載它
npm uninstall vue-cli -g
【1.3】安裝vue-cli3
// 安裝vue-cli3
npm install -g @vue/cli
// 安裝后查看版本號(hào)
vue -V 或者 vue --version
二、創(chuàng)建項(xiàng)目
【2.1】創(chuàng)建項(xiàng)目命令
vue create project // project是項(xiàng)目名稱
【2.2】選擇模板

- default (babel, eslint): 默認(rèn)配置,只有Babel和eslint,其他的都要自己另外再配置
- Manually select features: 手動(dòng)配置
通過上下箭頭可以切換選項(xiàng),這里我們選擇手動(dòng)配置
【2.3】選擇配置

根據(jù)你的項(xiàng)目需要來選擇配置
- 括號(hào)里有*代表選中
- 上下箭頭可切換選項(xiàng)
- Space空格鍵是切換選中與取消
- A鍵是切換全部選中和全部取消
- I鍵是反向選擇
- Enter確認(rèn)選擇完成
這邊選擇了(Babel、Router、Vuex、CSS預(yù)處理器、Linter / Formatter格式檢查)
再次詢問是否保存配置:
- 是否使用路由的 histroy 模式(Yes)

2)選擇一個(gè)css預(yù)處理器(Sass/SCSS)

3)選擇一個(gè)eslint配置(ESLint + Standard config)

4)選擇什么時(shí)候進(jìn)行eslint代碼規(guī)則檢查(Lint on save)

5)將babel、postcss、eslint這些配置文件放哪(In dedicated config files)

6)是否保存這份預(yù)設(shè)配置(Yes)

選擇是的話,會(huì)讓你填寫一個(gè)預(yù)設(shè)文件的名字,下次創(chuàng)建一個(gè)vue項(xiàng)目,可以直接使用這個(gè)預(yù)設(shè)文件,而無需再進(jìn)行配置。

【2.4】生成目錄結(jié)構(gòu)
- node_modules: 這個(gè)文件夾里面是我們項(xiàng)目需要的一些依賴;
- public: 靜態(tài)文件夾,這個(gè)文件夾中的資源不會(huì)被webpack編譯,構(gòu)建生產(chǎn)包的時(shí)候,會(huì)被直接拷貝一份;
- assets: 是頁(yè)面和組件中用到的靜態(tài)資源,比如公共樣式文件,字體文件,圖片等,該文件夾與public的區(qū)別是:該文件夾中的資源會(huì)被webpack編譯;
- components: 文件夾中存放我們的組件;
- views: 文件夾中存放我們的頁(yè)面;
- App.vue: 這個(gè)文件是我們所有vue頁(yè)面的頂層文件;
- main.js: 是我們整個(gè)項(xiàng)目的入口文件;
- router.js: 是路由的配置文件;
- store.js: 是vuex的配置文件;
- .browserslistrc: 文件用于給開發(fā)者設(shè)置瀏覽器版本的范圍;
- .eslintrc.js: eslint配置文件;
- .gitignore: 需要git忽略的文件;
- babel.config.js: babel的配置工具;
- package-lock.json: 記錄項(xiàng)目依賴中各個(gè)依賴之間的關(guān)系和版本,防止npm包中有不遵守“相同大版本號(hào)的同一個(gè)庫(kù)包,其接口符合兼容要求”
- 這一規(guī)范,導(dǎo)致項(xiàng)目運(yùn)行報(bào)錯(cuò);
- package.json: 項(xiàng)目的描述文件,包括項(xiàng)目名、依賴的版本、作者、命令、入口文件等信息。
- README.md: 項(xiàng)目的說明文檔,項(xiàng)目介紹、License、一些命令(例如:?jiǎn)?dòng)命令、打包命令、單元測(cè)試命令等)
vue-cli3和vue-cli2的區(qū)別在于:
- 創(chuàng)建項(xiàng)目 vue create
- 啟動(dòng)項(xiàng)目 由npm run dev 改成 npm run serve
- 移除了配置文件目錄 config 和 build 文件夾,如果需要自定義配置,需要自己新建vue.config.js文件
- 移除了 static 靜態(tài)資源文件夾,新增 public 文件夾,靜態(tài)資源轉(zhuǎn)移到public目錄中,通過/xx.xx可以直接訪問,并且 index.html 移動(dòng)到 public 中
- 在 src 文件夾中新增了 views 文件夾,用于分類 視圖組件 和 公共組件
- 安裝項(xiàng)目時(shí)會(huì)自動(dòng)下載node-model文件夾
【2.5】啟動(dòng)項(xiàng)目
npm run serve
三、修改目錄結(jié)構(gòu)
由于現(xiàn)在的目錄結(jié)構(gòu)不利于后期的開發(fā),現(xiàn)在我們?cè)黾硬糠治募?,待后續(xù)可以進(jìn)行功能擴(kuò)展。在src文件下:新建api文件夾,router文件夾,utils文件夾,views文件夾,store文件夾。并在其文件下建子目錄,詳細(xì)請(qǐng)參考目錄截圖:

四、項(xiàng)目配置 Vue.config.js
vue-cli3.0構(gòu)建項(xiàng)目目錄中沒有build和config目錄,那么問題來了,我們?nèi)绾稳ラ_發(fā)我們的項(xiàng)目呢?(比如設(shè)置代理、打包配置等問題)只需要在項(xiàng)目根目錄中添加vue.config.js文件,注意是根目錄非src下,它會(huì)被 @vue/cli-service 自動(dòng)加載。參考Vue CLI
配置如下:
// vue.config.js
const path = require('path');
function resolve(dir) {
return path.join(__dirname, dir);
}
module.exports = {
// 部署應(yīng)用包時(shí)的基本URL,默認(rèn)為'/'
// 假設(shè)你的應(yīng)用將會(huì)部署在域名的根部,比如,https://www.vue-cli.com/,則設(shè)置為"/"
// 如果你的應(yīng)用是部署在一個(gè)子路徑下,那么你需要在這里指定子路徑,比如,如果你部署在 https://www.my-vue.com/my-app/; 那么將這個(gè)值改為 “/my-app/”
publicPath: "/",
//將構(gòu)建好的文件輸出到哪里 當(dāng)運(yùn)行 vue-cli-service build 時(shí)生成的生產(chǎn)環(huán)境構(gòu)建文件的目錄。注意目標(biāo)目錄在構(gòu)建之前會(huì)被清除 (構(gòu)建時(shí)傳入 --no-clean 可關(guān)閉該行為)。
outputDir: "dist",
//放置生成的靜態(tài)資源(js、css、img、fonts)的目錄。
assetsDir: "",
// 指定生成的 index.html 的輸出路徑
indexPath: "index.html",
// 默認(rèn)情況下,生成的靜態(tài)資源在它們的文件名中包含了 hash 以便更好的控制緩存。然而,這也要求 index 的 HTML 是被 Vue CLI 自動(dòng)生成的。如果你無法使用 Vue CLI 生成的 index HTML,你可以通過將這個(gè)選項(xiàng)設(shè)為 false 來關(guān)閉文件名哈希
filenameHashing: true,
// 構(gòu)建多頁(yè)面應(yīng)用,頁(yè)面的配置
pages: {
index: {
// page 的入口
entry: 'src/main.js',
// 模板來源
template: 'public/index.html',
// 在 dist/index.html 的輸出
filename: 'index.html',
// 當(dāng)使用 title 選項(xiàng)時(shí),
// template 中的 title 標(biāo)簽需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// 在這個(gè)頁(yè)面中包含的塊,默認(rèn)情況下會(huì)包含
// 提取出來的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
// 當(dāng)使用只有入口的字符串格式時(shí),
// 模板會(huì)被推導(dǎo)為 `public/subpage.html`
// 并且如果找不到的話,就回退到 `public/index.html`。
// 輸出文件名會(huì)被推導(dǎo)為 `subpage.html`。
// subpage: 'src/subpage/main.js'
},
// 是否在開發(fā)環(huán)境下通過 eslint-loader 在每次保存時(shí) lint 代碼。這個(gè)值會(huì)在 @vue/cli-plugin-eslint 被安裝之后生效。
// 設(shè)置為 true 時(shí),eslint-loader 會(huì)將 lint 錯(cuò)誤輸出為編譯警告。默認(rèn)情況下,警告僅僅會(huì)被輸出到命令行,且不會(huì)使得編譯失敗。
// 如果你希望讓 lint 錯(cuò)誤在開發(fā)時(shí)直接顯示在瀏覽器中,你可以使用 lintOnSave: 'error'。這會(huì)強(qiáng)制 eslint-loader 將 lint 錯(cuò)誤輸出為編譯錯(cuò)誤,同時(shí)也意味著 lint 錯(cuò)誤將會(huì)導(dǎo)致編譯失敗。
lintOnSave: false,
//是否使用包含運(yùn)行時(shí)編譯器的 Vue 構(gòu)建版本。設(shè)置為 true 后你就可以在 Vue 組件中使用 template 選項(xiàng)了,但是這會(huì)讓你的應(yīng)用額外增加 10kb 左右。
runtimeCompiler: false,
// 默認(rèn)情況下 babel-loader 會(huì)忽略所有 node_modules 中的文件。如果你想要通過 Babel 顯式轉(zhuǎn)譯一個(gè)依賴,可以在這個(gè)選項(xiàng)中列出來。
transpileDependencies: [],
//如果你不需要生產(chǎn)環(huán)境的 source map,可以將其設(shè)置為 false 以加速生產(chǎn)環(huán)境構(gòu)建。
productionSourceMap: true,
//是一個(gè)函數(shù),會(huì)接收一個(gè)基于 webpack-chain 的 ChainableConfig 實(shí)例。允許對(duì)內(nèi)部的 webpack 配置進(jìn)行更細(xì)粒度的修改。
chainWebpack: (config) => {
//配置別名
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('components', resolve('src/components'))
.set('router', resolve('src/router'))
.set('utils', resolve('src/utils'))
.set('store', resolve('src/store'))
.set('views', resolve('src/views'))
},
//是否為 Babel 或 TypeScript 使用 thread-loader。該選項(xiàng)在系統(tǒng)的 CPU 有多于一個(gè)內(nèi)核時(shí)自動(dòng)啟用,僅作用于生產(chǎn)構(gòu)建。
parallel: require("os").cpus().length > 1,
// 向 PWA 插件傳遞選項(xiàng)。
// https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
pwa: {},
// 所有 webpack-dev-server 的選項(xiàng)都支持。注意:有些值像 host、port 和 https 可能會(huì)被命令行參數(shù)覆寫。
//有些值像 publicPath 和 historyApiFallback 不應(yīng)該被修改,因?yàn)樗鼈冃枰烷_發(fā)服務(wù)器的 publicPath 同步以保障正常的工作。
// 代理配置
devServer: {
host: "0.0.0.0",
port: 8080, // 端口號(hào)
https: false, // https:{type:Boolean}
open: true, // 配置自動(dòng)啟動(dòng)瀏覽器 open: 'Google Chrome'-默認(rèn)啟動(dòng)谷歌
// 配置單個(gè)代理
// proxy: 'http://localhost:9000'
// 配置多個(gè)代理
proxy: {
"/api": {
// target: "https://127.0.0.0:8080", // 目標(biāo)主機(jī)
target: "https://mock.yonyoucloud.com/mock/5708",
ws: true, //代理的WebSockets
changeOrigin: true, // 允許websockets跨域
pathRewrite: {
"^/api": ""
}
}
}
},
// 第三方插件選項(xiàng)
// 這是一個(gè)不進(jìn)行任何 schema 驗(yàn)證的對(duì)象,因此它可以用來傳遞任何第三方插件選項(xiàng)。
pluginOptions: {
foo: {
// 插件可以作為 `options.pluginOptions.foo` 訪問這些選項(xiàng)。
}
},
// 有的時(shí)候你想要向 webpack 的預(yù)處理器 loader 傳遞選項(xiàng)。你可以使用 vue.config.js 中的 css.loaderOptions 選項(xiàng)。比如你可以這樣向所有 Sass/Less 樣式傳入共享的全局變量
css: {
loaderOptions: {
// 給 sass-loader 傳遞選項(xiàng)
sass: {
prependData: `
@import "@/assets/css/common.scss";
@import "@/assets/css/mixin.scss";
@import "@/assets/css/reset.scss";
@import "@/assets/css/var.scss";
`
}
}
},
};
五、全局樣式引用
在項(xiàng)目開發(fā)過程中,我們經(jīng)常需要全局樣式引用,例如主題色等,如果每次去寫的化會(huì)變得很麻煩。因?yàn)槲覀儜?yīng)該了sass預(yù)語(yǔ)言編譯,所以可以大膽的應(yīng)用其特性。例如變量,函數(shù),混入等。但是我們需要在項(xiàng)目中進(jìn)行全局的配置才能有效果。不用在每一個(gè)頁(yè)面都進(jìn)行引入樣式,就能直接引用。
【5.1】新建目錄
在assets文件下增加css文件夾,在css文件夾下新建如下幾個(gè)樣式代碼文件,具體的代碼自行進(jìn)行配置
common.scss 主要存放公共的樣式
mixin.scss 主要存放混入樣式
reset.scss 主要存放重置樣式。
var.scss 主要存放變量

【5.2】全局引入
在vue.config.js配置文件中,加上以下代碼
module.exports = {
css: {
loaderOptions: {
// 給 sass-loader 傳遞選項(xiàng)
sass: {
prependData: `
@import "@/assets/css/common.scss";
@import "@/assets/css/mixin.scss";
@import "@/assets/css/reset.scss";
@import "@/assets/css/var.scss";
`
}
}
},
}
六、打包配置
在實(shí)際項(xiàng)目的開發(fā)中,我們一般會(huì)經(jīng)歷項(xiàng)目的開發(fā)階段、測(cè)試階段、預(yù)發(fā)布階段和最終上線階段,每一個(gè)階段對(duì)于項(xiàng)目代碼的要求可能都不盡相同,那么我們?nèi)绾文軌蛴稳杏杏嗟脑诓煌A段下使我們的項(xiàng)目呈現(xiàn)不同的效果,使用不同的功能呢?這里就需要引入環(huán)境的概念。作為一名開發(fā)人員,我們可能需要針對(duì)每一種環(huán)境編寫一些不同的代碼并且保證這些代碼運(yùn)行在正確的環(huán)境中,這就需要我們進(jìn)行正確的環(huán)境配置和管理。
一般一個(gè)項(xiàng)目都會(huì)有以下 4 種環(huán)境:
- 開發(fā)環(huán)境(開發(fā)階段,本地開發(fā)版本,一般會(huì)使用一些調(diào)試工具或額外的輔助功能)
- 測(cè)試環(huán)境(測(cè)試階段,上線前版本,除了一些 bug 的修復(fù),基本不會(huì)和上線版本有很大差別)
- 預(yù)發(fā)布環(huán)境(即將上線階段,上線前版本,預(yù)測(cè)線上出現(xiàn)問題的可能性,和上線版本無差別)
- 生產(chǎn)環(huán)境(上線階段,正式對(duì)外發(fā)布的版本,一般會(huì)進(jìn)行優(yōu)化,關(guān)掉錯(cuò)誤報(bào)告)
有關(guān)環(huán)境變量的注意事項(xiàng):
- 環(huán)境文件放置根目錄下
- 環(huán)境名應(yīng)該與環(huán)境文件統(tǒng)一
- 除了 baseUrl 和 NODE_ENV 其他環(huán)境變量使用VUE_APP開頭
在項(xiàng)目的根目錄新建4個(gè)文件夾,分別對(duì)應(yīng)開發(fā)環(huán)境(.env.dev),測(cè)試環(huán)境(.env.test),預(yù)發(fā)布環(huán)境(.env.pre),生產(chǎn)環(huán)境(env.prod)

.env.dev文件內(nèi)容如下:
NODE_ENV = 'development'
VUE_APP_CURRENTMODE = 'dev'
VUE_APP_BASEURL = '本地開發(fā)api地址'
.env.test文件內(nèi)容如下:
NODE_ENV = 'test'
VUE_APP_CURRENTMODE = 'test'
VUE_APP_BASEURL = '測(cè)試環(huán)境api地址'
.env.pre文件內(nèi)容如下:
NODE_ENV = 'pre-release'
VUE_APP_CURRENTMODE = 'pre'
VUE_APP_BASEURL = '預(yù)發(fā)布環(huán)境api地址'
env.prod文件內(nèi)容如下:
NODE_ENV = 'production'
VUE_APP_CURRENTMODE = 'prod'
VUE_APP_BASEURL = '正式環(huán)境api地址'
package.json配置:
"scripts": {
"dev": "vue-cli-service serve",
"build:test": "vue-cli-service build --mode test",
"build:per": "vue-cli-service build --mode pre-release",
"build:prod": "vue-cli-service build --mode production",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
.最后根據(jù)上面的配置進(jìn)行打包:
- npm run dev //本地運(yùn)行
- npm run build:test //測(cè)試環(huán)境打包
- npm run build:pre //預(yù)測(cè)試環(huán)境打包
- npm run build:prod //正式環(huán)境打包
注意:
在vue.config.js使用 proccess.env.NODE_ENV 進(jìn)行訪問就可以了
// vue.config.js
console.log(process.env.NODE_ENV); // development(在終端輸出)
當(dāng)你運(yùn)行 npm run dev命令后會(huì)發(fā)現(xiàn)輸出的是 development,因?yàn)?vue-cli-service serve 命令默認(rèn)設(shè)置的環(huán)境是 development,你可以修改 package.json 中的 dev 腳本的命令為:
"scripts": {
"dev": "vue-cli-service serve --mode test",
}
// --mode test其實(shí)就是修改了 webpack 4 中的 mode 配置項(xiàng)為 test,同時(shí)其會(huì)讀取對(duì)應(yīng) .env.[model]文件下的配置
// 如果沒找到對(duì)應(yīng)配置文件,其會(huì)使用默認(rèn)環(huán)境 development
// 同樣 vue-cli-service build 會(huì)使用默認(rèn)環(huán)境 production
七、安裝使用iview
【7.1】安裝iview
npm install iview -S
【7.2】main.js 引入iview
import iview from 'iview'
import 'iview/dist/styles/iview.css'
Vue.use(iview)

八、axios封裝
在vue項(xiàng)目中,和后臺(tái)交互獲取數(shù)據(jù)這塊,我們通常使用的是axios庫(kù),它是基于promise的http庫(kù),可運(yùn)行在瀏覽器端和node.js中。他有很多優(yōu)秀的特性,例如攔截請(qǐng)求和響應(yīng)、取消請(qǐng)求、轉(zhuǎn)換json、客戶端防御XSRF等。所以我們的尤大大也是果斷放棄了對(duì)其官方庫(kù)vue-resource的維護(hù),直接推薦我們使用axios庫(kù)。如果還對(duì)axios不了解的,可以移步 axios中文說明
【8.1】安裝
npm install axios --save-dev
【8.2】新建目錄
在src目錄下新建一個(gè)api文件夾,然后在里面新建一個(gè)axios.js和一個(gè)getData.js文件;axios.js文件用來封裝我們的axios,getData.js用來統(tǒng)一管理我們的接口。

?
【8.3】axios.js封裝axios
import axios from "axios";
import { Message } from "iview";
let router = import("@/router");
axios.defaults.baseURL = "/api";
axios.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8";
axios.defaults.headers["X-Requested-With"] = "XMLHttpRequest";
axios.defaults.headers["Cache-Control"] = "no-cache";
axios.defaults.headers["pragma"] = "no-cache";
let source = axios.CancelToken.source();
//請(qǐng)求添加token
axios.interceptors.request.use(request => {
request.headers["Authorization"] = window.localStorage.getItem('token') ? window.localStorage.getItem('token') : "";
return request;
});
//登錄過期(token失效)跳轉(zhuǎn)到登錄頁(yè)
axios.interceptors.response.use(response => {
let data = response.data;
if (
data.state && [401].includes(data.state.code)
) {
router.then(lib => {
if (lib.default.currentRoute.name === "login") return;
lib.default.push({
name: "login"
})
Message.warning(data.state.msg);
});
}
return response;
})
//返回值解構(gòu)
axios.interceptors.response.use(response => {
let data = response.data;
let isJson = (response.headers["content-type"] || "").includes("json");
if (isJson) {
if (data.state && data.state.code === 200) {
return Promise.resolve({
data: data.data,
msg: data.state.msg,
code: data.state.code,
page: data.page
});
}
return Promise.reject(
data.state &&
data.state.msg ||
"網(wǎng)絡(luò)錯(cuò)誤"
);
} else {
return data;
}
}, err => {
let isCancel = axios.isCancel(err);
if (isCancel) {
return new Promise(() => {});
}
return Promise.reject(
err.response.data &&
err.response.data.state &&
err.response.data.state.msg ||
"網(wǎng)絡(luò)錯(cuò)誤"
);
})
//切換頁(yè)面取消請(qǐng)求
axios.interceptors.request.use(request => {
request.cancelToken = source.token;
return request;
});
router.then(lib => {
lib.default.beforeEach((to, from, next) => {
source.cancel()
source = axios.CancelToken.source();
next()
})
})
export function post(url, data, otherConfig) {
return axios.post(url, data, otherConfig);
}
export function get(url, data, otherConfig) {
return axios.get(url, {
params: data,
...otherConfig
});
}
【8.4】getData.js 接口管理(例子)
import {get, post } from "./axios";
//獲取程序配置
export function getConfig() {
return get("static/config.json", null, { baseURL: "./" });
}
//獲取用戶信息(統(tǒng)一認(rèn)證登錄的用戶)
export function getLoginInfo() {
return get("/oauth/getLoginInfo");
}
//登錄
export function login(params) {
return post("/oauth/login", params);
}
//退出
export function logout(params) {
return get("/oauth/logout", params);
}
【8.5】頁(yè)面調(diào)用接口(例子)
import { login } from "@/api/getData.js";
export default {
data() {
return {
userName: '',
password: ''
};
},
methods: {
async login() {
try {
this.loading = true;
let { msg } = await login({
userName: this.userName,
userPwd: this.password
});
this.$Message.success(msg);
this.$router.push({ name: "loginPage" });
} catch (e) {
this.$Message.warning(e);
} finally {
this.loading = false;
}
},
}
};
九、登錄攔截(權(quán)限控制)
vue+router+axios 實(shí)現(xiàn)后臺(tái)管理系統(tǒng)登錄攔截(權(quán)限控制)