zoukankan      html  css  js  c++  java
  • 从零到一开发博客后台管理系统(二)

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

    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

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

  • 相关阅读:
    数据结构问题集锦
    大作业 开源项目列表
    数据结构问题集锦
    leetcode174
    leetcode152
    经典算法之KMP
    给出一个字符串,将其每一个字符表示成16进制表示,要求每个十六进制为8位数
    作业
    ASP 作业题
    ASP.NET 作业题
  • 原文地址:https://www.cnblogs.com/asia9847/p/10909142.html
Copyright © 2011-2022 走看看