前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >搭建后台管理系统的思路

搭建后台管理系统的思路

作者头像
公众号---人生代码
发布2021-05-08 15:49:06
2.7K0
发布2021-05-08 15:49:06
举报
文章被收录于专栏:人生代码人生代码

从零开始搭建后台管理系统

当然,这是一个简易版本的,你可以在这两个基础上加以改造

搭建后台管理系统最基础的是什么呢?个人的体会是整体的基础框架,这个是指最基础的框架,比如根 router-view, 侧边栏以及侧边栏的router-view,以及顶部栏,等基础布局的控制。

root

首先 App.vue 只有展示 rouer-view, 这个就是 root, 所谓的根。

代码语言:javascript
复制
<template>
  <router-view></router-view>
</template>

ok 有了根之后,我们需要有一个 layout 页面,这个页面来承载我们的侧边栏,顶部栏

layout 页面他是两栏布局的,一栏是我们的侧边导航栏,

侧边栏

如何完成这个两栏布局

  • 可以使用 float
  • 可以使用弹性布局 display: flex
  • 也可以使用定位

侧边导航栏,可能我们需要来研究 element-ui 的组件 NavMenu 导航菜单

侧边导航栏需要我们路由的一些信息,比如路由对应的组件,就像 router-link 对应的 router-view

如果菜单是二级菜单,三级菜单,需要怎么处理

如果需要折叠菜单,需要怎么处理,这里就需要阅读 折叠菜单组件

也就是说侧边菜单来其实就是一个个的 router-link

然后扩展菜单项是否有 icon 小图标,是否有标题存在,那么路由就需要设置 meta 属性了

顶部栏

接下来就是顶部栏,顶部导航栏有什么呢?

  • 面包屑
  • 消息通知
  • 下拉菜单
  • 关闭展开侧边栏按钮

面包屑

需要注意什么呢?需要注意是否需要点击跳转的,定位到那一级菜单的问题

需要研究 Breadcrumb 面包屑

关闭展开侧边栏按钮

需要使用 vuex 来存储打开与否的这个状态值,通过 vuex 来更改状态

AppMain.vue

代码语言:javascript
复制
<template>
  <section class="app-main">
    <!-- 内部应该显示子路由页面信息 -->
    <router-view v-slot="{ Component }">
      <component :is="Component" />
    </router-view>
  </section>
</template>

<script>
import { defineComponent } from "vue";

export default defineComponent({
  name: "AppMain",
});
</script>

<style lang="scss" scoped>
.app-main {
  /*50 = navbar  */
  min-height: calc(100vh - 50px);
  width: 100%;
  position: relative;
  overflow: hidden;
}
</style>

用来展示侧边栏的 router-link 对应的 router-view

所以,又回到 layout 页面整体框架如下:

代码语言:javascript
复制
<template>
  <div class="app-wrapper">
    <!-- 侧边栏 -->
    <side-bar class="sidebar-container"></side-bar>
    <!-- 内容容器 -->
    <div class="main-container">
      <!-- 顶部导航栏 -->
      <nav-bar />
      <!-- 内容区 -->
      <app-main />
    </div>
  </div>
</template>

<script setup>
import AppMain from "layout/components/AppMain.vue";
import NavBar from "layout/components/NavBar.vue";
import SideBar from "layout/components/Sidebar/index.vue";
</script>

<style lang="scss" scoped>
@import "styles/mixin.scss";
.app-wrapper {
  @include clearfix;
  position: relative;
  height: 100%;
  width: 100%;
}
</style>

请求封装

  • token 处理
  • 响应处理
  • 请求处理
代码语言:javascript
复制
import axios from 'axios';

import { Message, Msgbox } from 'element3';

import store from 'store/index.js';

// 创建 axios 实例

const service = axios.create({
    // 在请求地址前面加上 baseURL
    baseURL: import.meta.env.VITE_BASE_API,
    // 当前发送跨域请求时携带 cookie
    withCredentials: true,
    timeout: 5000
});

// 请求拦截
service.interceptors.request.use(
    (config) => {
        // 指定请求令牌
        // if (store.getters.token) {
        // // 自定义令牌的字段名为X-Token,根据咱们后台再做修改
        // config.headers["X-Token"] = store.getters.token;
        // }
        config.headers["X-Token"] = "my token";
        return config;
    },
    (error) => {
        // 请求错误的统一处理
        console.log(error); // for debug
        return Promise.reject(error);
    }
);

// 响应拦截器
service.interceptors.response.use(
    /**
     * If you want to get http information such as headers or status
     * Please return  response => response
     */

    /**
     * 通过判断状态码统一处理响应,根据情况修改
     * 同时也可以通过HTTP状态码判断请求结果
     */
    (response) => {
        const res = response.data;

        // 如果状态码不是20000则认为有错误
        if (res.code !== 20000) {
            Message.error({
                message: res.message || "Error",
                duration: 5 * 1000,
            });

            // 50008: 非法令牌; 50012: 其他客户端已登入; 50014: 令牌过期;
            if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
                // 重新登录
                Msgbox.confirm("您已登出, 请重新登录", "确认", {
                    confirmButtonText: "重新登录",
                    cancelButtonText: "取消",
                    type: "warning",
                }).then(() => {
                    store.dispatch("user/resetToken").then(() => {
                        location.reload();
                    });
                });
            }
            return Promise.reject(new Error(res.message || "Error"));
        } else {
            return res;
        }
    },
    (error) => {
        console.log("err" + error); // for debug
        Message({
            message: error.message,
            type: "error",
            duration: 5 * 1000,
        });
        return Promise.reject(error);
    }
);

export default service;

多语言

多语言会用到 vue-i18n 这样的插件

就需要研究官网文档了 vue-i18n

有一个 vite 多语言插件

intlify/vite-plugin-vue-i18n

vite.config.js 配置

代码语言:javascript
复制
import path from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueI18n from '@intlify/vite-plugin-vue-i18n'

export default defineConfig({
  plugins: [
    vue(), // you need to install `@vitejs/plugin-vue`
    vueI18n({
      // if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
      // compositionOnly: false,

      // you need to set i18n resource including paths !
      include: path.resolve(__dirname, './path/to/src/locales/**')
    })
  ]
})

模板这样使用多语言

代码语言:javascript
复制
<template>
  <form>
    <label>{{ t('language') }}</label>
    <select v-model="locale">
      <option value="en">en</option>
      <option value="ja">ja</option>
    </select>
  </form>
  <p>{{ t('hello') }}</p>
</template>

<script>
import { useI18n } from 'vue-i18n'

export default {
  name: 'App',
  setup() {
    const { locale, t } = useI18n({
      inheritLocale: true
    })

    return { locale, t }
  }
}
</script>

<i18n>
{
  "en": {
    "language": "Language",
    "hello": "hello, world!"
  },
  "ja": {
    "language": "言語",
    "hello": "こんにちは、世界!"
  }
}
</i18n>

当然,可以在 main.js 引入多语言

代码语言:javascript
复制
import { createApp } from 'vue'
import { createI18n } from 'vue-i18n'
/*
 * The i18n resources in the path specified in the plugin `include` option can be read
 * as vue-i18n optimized locale messages using the import syntax
 */
import en from './src/locales/en.json'
import ja from './src/locales/ja.yaml'
import fr from './src/locales/fr.json5'

const i18n = createI18n({
  locale: 'en',
  messages: {
    en,
    ja,
    fr
  }
})

const app = createApp()
app.use(i18n).mount('#app)

element3 组件

代码语言:javascript
复制
// 完整引入
import element3 from "element3";
import "element3/lib/theme-chalk/index.css";

export default function (app) {
    // 完整引入
    app.use(element3);
};

我们要如何组建自己的样式目录

  • var.scss 用于提取颜色值,字体大小值,字体权重值等
  • mixin.scss 写一些公用的样式

目录的重定向问题

代码语言:javascript
复制
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { viteMockServe } from 'vite-plugin-mock';
import path from 'path';
import vueI18n from '@intlify/vite-plugin-vue-i18n'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    viteMockServe({ supportTs: false }),
    vueI18n({
      // if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
      // compositionOnly: false,

      // you need to set i18n resource including paths !
      include: path.resolve(__dirname, './src/locales/**')
    })
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
      "comps": path.resolve(__dirname, "src/components"),
      "api": path.resolve(__dirname, "src/api"),
      "views": path.resolve(__dirname, "src/views"),
      "styles": path.resolve(__dirname, "src/styles"),
      "locales": path.resolve(__dirname, "src/locales"),
      "layout": path.resolve(__dirname, "src/layout"),
      "utils": path.resolve(__dirname, "src/utils"),
      "dirs": path.resolve(__dirname, "src/dirs"),
      "plugins": path.resolve(__dirname, "src/plugins"),
      "config": path.resolve(__dirname, "src/config"),
      "router": path.resolve(__dirname, "src/router"),
      "store": path.resolve(__dirname, "src/store"),
      "model": path.resolve(__dirname, "src/model")
    }
  }
});
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • root
  • 侧边栏
  • 顶部栏
    • 面包屑
      • 关闭展开侧边栏按钮
      • AppMain.vue
      • 请求封装
      • 多语言
      • element3 组件
      • 我们要如何组建自己的样式目录
      • 目录的重定向问题
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档