這裏準備採用的技術棧爲:vue全家桶+element-ui 這裏由於是後臺管理系統,沒有作SSR的必要。因此這裏就採用先後端分離來昨晚這個項目~javascript
vue init webpack gwc_manage
複製代碼
初始化過程當中,會讓咱們進行一些依賴包,項目配置的基本選擇。項目名稱,做者信息,描述,是否安裝路由,eslint,測試單元,npm/yarn。 這裏不選擇安裝eslint和測試單元。用過的人應該知道很是酸爽。 項目初始化成功後,css
npm run dev
複製代碼
能夠看到項目成功運行在8080端口。我麼就能夠打開8080端口查看咱們搭建好的項目 image-20190513171201664.png
上圖所述,就是vue初始化後的頁面。
npm install less less-loader -s
複製代碼
注:後面的-s表示本地安裝-g表示全局安裝,不些則表示默認本地安裝 由於使用了less後,我的通常喜歡將整個項目的配色進行一個管理。因此須要進行全局的配置。 這裏安裝完成後,繼續安裝html
npm install sass-resources-loader --save-dev
複製代碼
接下來,咱們找到build文件夾下的utils文件 exports.cssLoaders = function (options) {}中加上一下代碼:前端
function lessResourceLoader() {
var loaders = [
cssLoader,
'less-loader',
{
loader: 'sass-resources-loader',
options: {
resources: [
path.resolve(__dirname, '../src/assets/styles/common.less'),
]
}
}
];
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
複製代碼
注意位置必定要加對,且記得把path.resolve(__dirname,'../src/assets/styles/common.less')路徑改爲本身對應的文件。而後後面將 return{} 塊中的 less: generateLoaders('less') 替換成上面自定義的函數 less: lessResourceLoader(); 修改完配置文件記得重啓服務器:npm run dev 給你們上圖看一下主要配置: image-20190513172125756.png vue
重啓服務後,基本就配置完成。不過咱們仍是的檢測一下。 在common.less中寫入:@bg-blue: #3576e0;
複製代碼
在App.vue中修改java
<style lang="less" scoped>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
background-color: @bg-blue;
}
</style>
複製代碼
而後保存,打開瀏覽器。就能夠看到咱們配置好的全局變量被成功引用 image-20190513172403241.png webpack
背景色變成藍色。說明在common.less中定義的變量被正常調用。這裏全局的less配置也就成功了。項目搭建好了,可是能夠看到一些基本的樣式須要咱們進行更改ios
assets文件夾下styles文件中新建base.less文件。百度搜索reset.css而後複製文中的基本樣式,並添加html,body寬高爲100%便可。web
新建function.less文件css樣式工具封裝在文中找到適合本身項目的文件複製並粘貼金function.less文件。vue-router
新建index.css文件做爲出口文件。文件內容以下:
@import './base.less'; @import './function.less'; 在main.js文件中引入index.css文件
至此引入的基本的樣式文件就算被全局引用了。
至於封裝的function樣式類,咱們只須要在須要的時候,選擇性的 添加類名便可。
npm install element-ui -s
複製代碼
安裝完成後,在main.js中引入
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
複製代碼
安裝完成後,修改App.vue:
<template>
<div id="app">
<img src="./assets/logo.png">
<el-button type="danger">測試Element</el-button>
<router-view/>
</div>
</template>
複製代碼
打開瀏覽器,咱們能夠看到button按鈕是已經生效了。 image-20190513174650403.png
這裏,element-ui也已經安裝成功。在src文件夾下新建utils文件夾新建http.js爲咱們的請求方法的文件 image-20190513174918109.png
封裝前,咱們須要藉助axios來做爲請求的底層,而且須要緩存機制去緩存登陸狀態這裏藉助兩個依賴包 axios和vue-cookies
npm install axios vue-cookies -s
複製代碼
這裏封裝三個類型的。get請求一個post,json格式的一個post,body格式的一個
import axios from 'axios'
import Vue from 'vue'
// 請求方式的配置
export const postJsonRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
headers: {
'Content-Type': 'application/json',
},
});
}
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const getRequest = (url, data = {}) => {
return axios({
method: 'get',
params: data,
url: url,
});
}
複製代碼
這個就是請求方法的配置
隨後咱們在utils目錄下新建index.js文件做爲工具文件夾的出口文件
utils>index.js:
引入封裝的http請求並掛在到Vue原型鏈上供全局使用
import * as http from './http';
const install = (Vue, opts = {}) => {
if (install.installed) return;
Vue.prototype.$http = http;
}
export default install
main.js
import Utils from './utils';
Vue.use(Utils);
複製代碼
這裏方法請求的封裝就算是完成了。
攔截器的配置
攔截器:登陸狀態的管理,以及每次請求時,咱們作的一些處理。對不一樣code狀態作的不一樣的處理
攔截器分爲請求攔截器和響應攔截器。字面意思可理解爲:請求時的攔截和響應時的攔截
import axios from 'axios'
import { Message } from 'element-ui'
import router from 'vue-router'
import Vue from 'vue'
import VueCookies from 'vue-cookies'
// 請求攔截
axios.interceptors.request.use(config => {
if (VueCookies.isKey('isLogin')) {
const token = getToken(config);
config.headers['token'] = token;
}
return config;
}, err => {
Message.error({
message: '請求超時!'
});
return Promise.resolve(err);
})
// 響應攔截
axios.interceptors.response.use(res => {
switch (res.data.code) {
case 200:
return res.data.result;
case 401:
Message.error({
message: res.data.message
});
router.push('/login');
VueCookies.remove('userinfo');
return Promise.reject(res);
case 201:
Message.error({
message: res.data.message
});
case 403:
Message.warning({
message: res.data.message
});
return Promise.reject(res);
default:
return Promise.reject(res);
}
}, err => {
if (!err.response) {
return false;
}
switch (err.response.status) {
case 500:
Message.error({
message: '服務器出小差了⊙﹏⊙∥'
});
break;
case 504:
Message.error({
message: '服務器被吃了⊙﹏⊙∥'
});
break;
case 404:
Message.error({
message: '服務器被吃了⊙﹏⊙∥'
});
break;
case 403:
Message.error({
message: '權限不足,請聯繫管理員!'
});
break;
default:
Message.error({
message: '網絡超時'
});
}
return Promise.reject(err);
})
複製代碼
Vue攔截器的基本配置也就是以上這些了。下來我的想要實現一個loading的局部加載。就要藉助計數器了。
爲何說要作一個計數器?
由於在同一個view中可能會有不少個請求,咱們總不可能在一個請求完成後就關閉loading的加載吧?這樣顯然不合適。因此咱們須要計時器去將全部的請求記錄起來。而後在全部的請求完成後關閉loading。
//請求時loading配置
var loading;
function startLoading() {
loading = Vue.prototype.$loading({
lock: true,
text: "Loading...",
background: 'rgba(0, 0, 0, 0.5)',
target: document.querySelector('.loading-area') //設置加載動畫區域
});
}
function endLoading() {
loading.close();
}
var needLoadingRequestCount = 0;
//開啓loading並計數
function showFullScreenLoading() {
if (needLoadingRequestCount === 0) {
startLoading();
}
needLoadingRequestCount++;
};
//計數器==0關閉loading
function tryHideFullScreenLoading() {
if (needLoadingRequestCount <= 0) return;
needLoadingRequestCount--;
if (needLoadingRequestCount === 0) {
endLoading();
}
};
複製代碼
loading的依賴在element安裝後是直接掛在到了vue的原型鏈上。咱們再也不須要作過多處理。這裏計數器完成。下來咱們只須要在請求的時候調用,在響應的時候或者請求報錯的時候調用關閉的方法便可。
須要注意的是要實現局部的加載,咱們就須要在響應實現loading的地方添加類型loading-area才能夠!!!
http.js全部代碼以下:
/** * @description 配置網絡請求 * @author luokaibin chaizhiyang */
import axios from 'axios'
import { Message } from 'element-ui'
import router from 'vue-router'
import Vue from 'vue'
import VueCookies from 'vue-cookies'
axios.defaults.timeout = 300000; // 請求超時5fen
//請求時loading配置
var loading;
function startLoading() {
loading = Vue.prototype.$loading({
lock: true,
text: "Loading...",
background: 'rgba(0, 0, 0, 0.5)',
target: document.querySelector('.loading-area') //設置加載動畫區域
});
}
function endLoading() {
loading.close();
}
var needLoadingRequestCount = 0;
function showFullScreenLoading() {
if (needLoadingRequestCount === 0) {
startLoading();
}
needLoadingRequestCount++;
};
function tryHideFullScreenLoading() {
if (needLoadingRequestCount <= 0) return;
needLoadingRequestCount--;
if (needLoadingRequestCount === 0) {
endLoading();
}
};
// 請求攔截
axios.interceptors.request.use(config => {
showFullScreenLoading();
if (VueCookies.isKey('userinfo')) {
const token = getToken(config);
config.headers['token'] = token;
}
return config;
}, err => {
tryHideFullScreenLoading();
Message.error({
message: '請求超時!'
});
return Promise.resolve(err);
})
// 響應攔截
axios.interceptors.response.use(res => {
tryHideFullScreenLoading();
switch (res.data.code) {
case 200:
return res.data.result;
case 401:
Message.error({
message: res.data.message
});
router.push('/login');
// VueCookies.remove('userinfo');
return Promise.reject(res);
case 201:
Message.error({
message: res.data.message
});
case 403:
Message.warning({
message: res.data.message
});
return Promise.reject(res);
default:
return Promise.reject(res);
}
}, err => {
tryHideFullScreenLoading();
if (!err.response) {
return false;
}
switch (err.response.status) {
case 500:
Message.error({
message: '服務器出小差了⊙﹏⊙∥'
});
break;
case 504:
Message.error({
message: '服務器被吃了⊙﹏⊙∥'
});
break;
case 404:
Message.error({
message: '服務器被吃了⊙﹏⊙∥'
});
break;
case 403:
Message.error({
message: '權限不足,請聯繫管理員!'
});
break;
default:
Message.error({
message: '網絡超時'
});
}
return Promise.reject(err);
})
// 請求方式的配置
export const postJsonRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
headers: {
'Content-Type': 'application/json',
},
});
}
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const getRequest = (url, data = {}) => {
return axios({
method: 'get',
params: data,
url: url,
});
}
複製代碼
至此整個的全局loading,攔截器,fetch方法的封裝就算完成了。
element-ui的使用,咱們要多借助官方文檔去靈活使用。而不是死記硬背。太多的ui框架,再強的大腦也背不過來,況且,爲了本身的頭髮着想一下啦~
這裏並未設置跨域訪問。你們能夠根據vue的代理。這樣也是能夠進行跨域訪問的。詳見個人這篇博文Vue設置代理進行跨域訪問,不過這篇文章是針對vue3.0設置,2.0的設置文件,爲config下的index.js文件。固然前提是後端接口也進行跨域的設置,不然單純的前端設置是沒有做用的。
局部loading的使用,要求有一個好的佈局基礎。不然,在後期的使用過程當中,會有喝多樣式錯亂的問題。
請求方式有不少種,還有下載文件的請求配置,delete,post,put等等你們可根據本身需求靈活配置。最終的使用this.$http. get/post/put/...等等就能夠進行調用
底層佈局(Layout),路由(Router),狀態庫(vuex),Github倉庫關聯。
敬請期待~