从零到一开发博客后台管理系统(二)

时间:2022-10-23 12:34:58

从零到一开发博客后台管理系统

1.今日计划完成

  • home页顶栏设计
  • home页tab标签页与左侧导航栏动态菜单联动
  • axios的封装

2.home页顶栏设计

只是用于显示标题,看起来干净一些
我们来编辑top.vue

<template>
  <div>
    <span class="title">博客管理系统</span>
  </div>
</template>
.title {
  margin-left: 1.25rem;
  cursor: pointer;
}

现在的效果是这样的
从零到一开发博客后台管理系统(二)

3.home页标签页的设计

我们这里设计9个标签页,分别是:随笔 文章 日记 评论 链接 相册 文件 设置 选项
每一个标签页的选项应该对应一个组件,现在先用文字来代替,以后做到对应的组件在来替换
编辑完main.vue之后是这样的

<template>
  <div class="tab">
    <el-tabs type="card">
      <el-tab-pane label="随笔">随笔</el-tab-pane>
      <el-tab-pane label="文章">文章</el-tab-pane>
      <el-tab-pane label="日记">日记</el-tab-pane>
      <el-tab-pane label="评论">评论</el-tab-pane>
      <el-tab-pane label="链接">链接</el-tab-pane>
      <el-tab-pane label="相册">相册</el-tab-pane>
      <el-tab-pane label="文件">文件</el-tab-pane>
      <el-tab-pane label="设置">设置</el-tab-pane>
      <el-tab-pane label="选项">选项</el-tab-pane>
    </el-tabs>
  </div>
</template>

没错就是如此简单,现在我们来看一下效果吧
从零到一开发博客后台管理系统(二)

4.左侧的导航栏

导航栏我们可以根据选中的标签不同,显示不同的动态菜单
我们先来设计一下我们的菜单吧

  • 标签选中随笔
    × 博客操作
    1. 新建随笔
    2. 草稿箱
    3. 博客签名
    4. 博客备份
    5. 博客搬家
    × 博客分类 (编辑)
    1. vue
    2. python
    3. 。。。
  • 标签选中文章
    × 文章操作
    1. 新建文章
    2. 草稿箱
    3. 文章备份
    × 文章分类 (编辑)
    1. vue
    2. python
    3. 。。。
  • 标签选中日记
    × 日记操作
    1. 新建日记
    2. 阅读日记
    3. 日记备份
  • 标签选中评论
    1. 我发表过的评论
    2. 我参与的随笔
    3. 旧版留言
    4. 订阅评论通知的博文

由于后面的链接 相册 文件 设置 选项过于复杂,本次版本不做处理(如果搞得太复杂很可能太监掉)
选到这些我们暂时用同意的页面来提示

那么现在在src下新建文件夹config,新建文件home.json,写入上面的信息
这是我的json文件(home.json)

{
    "InformalEssay_Menu": [{
            "index": "1",
            "name": "博客管理",
            "url": "",
            "children": [{
                "index": "1-1",
                "name": "新建随笔",
                "url": ""
            }, {
                "index": "1-2",
                "name": "草稿箱",
                "url": ""
            }, {
                "index": "1-3",
                "name": "博客签名",
                "url": ""
            }, {
                "index": "1-4",
                "name": "博客备份",
                "url": ""
            }, {
                "index": "1-5",
                "name": "博客搬家",
                "url": ""
            }]
        },
        {
            "index": "2",
            "name": "分类管理",
            "url": "",
            "children": [{
                "index": "2-1",
                "name": "vue",
                "url": ""
            }, {
                "index": "2-2",
                "name": "python",
                "url": ""
            }, {
                "index": "2-3",
                "name": "java",
                "url": ""
            }]
        }
    ],
    "Article_Menu": [{
            "index": "1",
            "name": "文章管理",
            "url": "",
            "children": [{
                "index": "1-1",
                "name": "新建文章",
                "url": ""
            }, {
                "index": "1-2",
                "name": "草稿箱",
                "url": ""
            }, {
                "index": "1-3",
                "name": "文章备份",
                "url": ""
            }]
        },
        {
            "index": "2",
            "name": "分类管理",
            "url": "",
            "children": [{
                "index": "2-1",
                "name": "vue",
                "url": ""
            }, {
                "index": "2-2",
                "name": "python",
                "url": ""
            }, {
                "index": "2-3",
                "name": "java",
                "url": ""
            }]
        }
    ],
    "Diary_menu": [{
            "index": "1",
            "name": "日记管理",
            "url": "",
            "children": [{
                "index": "1-1",
                "name": "新建日记",
                "url": ""
            }, {
                "index": "1-2",
                "name": "阅读日记",
                "url": ""
            }, {
                "index": "1-3",
                "name": "日记备份",
                "url": ""
            }]
        }

    ],
    "Commpent_Menu": [{
            "index": "1",
            "name": "评论管理",
            "url": "",
            "children": [{
                "index": "1-1",
                "name": "我发表过的评论",
                "url": ""
            }, {
                "index": "1-2",
                "name": "我参与的随笔",
                "url": ""
            }, {
                "index": "1-3",
                "name": "旧版留言",
                "url": ""
            }, {
                "index": "1-4",
                "name": "订阅评论通知的博文",
                "url": ""
            }]
        }

    ],
    "tab": {
        "tab0": "InformalEssay_Menu",
        "tab1": "Article_Menu",
        "tab2": "Diary_menu",
        "tab3": "Commpent_Menu"
    }

}

只写了四个菜单,有兴趣的可以自己补充完整,那么我们如何将这些数据变成菜单呢?我们需要在home文件夹下面新建menutree.vue,这就是我们的菜单组件了。

<template>
  <div class="menutree">
    <label v-for="menu in data" :key="menu.index">
      <el-submenu :index="menu.index" v-if="menu.children && menu.children.length">
        <template slot="title">
          <span>{{menu.name}}</span>
        </template>
        <label>
          <menutree :data="menu.children"></menutree>
        </label>
      </el-submenu>
      <el-menu-item v-else :index="menu.index" @click="select(menu)">
        <span slot="title">{{menu.name}}</span>
      </el-menu-item>
    </label>
  </div>
</template>

<script>
import menutree from "@/views/home/menutree";
export default {
  name: "menutree",
  data() {
    return {
      menu_data: {}
    };
  },
  components: {
    menutree: menutree
  },
  props: ["data"],
  methods: {
    select(menu) {
      this.$router.push(menu.url);
    }
  }
};
</script>
<style scoped>
</style>

从我们的菜单数据中递归生成一个菜单树,详细的过程可以参考另一篇博客

接下来就是在left.vue中调用这个组件了,为了避免频繁的调用json文件,我们使用一个data参数来传递数据。

<template>
  <div>
    <el-menu>
      <menutree :data="data"></menutree>
    </el-menu>
  </div>
</template>
<script>
import menutree from "@/views/home/menutree";
export default {
  components: {
    menutree: menutree
  },
  props: ["data"],
  methods: {
    select(menu) {
      this.$router.push(menu.url);
    }
  }
};
</script>

接下来就是我们的index.vue组件了
只需要简单的改动一下left标签中添加 :data属性

<left :data="data"></left>

在js中添加data

import top from "@/views/home/top";
import left from "@/views/home/left";
import right from "@/views/home/main";
import data from "@/config/home.json";
export default {
  data() {
    return {
      data: {}
    };
  },
  components: {
    top: top,
    left: left,
    right: right
  },
  mounted() {
    this.data = data.InformalEssay_Menu;
  },
}

现在我们的页面上应该已经有一个菜单栏显示了
从零到一开发博客后台管理系统(二)

当然这个时候,我们点击右面的标签,左边的菜单栏是不会有任何变化的。我们需要吧它们关联起来,这时,我们就需要了解一下组件间的通信了。

我们的信息都是在index.vue组件上处理的,所以main.vue上的标签被点击时需要向父节点传递信息,这种情景我们使用$emit这个方法来传递消息
在index.vue 组件中,为right标签添加属性

<right @change="change"></right>

定义change方法

 methods: {
    change(msg) {
      this.data = data[data.tab[msg]];
    }
  }

上面的msg传递的是tab标签的唯一标识信息

接下来在main.vue中来传递这个消息

<template>
  <div class="tab">
    <el-tabs type="card" @tab-click="toParent">
      <el-tab-pane label="随笔">随笔</el-tab-pane>
      <el-tab-pane label="文章">文章</el-tab-pane>
      <el-tab-pane label="日记">日记</el-tab-pane>
      <el-tab-pane label="评论">评论</el-tab-pane>
      <el-tab-pane label="链接">链接</el-tab-pane>
      <el-tab-pane label="相册">相册</el-tab-pane>
      <el-tab-pane label="文件">文件</el-tab-pane>
      <el-tab-pane label="设置">设置</el-tab-pane>
      <el-tab-pane label="选项">选项</el-tab-pane>
    </el-tabs>
  </div>
</template>

<script>
export default {
  methods: {
    toParent(tab, event) {
      let id = event.target.getAttribute("id").replace("-", "");
      this.$emit("change", id);
    }
  }
};
</script>

由于tab默认的id是 tab-1这种命名方式,在这里我选择把中间的-过滤掉,变成tab1这种形式传递到父节点
这样tab标签就和菜单关联起来了
从零到一开发博客后台管理系统(二)

从零到一开发博客后台管理系统(二)

因为我们只写了前面四个标签的菜单数据,所以后面的标签是没有菜单的,点击左边是空白的,这样很不友好,先把他们注释掉
从零到一开发博客后台管理系统(二)

5.axios的封装

这个我参考了大量的博客,主要就是拦截器以及对各种请求方法的封装,写法比较固定
在axios文件夹下新建index.js文件

import axios from 'axios';
import { Message } from 'element-ui';

axios.defaults.timeout = 5000;
axios.defaults.baseURL ='http://127.0.0.1:8000';


//http request 拦截器
axios.interceptors.request.use(
  config => {
    // 发送数据之前的操作
    
    return config;
  },
  error => {
    return Promise.reject(err);
  }
);


//http response 拦截器
axios.interceptors.response.use(
  response => {
    // 返回数据之前的操作

    return response;
  },
  error => {
    return Promise.reject(error)
  }
)


/**
 * 封装get方法
 * @param url
 * @param data
 * @returns {Promise}
 */

export function fetch(url,params={}){
  return new Promise((resolve,reject) => {
    axios.get(url,{
      params:params
    })
    .then(response => {
      resolve(response.data);
    })
    .catch(err => {
      reject(err)
    })
  })
}


/**
 * 封装post请求
 * @param url
 * @param data
 * @returns {Promise}
 */

 export function post(url,data = {}){
   return new Promise((resolve,reject) => {
     axios.post(url,data)
          .then(response => {
            resolve(response.data);
          },err => {
            reject(err)
          })
   })
 }

 /**
 * 封装patch请求
 * @param url
 * @param data
 * @returns {Promise}
 */

export function patch(url,data = {}){
  return new Promise((resolve,reject) => {
    axios.patch(url,data)
         .then(response => {
           resolve(response.data);
         },err => {
           reject(err)
         })
  })
}

 /**
 * 封装put请求
 * @param url
 * @param data
 * @returns {Promise}
 */

export function put(url,data = {}){
  return new Promise((resolve,reject) => {
    axios.put(url,data)
         .then(response => {
           resolve(response.data);
         },err => {
           reject(err)
         })
  })
}

如果需要封装其他的方法,写法都是一样的。
那么今天的内容就到此结束了,记录一下时间:19年5月22日 22:51

有任何疑问或者建议可以在下方留言