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

Vue实战狗尾草博客后台管理系统第一章

这里准备采用的技术栈为:vue全家桶+element-ui

这里因为是后台管理系统,没有做SSR的必要。所以这里就采用前后端分离来昨晚这个项目~

项目搭建

  1. vue init webpack gwc_manage
 初始化过程中,会让我们进行一些依赖包,项目配置的基本选择。项目名称,作者信息,描述,是否安装路由,eslint,测试单元,npm/yarn。

这里不选择安装eslint和测试单元。用过的人应该知道非常酸爽。

项目初始化成功后,

  1. npm run dev

可以看到项目成功运行在8080端口。我么就可以打开8080端口查看我们搭建好的项目

上图所述,就是vue初始化后的页面。

安装less并配置全局的变量

  1. npm install less less-loader -s

注:后面的-s表示本地安装-g表示全局安装,不些则表示默认本地安装

因为使用了less后,个人一般喜欢将整个项目的配色进行一个管理。所以需要进行全局的配置。

这里安装完成后,继续安装

  1. npm install sass-resources-loader --save-dev

接下来,我们找到build文件夹下的utils文件

exports.cssLoaders = function (options) {}中加上一下代码:

  1. function lessResourceLoader() {
  2. var loaders = [
  3. cssLoader,
  4. 'less-loader',
  5. {
  6. loader: 'sass-resources-loader',
  7. options: {
  8. resources: [
  9. path.resolve(__dirname, '../src/assets/styles/common.less'),
  10. ]
  11. }
  12. }
  13. ];
  14. if (options.extract) {
  15. return ExtractTextPlugin.extract({
  16. use: loaders,
  17. fallback: 'vue-style-loader'
  18. })
  19. } else {
  20. return ['vue-style-loader'].concat(loaders)
  21. }
  22. }

注意位置一定要加对,且记得把path.resolve(__dirname,'../src/assets/styles/common.less')路径改成自己对应的文件。然后后面将 return{} 块中的 less: generateLoaders('less') 替换成上面自定义的函数 less: lessResourceLoader();

修改完配置文件记得重启服务器:npm run dev

给大家上图看一下主要配置:

重启服务后,基本就配置完成。不过我们还是的检测一下。

在common.less中写入:

  1. @bg-blue: #3576e0;

在App.vue中修改

  1. <style lang="less" scoped>
  2. #app {
  3. font-family: 'Avenir', Helvetica, Arial, sans-serif;
  4. -webkit-font-smoothing: antialiased;
  5. -moz-osx-font-smoothing: grayscale;
  6. text-align: center;
  7. color: #2c3e50;
  8. margin-top: 60px;
  9. background-color: @bg-blue;
  10. }
  11. </style>

然后保存,打开浏览器。就可以看到我们配置好的全局变量被成功引用

背景色变成蓝色。说明在common.less中定义的变量被正常调用。这里全局的less配置也就成功了。

引入全局的基本样式

项目搭建好了,但是可以看到一些基本的样式需要我们进行更改

  1. assets文件夹下styles文件中新建base.less文件。百度搜索reset.css然后复制文中的基本样式,并添加html,body宽高为100%即可。

  2. 新建function.less文件css样式工具封装在文中找到适合自己项目的文件复制并粘贴金function.less文件。

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

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

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

至于封装的function样式类,我们只需要在需要的时候,选择性的 添加类名即可。

安装element-ui

  1. npm install element-ui -s

安装完成后,在main.js中引入

  1. import ElementUI from 'element-ui'
  2. import 'element-ui/lib/theme-chalk/index.css'
  3. Vue.use(ElementUI);

安装完成后,修改App.vue:

  1. <template>
  2. <div id="app">
  3. <img src="./assets/logo.png">
  4. <el-button type="danger">测试Element</el-button>
  5. <router-view/>
  6. </div>
  7. </template>

打开浏览器,我们可以看到button按钮是已经生效了。

这里,element-ui也已经安装成功。

请求方法,拦截器,全局加载框的配置

在src文件夹下新建utils文件夹新建http.js为我们的请求方法的文件

封装前,我们需要借助axios来作为请求的底层,并且需要缓存机制去缓存登录状态

这里借助两个依赖包 axios和vue-cookies

  1. npm install axios vue-cookies -s
  1. 请求方法封装。这里封装三个类型的。get请求一个post,json格式的一个post,body格式的一个

  1. import axios from 'axios'
  2. import Vue from 'vue'
  3.  
  4. // 请求方式的配置
  5. export const postJsonRequest = (url, params) => {
  6. return axios({
  7. method: 'post',
  8. url: url,
  9. data: params,
  10. headers: {
  11. 'Content-Type': 'application/json',
  12. },
  13. });
  14. }
  15. export const postRequest = (url, params) => {
  16. return axios({
  17. method: 'post',
  18. url: url,
  19. data: params,
  20. transformRequest: [function (data) {
  21. let ret = ''
  22. for (let it in data) {
  23. ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
  24. }
  25. return ret
  26. }],
  27. headers: {
  28. 'Content-Type': 'application/x-www-form-urlencoded'
  29. }
  30. });
  31. }
  32.  
  33. export const getRequest = (url, data = {}) => {
  34. return axios({
  35. method: 'get',
  36. params: data,
  37. url: url,
  38. });
  39. }

这个就是请求方法的配置

随后我们在utils目录下新建index.js文件作为工具文件夹的出口文件

utils>index.js:

引入封装的http请求并挂在到Vue原型链上供全局使用

  1. import * as http from './http';
  2.  
  3. const install = (Vue, opts = {}) => {
  4. if (install.installed) return;
  5. Vue.prototype.$http = http;
  6. }
  7.  
  8. export default install

main.js

  1. import Utils from './utils';
  2. Vue.use(Utils);

这里方法请求的封装就算是完成了。

  1. 拦截器的配置

拦截器:登录状态的管理,以及每次请求时,我们做的一些处理。对不同code状态做的不同的处理

拦截器分为请求拦截器和响应拦截器。字面意思可理解为:请求时的拦截和响应时的拦截

  1. import axios from 'axios'
  2. import { Message } from 'element-ui'
  3. import router from 'vue-router'
  4. import Vue from 'vue'
  5. import VueCookies from 'vue-cookies'
  6. // 请求拦截
  7. axios.interceptors.request.use(config => {
  8. if (VueCookies.isKey('isLogin')) {
  9. const token = getToken(config);
  10. config.headers['token'] = token;
  11. }
  12. return config;
  13. }, err => {
  14. Message.error({
  15. message: '请求超时!'
  16. });
  17. return Promise.resolve(err);
  18. })
  19.  
  20. // 响应拦截
  21. axios.interceptors.response.use(res => {
  22. switch (res.data.code) {
  23. case 200:
  24. return res.data.result;
  25. case 401:
  26. Message.error({
  27. message: res.data.message
  28. });
  29. router.push('/login');
  30. VueCookies.remove('userinfo');
  31. return Promise.reject(res);
  32. case 201:
  33. Message.error({
  34. message: res.data.message
  35. });
  36. case 403:
  37. Message.warning({
  38. message: res.data.message
  39. });
  40. return Promise.reject(res);
  41. default:
  42. return Promise.reject(res);
  43. }
  44.  
  45. }, err => {
  46. if (!err.response) {
  47. return false;
  48. }
  49. switch (err.response.status) {
  50. case 500:
  51. Message.error({
  52. message: '服务器出小差了⊙﹏⊙∥'
  53. });
  54. break;
  55. case 504:
  56. Message.error({
  57. message: '服务器被吃了⊙﹏⊙∥'
  58. });
  59. break;
  60. case 404:
  61. Message.error({
  62. message: '服务器被吃了⊙﹏⊙∥'
  63. });
  64. break;
  65. case 403:
  66. Message.error({
  67. message: '权限不足,请联系管理员!'
  68. });
  69. break;
  70. default:
  71. Message.error({
  72. message: '网络超时'
  73. });
  74. }
  75. return Promise.reject(err);
  76. })

Vue拦截器的基本配置也就是以上这些了。下来个人想要实现一个loading的局部加载。就要借助计数器了。

为什么说要做一个计数器?

因为在同一个view中可能会有很多个请求,我们总不可能在一个请求完成后就关闭loading的加载吧?这样显然不合适。所以我们需要计时器去将所有的请求记录起来。然后在所有的请求完成后关闭loading。

  1. //请求时loading配置
  2. var loading;
  3.  
  4. function startLoading() {
  5. loading = Vue.prototype.$loading({
  6. lock: true,
  7. text: "Loading...",
  8. background: 'rgba(0, 0, 0, 0.5)',
  9. target: document.querySelector('.loading-area') //设置加载动画区域
  10. });
  11. }
  12.  
  13. function endLoading() {
  14. loading.close();
  15. }
  16. var needLoadingRequestCount = 0;
  17. //开启loading并计数
  18. function showFullScreenLoading() {
  19. if (needLoadingRequestCount === 0) {
  20. startLoading();
  21. }
  22. needLoadingRequestCount++;
  23. };
  24. //计数器==0关闭loading
  25. function tryHideFullScreenLoading() {
  26. if (needLoadingRequestCount <= 0) return;
  27. needLoadingRequestCount--;
  28. if (needLoadingRequestCount === 0) {
  29. endLoading();
  30. }
  31. };

loading的依赖在element安装后是直接挂在到了vue的原型链上。我们不再需要做过多处理。这里计数器完成。下来我们只需要在请求的时候调用,在响应的时候或者请求报错的时候调用关闭的方法即可。

需要注意的是要实现局部的加载,我们就需要在响应实现loading的地方添加类型loading-area才可以!!!

http.js所有代码如下:

  1. /**
  2. * @description 配置网络请求
  3. * @author luokaibin chaizhiyang
  4. */
  5. import axios from 'axios'
  6. import { Message } from 'element-ui'
  7. import router from 'vue-router'
  8. import Vue from 'vue'
  9. import VueCookies from 'vue-cookies'
  10.  
  11. axios.defaults.timeout = 300000; // 请求超时5fen
  12.  
  13. //请求时loading配置
  14. var loading;
  15.  
  16. function startLoading() {
  17. loading = Vue.prototype.$loading({
  18. lock: true,
  19. text: "Loading...",
  20. background: 'rgba(0, 0, 0, 0.5)',
  21. target: document.querySelector('.loading-area') //设置加载动画区域
  22. });
  23. }
  24.  
  25. function endLoading() {
  26. loading.close();
  27. }
  28. var needLoadingRequestCount = 0;
  29.  
  30. function showFullScreenLoading() {
  31. if (needLoadingRequestCount === 0) {
  32. startLoading();
  33. }
  34. needLoadingRequestCount++;
  35. };
  36.  
  37. function tryHideFullScreenLoading() {
  38. if (needLoadingRequestCount <= 0) return;
  39. needLoadingRequestCount--;
  40. if (needLoadingRequestCount === 0) {
  41. endLoading();
  42. }
  43. };
  44.  
  45. // 请求拦截
  46. axios.interceptors.request.use(config => {
  47. showFullScreenLoading();
  48. if (VueCookies.isKey('userinfo')) {
  49. const token = getToken(config);
  50. config.headers['token'] = token;
  51. }
  52. return config;
  53. }, err => {
  54. tryHideFullScreenLoading();
  55. Message.error({
  56. message: '请求超时!'
  57. });
  58. return Promise.resolve(err);
  59. })
  60.  
  61. // 响应拦截
  62. axios.interceptors.response.use(res => {
  63. tryHideFullScreenLoading();
  64. switch (res.data.code) {
  65. case 200:
  66. return res.data.result;
  67. case 401:
  68. Message.error({
  69. message: res.data.message
  70. });
  71. router.push('/login');
  72. // VueCookies.remove('userinfo');
  73. return Promise.reject(res);
  74. case 201:
  75. Message.error({
  76. message: res.data.message
  77. });
  78. case 403:
  79. Message.warning({
  80. message: res.data.message
  81. });
  82. return Promise.reject(res);
  83. default:
  84. return Promise.reject(res);
  85. }
  86.  
  87. }, err => {
  88. tryHideFullScreenLoading();
  89. if (!err.response) {
  90. return false;
  91. }
  92. switch (err.response.status) {
  93. case 500:
  94. Message.error({
  95. message: '服务器出小差了⊙﹏⊙∥'
  96. });
  97. break;
  98. case 504:
  99. Message.error({
  100. message: '服务器被吃了⊙﹏⊙∥'
  101. });
  102. break;
  103. case 404:
  104. Message.error({
  105. message: '服务器被吃了⊙﹏⊙∥'
  106. });
  107. break;
  108. case 403:
  109. Message.error({
  110. message: '权限不足,请联系管理员!'
  111. });
  112. break;
  113. default:
  114. Message.error({
  115. message: '网络超时'
  116. });
  117. }
  118. return Promise.reject(err);
  119. })
  120.  
  121. // 请求方式的配置
  122. export const postJsonRequest = (url, params) => {
  123. return axios({
  124. method: 'post',
  125. url: url,
  126. data: params,
  127. headers: {
  128. 'Content-Type': 'application/json',
  129. },
  130. });
  131. }
  132. export const postRequest = (url, params) => {
  133. return axios({
  134. method: 'post',
  135. url: url,
  136. data: params,
  137. transformRequest: [function (data) {
  138. let ret = ''
  139. for (let it in data) {
  140. ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
  141. }
  142. return ret
  143. }],
  144. headers: {
  145. 'Content-Type': 'application/x-www-form-urlencoded'
  146. }
  147. });
  148. }
  149.  
  150. export const getRequest = (url, data = {}) => {
  151. return axios({
  152. method: 'get',
  153. params: data,
  154. url: url,
  155. });
  156. }

至此整个的全局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仓库关联。

敬请期待~

Vue实战狗尾草博客管理系统第一章的更多相关文章

  1. Vue实战狗尾草博客管理系统第二章

    伙伴们出来啦,探讨各问题,关于项目中大量的表单,大家是怎么处理的? 本章主要内容如下:底层布局,路由配置,github仓库推送关联. 关联GitHub仓库 关联建立在github已创建账号的基础上 登 ...

  2. Vue实战狗尾草博客后台管理系统第七章

    Vue实战狗尾草博客后台管理平台第七章 本章内容为借助模块化来阐述Vuex的进阶使用. 在复杂项目的架构中,对于数据的处理是一个非常头疼的问题.处理不当,不仅对维护增加相当的工作负担,也给开发增加巨大 ...

  3. Vue实战狗尾草博客后台管理系统第三章

    Vue实现狗尾草博客后台管理系统第三章 本章节,咱们开发管理系统侧边栏及面包屑功能. 先上一张效果图 样式呢,作者前端初审,关于设计上毫无美感可言,大家可根据自己情况设计更好看的哦~ 侧边栏 这里我们 ...

  4. Vue实战狗尾草博客管理平台第六章

    Vue实现狗尾草博客后台管理系统第六章 本章节内容 文章列表 文章详情 草稿箱 文章发布. 本章节内容呢,开发的很是随意哈,因为多数就是element-ui的使用,熟悉的童鞋,是可以很快完成本章节的内 ...

  5. Vue实战狗尾草博客管理平台第四章

    本章主要内容如下: 填补上期的坑. iconfont仓库的关联,引入. 开发登录页面 填坑 上期中我们功能都已正常使用.但不知道有没有小伙伴测试过error页面,当访问地址不存在时,路由是否能正常挑战 ...

  6. Vue实战狗尾草博客管理平台第五章

    本章主要内容如下: 静态资源服务器的配置.学会如何使用静态资源服务器引入静态资源.并给大家推荐一个免费可使用的oss服务器~ 页面的开发由于近期做出的更改较大.就放在下一篇中. 静态资源服务器 静态资 ...

  7. yii2实战教程之新手入门指南-简单博客管理系统

    作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...

  8. SSM(Spring+Spring MVC+Mybatis)开发前台后功能完整的java开源博客管理系统

    项目描述 本项目通过SSM(SpringMVC+Mybatis+Spring)框架编写的一个人博客管理系统,使用hexo主题,以及MAVEN进行对项目管理,并且前端具有粒子和点击爱心效果.后端的页面框 ...

  9. 一个 Vue + Node + MongoDB 博客系统

    源码 耗时半载(半个月)的大项目终于完成了.这是一个博客系统,使用 Vue 做前端框架,Node + express 做后端,数据库使用的是 MongoDB.实现了用户注册.用户登录.博客管理(文章的 ...

随机推荐

  1. PHP代码篇(五)--如何将图片文件上传到另外一台服务上

    说,我有一个需求,就是一个临时功能.由于工作开发问题,我们有一个B项目,需要有一个商品添加的功能,涉及到添加商品内容,比如商品名字,商品描述,商品库存,商品图片等.后台商品添加的接口已经写完了,但是问 ...

  2. [日常] 解决docker拉取镜像速度慢的问题

    将docker修改为国内镜像源 在/etc/docker/daemon.json文件中添加下面参数 此处使用的是中国科技大学的docker镜像源 {    "registry-mirrors ...

  3. Shel脚本-初步入门之《06》

    Shel脚本-初步入门-06 Shell 脚本的建立和执行 6.Shell 脚本的建立和执行 6.1 Shell脚本的建立 在 Linux 系统中,Shell 脚本(bash Shell 程序)通常是 ...

  4. softmax求导、cross-entropy求导及label smoothing

    softmax求导 softmax层的输出为 其中,表示第L层第j个神经元的输入,表示第L层第j个神经元的输出,e表示自然常数. 现在求对的导数, 如果j=i,   1 如果ji, 2 cross-e ...

  5. C# 深入分析 GC 处理机制

    引用地址:https://www.cnblogs.com/nele/p/5673215.html GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年 ...

  6. JMeter配置数据库连接

    在平时接口的测试中,很多时候是需要直接连接数据库,查询对应数据信息的. 我将其中一些内容整理出来,方便以后调阅. 1.首先是配置数据库的连接,也就是JDBC Connection Configurat ...

  7. Html学习之十三(导航栏的制作)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. 201871010111-刘佳华《面向对象程序设计(java)》第十六周学习总结

    学号-姓名<面向对象程序设计(java)>第十六周学习总结 实验十四  应用程序归档与线程初步 实验时间 2019-12-12 第一部分:理论知识总结 1.程序与进程的概念 ‐程序是一段静 ...

  9. [转] 从零推导支持向量机 (SVM)

    原文连接 - https://zhuanlan.zhihu.com/p/31652569 摘要 支持向量机 (SVM) 是一个非常经典且高效的分类模型.但是,支持向量机中涉及许多复杂的数学推导,并需要 ...

  10. HTTP 与HTTPS 简单理解

      HTTP协议,即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和万维网(WWW = World Wide Web)服务器之间互相通信的规则,通过因 ...