一,登录功能
登录功能除了普通的上传用户名密码参数以外,需要在登录的请求头中添加code码,这个code码的生成需要配合插件md5来实现,通过下载插件md5来对请求的密码进行加密,再通过在请求拦截器中使用md5升成请求头的code码,代码如下...
// 获取加密code码
function getmdcode() {
const now = parseInt(Date.now() / 1000)
const code = now + "LGD_Sunday-1991"
return {
icode: md5(code),
time: now
}
}
二,换肤功能的实现
通过下载插件i8n,在我们点击切换语言的时候,将对应语言的名称存储到本地存储。
在src目录下创建一个存放各国语言的文件夹,当我们点击对应的语言时候通过查询本地存储语言进行判断切换到对印的语言,然后全局引入语言,在页面中通过$t来引入语言进行编译。
d
import { createI18n } from 'vue-i18n'
import mZhLocale from './lang/zh'
import mEnLocale from './lang/en'
import store from '@/store'
const messages = {
en: {
msg: {
...mEnLocale
}
},
zh: {
msg: {
...mZhLocale
}
}
}
/**
* 返回当前 lang
*/
function getLanguage() {
return store && store.getters && store.getters.language
}
const i18n = createI18n({
// 使用 Composition API 模式,则需要将其设置为false
legacy: false,
// 全局注入 $t 函数
globalInjection: true,
locale: getLanguage(),
messages
})
export default i18n
因为接口返回的数据也需要进行处理所有需要后端给我们配置语言,前端通过判断语言切换的时候在前置拦截器中配置国际化的请求头。
三,背景颜色切换
当我们点击对应的颜色切换的时候,获取到切换的颜色添加到将静态页面的 背景颜色中去,如果我们引入了elementui的组件,这个时候就需要对elementui组件的颜色进行改变。
import color from 'css-color-function'
import rgbHex from 'rgb-hex'
import axios from 'axios'
const formula = {
"shade-1": "color(primary shade(10%))",
"light-1": "color(primary tint(10%))",
"light-2": "color(primary tint(20%))",
"light-3": "color(primary tint(30%))",
"light-4": "color(primary tint(40%))",
"light-5": "color(primary tint(50%))",
"light-6": "color(primary tint(60%))",
"light-7": "color(primary tint(70%))",
"light-8": "color(primary tint(80%))",
"light-9": "color(primary tint(90%))",
"subMenuHover": "color(primary tint(70%))",
"subMenuBg": "color(primary tint(80%))",
"menuHover": "color(primary tint(90%))",
"menuBg": "color(primary)"
}
/**
* 写入新样式到 style
* @param {*} elNewStyle element-plus 的新样式
* @param {*} isNewStyleTag 是否生成新的 style 标签
*/
export const writeNewStyle = elNewStyle => {
console.log(27, elNewStyle);
const style = document.createElement('style')
style.innerText = elNewStyle
document.head.appendChild(style)
}
/**
* 根据主色值,生成最新的样式表
*/
export const generateNewStyle = async primaryColor => {
const colors = generateColors(primaryColor)
let cssText = await getOriginalStyle()
// 遍历生成的样式表,在 CSS 的原样式中进行全局替换
Object.keys(colors).forEach(key => {
cssText = cssText.replace(
new RegExp('(:|\\s+)' + key, 'g'),
'$1' + colors[key]
)
})
return cssText
}
/**
* 根据主色生成色值表
*/
export const generateColors = primary => {
if (!primary) return
const colors = {
primary
}
Object.keys(formula).forEach(key => {
const value = formula[key].replace(/primary/g, primary)
colors[key] = '#' + rgbHex(color.convert(value))
})
return colors
}
/**
* 获取当前 element-plus 的默认样式表
*/
const getOriginalStyle = async() => {
const version = require('element-plus/package.json').version
const url = `https://unpkg.com/element-plus@${version}/dist/index.css`
const { data } = await axios(url)
// console.log("默认样式", data);
// 把获取到的数据筛选为原样式模板
return getStyleTemplate(data)
}
/**
* 返回 style 的 template
*/
const getStyleTemplate = data => {
// element-plus 默认色值
const colorMap = {
'#3a8ee6': 'shade-1',
'#409eff': 'primary',
'#53a8ff': 'light-1',
'#66b1ff': 'light-2',
'#79bbff': 'light-3',
'#8cc5ff': 'light-4',
'#a0cfff': 'light-5',
'#b3d8ff': 'light-6',
'#c6e2ff': 'light-7',
'#d9ecff': 'light-8',
'#ecf5ff': 'light-9'
}
// 根据默认色值为要替换的色值打上标记
Object.keys(colorMap).forEach(key => {
const value = colorMap[key]
data = data.replace(new RegExp(key, 'ig'), value)
})
return data
}
在主题颜色切换的页面中引入对应的获取颜色的方法,和写入最新主题色的方法
import { generateNewStyle, writeNewStyle } from "../utils/theme.js";
// 1.1 获取主题色
const newStyleText = await generateNewStyle(“背景切换的16进制颜色”);
// 1.2 写入最新主题色
writeNewStyle(newStyleText);
四,动态路由的实现
因为后端只给我们返回的对应的路由name名称的数组,所以我们需要将他进行处理,并且转换成树形结构的数组进行渲染左侧菜单栏,这里的话我是新建了一个js的文件夹,在这个文件中定义对应的处理后端返回数组的方法,因为接口只给我们返回了对应路由的name值,所以我们需要创建出对应的私有路由,然后在私有路由中进行查找出与接口name匹配的路由进行处理添加为动态路由。
/*
一些公共的方法
*/
import store from "@/store"
//私有路由表
import privateRoutes from '../router/modules/privateRoutes';
import i18n from "@/language"
//计算当前登录账号的权限列表中是否有私有路由表中的路由,返回当前值
export function hasName(menuName) {
return privateRoutes.find(item => {
return item.name === menuName
})
}
//根据权限初始化公有私有路由表
export function generateRoute() {
const result = []
store.state.menus.forEach(item => {
result.push(hasName(item))
})
return result
}
function i18nRouteName(name) {
return i18n.global.t(`msg.route.${name}`)
}
//生成树状结构左侧菜单
export function deepTree(filterRoutes) {
const result = []
filterRoutes.forEach(item => {
//如果没有children没有meta,直接return (其实目的为了去掉login这条路由)
if ((item.children && item.children.length == 0) && JSON.stringify(item.meta) === '{}') {
return false
}
//如果有chidren,没有meta ,那么将当前的children传递到下次递归中
if ((item.children && item.children.length > 0) && JSON.stringify(item.meta) === '{}') {
result.push(...deepTree(item.children))
return false
}
/*
定义一个值,接收上次递归完毕的result所find到的path路径等于当前循环path路径的路由
意义在于当前路由可能会与父路由path重名,如果重名我们将他们放到同一个路由的children里
*/
let flag = result.find(ite => ite.path === item.path)
//如果flag为undefined,那么证明当前不重名,那么做判断,取反为true,添加路由
if (!flag) {
//路由为当前循环的item,children要清空掉, 添加后续重名的子路由
//为name添加国际化
flag = {
...item,
children: [],
meta: {
title: i18nRouteName(item.meta.title),
icon: item.meta.icon
}
}
//如果当前这条路由的meta的icon和title都存在, 那么我们才添加到result里
if (flag.meta.icon && flag.meta.title) {
result.push(flag)
}
}
//flag不为false,那么证明flag有find到的值,我们对这个值的children进行操作
if (item.children) {
flag.children.push(...deepTree(item.children))
}
})
return result
}
在home页面中引入对应的方法,传入接口返回的路由数组进行处理
import { generateRoute,deepTree} from "../utils/publicFn.js";
// 获取左侧菜单栏数据
const getlist1 = async () => {
let res = await getlist();
list.value = res.data;
// 将接口请求出来的动态路由参数存储到本地
// console.log("home页面数据", list.value.permission.menus);
store.commit("setmenus", list.value.permission.menus);
// 拿到接口请求出来的路由表
generateRoute().forEach((item) => {
router.addRoute("home", item);
});
// console.log(169,generateRoute());
menus();
};
在这里的时候已经将路由动态的添加到了路由中,然后因为我们在渲染的时候,需要将他转换成树形的结构图进行渲染左侧菜单栏。
const menus = () => {
const childrenmenus = [];
// 将所有的路由表拿出来,如果当前里面有子路由就拿出来放到一个新数组里面
router.getRoutes().forEach((item) => {
if (item.children && item.children.length > 0) {
childrenmenus.push(...item.children);
}
});
/*
以下是过滤出所有有孩子的路由,后边会用到,用于渲染左侧导航
所有的路由表去进行filter
条件为: 所有的子路由去循环,find当前的path等于所有路由循环时的path,然后取反
因为find方法搜索到一个之后就会停止循环,返回查找到的第一条值,
所以我们取反后为false,false就会跳过本次循环,这样的话,所有有子路由的路由就会过滤处后来
意思就是取出所有路由中的左侧导航需要的路由
*/
const filterRoutes = router.getRoutes().filter((item) => {
return !childrenmenus.find((ite) => {
return ite.path === item.path;
});
});
// console.log(childrenmenus);
console.log(deepTree(filterRoutes));
console.log("所有路由",router.getRoutes());
users.value=deepTree(filterRoutes)
};