Vue實戰狗尾草博客後臺管理系統

Vue實戰狗尾草博客後臺管理系統第一章

這裏準備採用的技術棧爲:vue全家桶+element-ui 這裏由於是後臺管理系統,沒有作SSR的必要。因此這裏就採用先後端分離來昨晚這個項目~javascript

項目搭建

vue init webpack gwc_manage
複製代碼

初始化過程當中,會讓咱們進行一些依賴包,項目配置的基本選擇。項目名稱,做者信息,描述,是否安裝路由,eslint,測試單元,npm/yarn。 這裏不選擇安裝eslint和測試單元。用過的人應該知道很是酸爽。 項目初始化成功後,css

npm run dev
複製代碼

能夠看到項目成功運行在8080端口。我麼就能夠打開8080端口查看咱們搭建好的項目 image-20190513171201664.png
上圖所述,就是vue初始化後的頁面。

安裝less並配置全局的變量

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

  1. assets文件夾下styles文件中新建base.less文件。百度搜索reset.css而後複製文中的基本樣式,並添加html,body寬高爲100%便可。web

  2. 新建function.less文件css樣式工具封裝在文中找到適合本身項目的文件複製並粘貼金function.less文件。vue-router

  3. 新建index.css文件做爲出口文件。文件內容以下:

@import './base.less'; @import './function.less'; 在main.js文件中引入index.css文件

至此引入的基本的樣式文件就算被全局引用了。

至於封裝的function樣式類,咱們只須要在須要的時候,選擇性的 添加類名便可。

安裝element-ui

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
複製代碼
  1. 請求方法封裝。

    這裏封裝三個類型的。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);
複製代碼

這裏方法請求的封裝就算是完成了。

  1. 攔截器的配置

    攔截器:登陸狀態的管理,以及每次請求時,咱們作的一些處理。對不一樣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方法的封裝就算完成了。

總結

  1. element-ui的使用,咱們要多借助官方文檔去靈活使用。而不是死記硬背。太多的ui框架,再強的大腦也背不過來,況且,爲了本身的頭髮着想一下啦~

  2. 這裏並未設置跨域訪問。你們能夠根據vue的代理。這樣也是能夠進行跨域訪問的。詳見個人這篇博文Vue設置代理進行跨域訪問,不過這篇文章是針對vue3.0設置,2.0的設置文件,爲config下的index.js文件。固然前提是後端接口也進行跨域的設置,不然單純的前端設置是沒有做用的。

  3. 局部loading的使用,要求有一個好的佈局基礎。不然,在後期的使用過程當中,會有喝多樣式錯亂的問題。

  4. 請求方式有不少種,還有下載文件的請求配置,delete,post,put等等你們可根據本身需求靈活配置。最終的使用this.$http. get/post/put/...等等就能夠進行調用

下一章節:

底層佈局(Layout),路由(Router),狀態庫(vuex),Github倉庫關聯。

敬請期待~

相關文章
相關標籤/搜索