目录
目标
配置中心
config/config.js
皮肤/国际化
config/theme.js
config/language.js
app.js
App.vue
权限管理
src/views/about.vue
src/views/403.vue
config/permission.js
src/router.js
src/store.js
献上一张通过ai生成的图片~
目标
- 配置中心
- 皮肤/国际化
- 权限控制
配置中心
config/config.js
// config/config.js
class Config {
  constructor() {// 构造函数
    this._config = {};
  }
  regist(type, value) { // 注册配置
    this._config[type] = value;
  }
  get(type) { // 获取配置
    return this._config[type];
  }
}
// 返回一个单例
export default new Config();皮肤/国际化
config/theme.js
// config/theme.js
// 皮肤配置
import config from "./config";
// 启动加载数据
export const init = () => {
  config.regist("theme", {
    blue: {
      primary: "#007fff",
      highlight: "#00a6ff",
    },
    red: {
      primary: "#A83733",
      highlight: "rgb(195, 75, 73)",
    },
  });
};config/language.js
// config/language.js
// 国际化,(中英切换)
import config from "./config";
import { LIST_TYPE } from "../module/topic/store";
export const init = () => {
  config.regist("language", {
    Chinese: {
      navs: [
        {
          name: "热门",
          path: LIST_TYPE.HOT,
        },
        {
          name: "最新",
          path: LIST_TYPE.NEW,
        },
        {
          name: "热榜",
          path: LIST_TYPE.TOP,
        },
        {
          name: "关于我",
          path: "about",
        },
      ]
    },
    English: {
      navs: [
        {
          name: "pop",
          path: LIST_TYPE.HOT,
        },
        {
          name: "new",
          path: LIST_TYPE.NEW,
        },
        {
          name: "hot",
          path: LIST_TYPE.TOP,
        },
        {
          name: "aboutMe",
          path: "about",
        },
      ]
    },
  });
};app.js
import Vue from "vue";
import App from "./App.vue";
import { createStore } from "./store";
import { createRouter } from "./router";
import intersect from "./directive/intersect";
// 皮肤配置,初始化方法init重命名为themeInit
import { init as themeInit } from "./config/theme";
// 国际化
import { init as languageInit } from "./config/language";
// 权限
import { init as permissionInit } from "./config/permission";
// 注册指令
Vue.directive("intersect", intersect);
// app.$mount("#app");
export function createApp() {
  const store = createStore();
  const router = createRouter({ store });
  // 应用初始化之前,初始化皮肤相关配置信息
  themeInit();
  // 应用初始化之前,初始化国际化相关配置信息
  languageInit();
  // 初始化权限
  permissionInit();
  const app = new Vue({
    store,
    router,
    render: (h) => h(App),
  });
  return {
    app,
    store,
    router,
  };
}App.vue
<template>
  <div id="app">
    <div class="m-top" :style="{ backgroundColor: theme.primary }">
      <u-link
        class="m-link"
        :style="{
          backgroundColor:
            $route.name === nav.path ? theme.highlight : theme.primary,// 读取配置
        }"
        v-for="nav in language.navs"
        :key="nav.path"
        :to="nav.path"
        :prefetch="true"
        >{{ nav.name }}</u-link>
    </div>
    <div class="m-content">
      <u-keep-alive max="2">
        <router-view></router-view>
      </u-keep-alive>
    </div>
    <div class="m-side">
      主题切换:
      <button @click="themeType = 'red'">红</button>
      <button @click="themeType = 'blue'">蓝</button>
    </div>
  </div>
</template>
<script>
import UTopic from "./module/topic/views/UTopic.vue";
import { LIST_TYPE } from "./module/topic/store";
import config from "./config/config";// 读取配置
export default {
  components: {
    UTopic,
  },
  data() {
    return {
      themeType: "blue",
      languageType: "Chinese",
    };
  },
  //provide 全局注入主题颜色;
  //inject: ["theme"]获取;这个方案不对响应式数据进行传递
  // 用于一次性启动的配置,在生命周期中不进行修改
  // 性能考虑
  provide() { 
    return {
      theme: this.theme,
    };
  },
  computed: {
    theme() {
      return config.get("theme")[this.themeType];// 读取配置
    },
    language() {
      return config.get("language")[this.languageType];
    },
  },
};
</script>
<style>
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  margin: 0;
  overflow-y: scroll;
}
a {
  text-decoration: none;
  color: #007fff;
}
.m-top {
  height: 60px;
  width: 100%;
  background: #007fff;
}
.m-content {
  width: 360px;
  border: 1px solid #eee;
  background: #fff;
  margin: 20px auto;
  padding: 0 20px;
}
.m-link {
  display: inline-block;
  color: #fff;
  height: 60px;
  line-height: 60px;
  font-size: 19px;
  padding: 0 20px;
}
.router-link-active {
  background: #00a6ff;
}
.m-side {
  position: fixed;
  left: 50%;
  margin-left: 220px;
  top: 100px;
}
</style>权限管理
src/views/about.vue
<template>
  <div class="about">
    about me!!!
    <input type="text" v-model="x" />
  </div>
</template>
<script>
export default {
  data() {
    return {
      x: "",
    };
  },
};
</script>
<style scoped>
.about {
  padding: 30px;
  text-align: center;
}
</style>src/views/403.vue
<template>
  <div class="stop">无权限访问页面</div>
</template>
<style scoped>
.stop {
  padding: 30px;
  text-align: center;
}
</style>config/permission.js
// config/permission.js
// 权限配置文件
import config from "./config";
// 暴漏常量
export const PERMISSION_MAP = {
  ABOUT_PAGE: Symbol("ABOUT_PAGE"),
};
export const init = () => {
  config.regist("permission", {
    CEO: {
      [PERMISSION_MAP.ABOUT_PAGE]: true,
    },
    COO: {
      [PERMISSION_MAP.ABOUT_PAGE]: false,
    },
  });
};
// 获取身份权限
export const getPermissionByRole = (role) => config.get("permission")[role];src/router.js
import Vue from "vue";
import VueRouter from "vue-router";
import { routes as topic } from "./module/topic/router";
import { PERMISSION_MAP, getPermissionByRole } from "./config/permission";
import store from "./store";
import { compose } from "./util/compose";
Vue.use(VueRouter);
export function createRouter({ store }) {
    // 1. 获取当前角色
  const getRole = () => store.state.user.role;
  	// 2.获取当前权限getPermissionByRole
  const getPermission = (permission) =>
    // 3.当前obj[permission]是否在PERMISSION_MAP上,从右往左执行
    compose((obj) => obj[permission], getPermissionByRole, getRole)();
  return new VueRouter({
    mode: "history",
    routes: [
      ...topic,
      {
        name: "about",
        path: "/about",
        component: () => import(/* webpackChunkName:"about" */ "./views/UAbout.vue"),
        beforeEnter(to, from, next) {  // 守卫钩子
          // 如果有权限就去to页面,没有就去403页面
          getPermission(PERMISSION_MAP.ABOUT_PAGE) ? next() : next("403");
        },
      },
      {
        name: "403",
        path: "/403",
        component: () => import(/* webpackChunkName:"403" */ "./views/403.vue"),
      },
      {
        path: "/",
        redirect: "/hot",
      },
    ],
  });
}src/store.js
// 全局单例store
import Vue from "vue";
import Vuex from "vuex";
import { store as topic } from "./module/topic/store";
Vue.use(Vuex);
export function createStore() {
  return new Vuex.Store({
    state: {
      user: {
        role: "CEO",// 假装在后端请求到的身份
      },
    },
    modules: {
      topic,
    },
  });
}分享的文章多是学习过程中记录的coding && 笔记~
献上一张通过ai生成的图片~












![[USACO23FEB] Equal Sum Subarrays G](https://img-blog.csdnimg.cn/5eac9c219ea043e7823b726a9b8d8c04.png#pic_center)







