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


 源碼地址:https://github.com/18291907191/gwc_manage

Vue實戰狗尾草博客后台管理系統第一章

這里准備采用的技術棧為:vue全家桶+element-ui

這里因為是后台管理系統,沒有做SSR的必要。所以這里就采用前后端分離來昨晚這個項目~

項目搭建

vue init webpack gwc_manage
 初始化過程中,會讓我們進行一些依賴包,項目配置的基本選擇。項目名稱,作者信息,描述,是否安裝路由,eslint,測試單元,npm/yarn。

這里不選擇安裝eslint和測試單元。用過的人應該知道非常酸爽。

項目初始化成功后,

npm run dev

可以看到項目成功運行在8080端口。我么就可以打開8080端口查看我們搭建好的項目

 

 

上圖所述,就是vue初始化后的頁面。

安裝less並配置全局的變量

npm install less less-loader -s

注:后面的-s表示本地安裝-g表示全局安裝,不些則表示默認本地安裝

因為使用了less后,個人一般喜歡將整個項目的配色進行一個管理。所以需要進行全局的配置。

這里安裝完成后,繼續安裝

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

給大家上圖看一下主要配置:

重啟服務后,基本就配置完成。不過我們還是的檢測一下。

在common.less中寫入:

@bg-blue: #3576e0;

在App.vue中修改

<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>

然后保存,打開瀏覽器。就可以看到我們配置好的全局變量被成功引用

 

 

背景色變成藍色。說明在common.less中定義的變量被正常調用。這里全局的less配置也就成功了。

引入全局的基本樣式

項目搭建好了,但是可以看到一些基本的樣式需要我們進行更改

  1. assets文件夾下styles文件中新建base.less文件。百度搜索reset.css然后復制文中的基本樣式,並添加html,body寬高為100%即可。

  2. 新建function.less文件css樣式工具封裝在文中找到適合自己項目的文件復制並粘貼金function.less文件。

  3. 新建index.css文件作為出口文件。文件內容如下:

@import './base.less';
@import './function.less';
  1. 在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按鈕是已經生效了。

這里,element-ui也已經安裝成功。

請求方法,攔截器,全局加載框的配置

在src文件夾下新建utils文件夾新建http.js為我們的請求方法的文件

封裝前,我們需要借助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倉庫關聯。

敬請期待~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM