bug fixed: 修复浏览器标题渲染错误问题,以及v4.0.2的一些小细节更新

This commit is contained in:
ray_wuhao 2023-07-02 01:00:59 +08:00
parent f21eeddd7f
commit dbb27902aa
34 changed files with 247 additions and 133 deletions

View File

@ -74,12 +74,22 @@ module.exports = {
'no-ex-assign': 2, // 禁止给 `catch` 语句中的异常参数赋值
'no-extend-native': 2, // 禁止扩展 `native` 对象
'no-extra-bind': 2, // 禁止不必要的函数绑定
'no-extra-boolean-cast': 2, // 禁止不必要的 `bool` 转换
'no-extra-boolean-cast': [
'error',
{
enforceForLogicalOperands: true,
},
], // 禁止不必要的 `bool` 转换
'no-extra-parens': 0, // 禁止非必要的括号
semi: ['error', 'never', { beforeStatementContinuationChars: 'always' }],
'no-fallthrough': 1, // 禁止 `switch` 穿透
'no-func-assign': 2, // 禁止重复的函数声明
'no-implicit-coercion': 1, // 禁止隐式转换
'no-implicit-coercion': [
'error',
{
allow: ['!!', '~'],
},
], // 禁止隐式转换
'no-implied-eval': 2, // 禁止使用隐式 `eval`
'no-invalid-regexp': 2, // 禁止无效的正则表达式
'no-invalid-this': 2, // 禁止无效的 `this`

View File

@ -6,6 +6,13 @@
- 新增平级路由配置router meta配置项sameLevel 允许你将子路由标记为平级模式,跳转时不会出发菜单、标签页更新,仅会更新面包屑
- 修改路由菜单显示、隐藏逻辑,现在仅会针对权限的验证匹配选择是否加入菜单列表中
- 更新 setupAppMenu 方法触发时机Layout => menu store现在将在 pinia menu store 初始化时触发 App Menu 更新
- 更新了 utils 包中的一些方法,进行了一些重写和重命名
### Fixes
- 修复不能正确渲染浏览器标题问题
- 修复初始化模板菜单函数与菜单更新函数重复执行一些方法的问题
## 4.0.1

View File

@ -3,7 +3,7 @@ import { RouterView } from 'vue-router'
import GlobalSpin from '@/spin/index'
import LockScreen from '@/components/AppComponents/AppLockScreen/index'
import { getCache } from '@/utils/cache'
import { getStorage } from '@/utils/cache'
import { get } from 'lodash-es'
import { useSetting } from '@/store'
import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element'
@ -24,18 +24,20 @@ const App = defineComponent({
} = __APP_CFG__ // 默认主题色
const body = document.body
const primaryColorOverride = getCache<SettingState>(
const primaryColorOverride = getStorage<SettingState>(
'piniaSettingStore',
'localStorage',
primaryColor,
)
const _p = get(
primaryColorOverride,
primaryColorOverride as SettingState,
'primaryColorOverride.common.primaryColor',
primaryColor,
)
const _fp = colorToRgba(_p || primaryColor, 0.3)
const _fp = colorToRgba(_p, 0.3)
/** 设置全局主题色 css 变量 */
body.style.setProperty('--ray-theme-primary-color', _p || primaryColor)
body.style.setProperty('--ray-theme-primary-color', _p)
body.style.setProperty(
'--ray-theme-primary-fade-color',
_fp || primaryFadeColor,

View File

@ -21,7 +21,7 @@
import { useAxiosInterceptor, axiosCanceler } from '@/axios/helper/interceptor'
import { appendRequestHeaders } from '@/axios/helper/axiosCopilot'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import { getCache } from '@/utils/cache'
import { getStorage } from '@/utils/cache'
import type {
RequestInterceptorConfig,
@ -40,7 +40,7 @@ const { setImplement } = useAxiosInterceptor()
* request instance ,
*/
const requestHeaderToken = (ins: RequestInterceptorConfig, mode: string) => {
const token = getCache<string>(APP_CATCH_KEY.token)
const token = getStorage<string>(APP_CATCH_KEY.token)
if (ins.url) {
// TODO: 根据 url 不同是否设置 token

View File

@ -23,7 +23,7 @@ import { NAvatar, NSpace } from 'naive-ui'
import { avatarProps, spaceProps } from 'naive-ui'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
import { getCache } from '@/utils/cache'
import { getStorage } from '@/utils/cache'
import type { PropType } from 'vue'
import type { AvatarProps, SpaceProps } from 'naive-ui'
@ -48,7 +48,7 @@ const AppAvatar = defineComponent({
},
},
setup(props) {
const signin = getCache<SigninCallback>(APP_CATCH_KEY.signin)
const signin = getStorage<SigninCallback>(APP_CATCH_KEY.signin)
const cssVars = computed(() => {
const vars = {
'--app-avatar-cursor': props.cursor,

View File

@ -9,6 +9,7 @@ import { useVueRouter } from '@/router/helper/useVueRouter'
import type { MenuInst } from 'naive-ui'
import type { NaiveMenuOptions } from '@/types/modules/component'
import type { AppMenuOption } from '@/types/modules/app'
const LayoutMenu = defineComponent({
name: 'LayoutMenu',
@ -106,7 +107,9 @@ const LayoutMenu = defineComponent({
collapsed={this.modelCollapsed}
collapsedIconSize={APP_MENU_CONFIG.MENU_COLLAPSED_ICON_SIZE}
collapsedWidth={APP_MENU_CONFIG.MENU_COLLAPSED_WIDTH}
onUpdateValue={this.changeMenuModelValue.bind(this)}
onUpdateValue={(key, op) => {
this.changeMenuModelValue(key, op as unknown as AppMenuOption)
}}
accordion={APP_MENU_CONFIG.MENU_ACCORDION}
/>
</NLayoutSider>

View File

@ -33,10 +33,10 @@ import { uuid } from '@/utils/hook'
import { hasClass } from '@/utils/element'
import { redirectRouterToDashboard } from '@/router/helper/routerCopilot'
import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { getElement } from '@use-utils/element'
import { getElements } from '@use-utils/element'
import type { MenuOption, ScrollbarInst } from 'naive-ui'
import type { MenuTagOptions } from '@/types/modules/app'
import type { MenuTagOptions, AppMenuOption } from '@/types/modules/app'
const MenuTag = defineComponent({
name: 'MenuTag',
@ -247,7 +247,7 @@ const MenuTag = defineComponent({
*
* @param item
*/
const handleTagClick = (item: MenuOption) => {
const handleTagClick = (item: AppMenuOption) => {
changeMenuModelValue(item.key as string, item)
}
@ -381,7 +381,7 @@ const MenuTag = defineComponent({
/** 动态更新 menu tag 所在位置 */
const positionMenuTag = () => {
nextTick().then(() => {
const tags = getElement<HTMLElement>(
const tags = getElements<HTMLElement>(
`attr:${MENU_TAG_DATA}="${menuKey.value}"`,
)

View File

@ -42,12 +42,16 @@ const Breadcrumb = defineComponent({
key: string | number,
option: DropdownOption,
) => {
changeMenuModelValue(key, option)
changeMenuModelValue(key, option as unknown as AppMenuOption)
}
const handleBreadcrumbItemClick = (option: AppMenuOption) => {
if (!option.children?.length) {
changeMenuModelValue(option.key, option as unknown as MenuOption)
const { meta = {} } = option
if (!meta.sameLevel) {
changeMenuModelValue(option.key, option)
}
}
}

View File

@ -109,7 +109,7 @@ const GlobalSeach = defineComponent({
}
}
const handleSearchItemClick = (option: MenuOption) => {
const handleSearchItemClick = (option: AppMenuOption) => {
const meta = option.meta as AppRouteMeta
/** 如果配置站外跳转则不会关闭搜索框 */
@ -118,7 +118,7 @@ const GlobalSeach = defineComponent({
} else {
modelShow.value = false
changeMenuModelValue(option.key as string, option)
changeMenuModelValue(option.key, option)
}
}

View File

@ -18,7 +18,7 @@
import { set } from 'lodash-es'
import { zhCN, dateZhCN } from 'naive-ui' // 导入 `naive ui` 中文包
import { getCache } from '@use-utils/cache'
import { getStorage } from '@use-utils/cache'
import { SYSTEM_DEFAULT_LOCAL } from '@/appConfig/localConfig'
import { APP_CATCH_KEY } from '@/appConfig/appConfig'
@ -126,10 +126,11 @@ export const naiveLocales = (key: string) => {
* @remak , `main.ts` , `i18n`
*/
export const getAppDefaultLanguage = () => {
const language = getCache<string>(
const language = getStorage<string>(
APP_CATCH_KEY.localeLanguage,
'localStorage',
SYSTEM_DEFAULT_LOCAL,
)
return language ? language : SYSTEM_DEFAULT_LOCAL
return language || SYSTEM_DEFAULT_LOCAL
}

View File

@ -115,5 +115,5 @@ hidden: 是否显示
noLocalTitle: 不使用国际化渲染 Menu Titile
ignoreAutoResetScroll: 该页面内容区域自动初始化滚动条位置
keepAlive: 是否缓存该页面(需要配置 APP_KEEP_ALIVE setupKeepAlive 属性为 true 启用才有效)
sameLevel: 是否标记该路由为平级模式
sameLevel: 是否标记该路由为平级模式,如果标记为平级模式,会使路由菜单项隐藏。如果在含有子节点处,设置了该属性,会导致子节点全部被隐藏
```

View File

@ -20,11 +20,10 @@
* , ,
*/
import { getCache, setCache } from '@/utils/cache'
import { useSignin } from '@/store'
import { getStorage } from '@/utils/cache'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/appConfig/appConfig'
import { redirectRouterToDashboard } from '@/router/helper/routerCopilot'
import { validRole, validMenuItemShow } from '@/router/helper/routerCopilot'
import { validRole } from '@/router/helper/routerCopilot'
import type {
Router,
@ -38,8 +37,12 @@ export const permissionRouter = (router: Router) => {
const { beforeEach } = router
beforeEach((to, from, next) => {
const token = getCache<string>(APP_CATCH_KEY.token)
const route = getCache<string>('menuKey') || ROOT_ROUTE.path
const token = getStorage<string>(APP_CATCH_KEY.token)
const route = getStorage<string>(
'menuKey',
'sessionStorage',
ROOT_ROUTE.path,
) as string
const { meta } = to
if (token !== null) {

View File

@ -20,7 +20,7 @@ import {
import { useSignin } from '@/store'
import { useVueRouter } from '@/router/helper/useVueRouter'
import { ROOT_ROUTE } from '@/appConfig/appConfig'
import { setCache } from '@/utils/cache'
import { setStorage } from '@/utils/cache'
import type { Router } from 'vue-router'
import type { AppRouteMeta } from '@/router/type'
@ -58,18 +58,27 @@ export const validRole = (meta: AppRouteMeta) => {
/**
*
* @remark
* @remark
*
* , hidden role
* ,
* , hidden sameLevel
* sameLevel
*
* , 使 validRole
*/
export const validMenuItemShow = (option: AppMenuOption) => {
const { meta = {} } = option
const { hidden } = meta
const { hidden, sameLevel } = meta
return hidden === undefined || hidden === false ? true : false
// 如果该路由被标记为平级模式, 则会强制不显示在菜单中
if (sameLevel) {
return false
}
if (!sameLevel && !hidden) {
return true
}
return !hidden ? true : false
}
/**
@ -119,7 +128,7 @@ export const redirectRouterToDashboard = (isReplace = true) => {
const { push, replace } = router
const { path } = ROOT_ROUTE
setCache('menuKey', path)
setStorage('menuKey', path)
isReplace ? push(path) : replace(path)
}

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,9 +1,8 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'
import { LAYOUT } from '@/router/constant/index'
const multiMenu: AppRouteRecordRaw = {
path: '/multi',
name: 'MultiMenu',

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,9 +1,8 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'
import { LAYOUT } from '@/router/constant/index'
const rely: AppRouteRecordRaw = {
path: '/rely',
name: 'RelyAbout',

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -1,4 +1,5 @@
import { t } from '@/locales/useI18n'
import { LAYOUT } from '@/router/constant/index'
import type { AppRouteRecordRaw } from '@/router/type'

View File

@ -14,7 +14,7 @@
import { APP_MENU_CONFIG, ROOT_ROUTE } from '@/appConfig/appConfig'
import RayIcon from '@/components/RayIcon/index'
import { isValueType } from '@/utils/hook'
import { getCache, setCache } from '@/utils/cache'
import { getStorage, setStorage } from '@/utils/cache'
import type { VNode } from 'vue'
import type {
@ -174,10 +174,11 @@ export const hasMenuIcon = (option: AppMenuOption) => {
/** 获取缓存的 menu key, 如果未获取到则使用 ROOTROUTE path 当作默认激活路由菜单 */
export const getCatchMenuKey = () => {
const { path: rootPath } = ROOT_ROUTE
const cacheMenuKey =
getCache<AppMenuKey>('menuKey') === null
? rootPath
: getCache<AppMenuKey>('menuKey')
const cacheMenuKey = getStorage<AppMenuKey>(
'menuKey',
'sessionStorage',
rootPath,
)
return cacheMenuKey
}

View File

@ -24,8 +24,8 @@
import { NEllipsis } from 'naive-ui'
import { getCache, setCache } from '@/utils/cache'
import { validMenuItemShow, validRole } from '@/router/helper/routerCopilot'
import { setStorage } from '@/utils/cache'
import { validRole, validMenuItemShow } from '@/router/helper/routerCopilot'
import {
parseAndFindMatchingNodes,
updateDocumentTitle,
@ -86,7 +86,10 @@ export const useMenu = defineStore(
*
* ,
*/
const setBreadcrumbOptions = (key: string | number, option: MenuOption) => {
const setBreadcrumbOptions = (
key: string | number,
option: AppMenuOption,
) => {
const { meta } = option as unknown as AppRouteRecordRaw
menuState.breadcrumbOptions = getCompleteRoutePath(menuState.options, key)
@ -124,12 +127,12 @@ export const useMenu = defineStore(
/** 当 url 地址发生变化触发 menuTagOptions 更新 */
const setMenuTagOptionsWhenMenuValueChange = (
key: string | number,
option: MenuOption,
option: AppMenuOption,
) => {
const tag = menuState.menuTagOptions.find((curr) => curr.path === key)
if (!tag) {
menuState.menuTagOptions.push(option as unknown as MenuTagOptions)
menuState.menuTagOptions.push(option as MenuTagOptions)
}
}
@ -141,8 +144,11 @@ export const useMenu = defineStore(
* @remark `menu key`
* @remark , key (router push )
*/
const changeMenuModelValue = (key: string | number, option: MenuOption) => {
const { meta, path } = option as unknown as AppRouteRecordRaw
const changeMenuModelValue = (
key: string | number,
option: AppMenuOption,
) => {
const { meta, path } = option
if (meta.windowOpen) {
window.open(meta.windowOpen)
@ -169,10 +175,10 @@ export const useMenu = defineStore(
/** 检查是否为根路由 */
const count = (path.match(new RegExp('/', 'g')) || []).length
/** 更新浏览器标题 */
updateDocumentTitle(option as unknown as AppMenuOption)
/** 更新缓存队列 */
setKeepAliveInclude(option as unknown as AppMenuOption)
/** 更新浏览器标题 */
updateDocumentTitle(option as unknown as AppMenuOption)
if (!meta.sameLevel || (meta.sameLevel && count === 1)) {
/** 更新标签菜单 */
@ -182,7 +188,7 @@ export const useMenu = defineStore(
menuState.menuKey = key
/** 缓存菜单 key(sessionStorage) */
setCache('menuKey', key)
setStorage('menuKey', key)
} else {
setBreadcrumbOptions(menuState.menuKey || '', option)
}
@ -196,21 +202,33 @@ export const useMenu = defineStore(
* @remark
* @remark
*/
const updateMenuKeyWhenRouteUpdate = (path: string) => {
const appRawRoutes = expandRoutes(getAppRawRoutes())
const updateMenuKeyWhenRouteUpdate = async (path: string) => {
// 获取 `/` 出现次数(如果为 1 则表示该路径为根路由路径)
const count = (path.match(new RegExp('/', 'g')) || []).length
const fd = appRawRoutes.find((curr) => curr.path === path)
let combinePath = path
if (count > 1) {
// 如果不是跟路径则取出最后一项字符
const splitPath = path.split('/').filter((curr) => curr)
combinePath = splitPath[splitPath.length - 1]
}
if (fd) {
changeMenuModelValue(combinePath, fd as unknown as MenuOption)
const findMenuOption = (pathKey: string, options: AppMenuOption[]) => {
for (const curr of options) {
if (curr.children?.length) {
findMenuOption(pathKey, curr.children)
}
if (pathKey === curr.key) {
changeMenuModelValue(pathKey, curr)
break
}
}
}
findMenuOption(combinePath, menuState.options)
}
/**
@ -237,8 +255,6 @@ export const useMenu = defineStore(
}),
breadcrumbLabel: label.value,
/** 检查该菜单项是否展示 */
show:
meta.hidden === false || meta.hidden === undefined ? true : false,
} as AppMenuOption
/** 合并 icon */
const attr: AppMenuOption = Object.assign({}, route, {
@ -246,14 +262,12 @@ export const useMenu = defineStore(
})
if (option.path === getCatchMenuKey()) {
/** 设置浏览器标题 */
updateDocumentTitle(attr)
setMenuTagOptionsWhenMenuValueChange(
option.path,
attr as unknown as MenuOption,
)
/** 设置标签页(初始化时执行设置一次, 避免含有平级路由模式情况时出现不能正确设置标签页的情况) */
setMenuTagOptionsWhenMenuValueChange(option.path, attr)
}
attr.show = validMenuItemShow(attr)
return attr
}
@ -320,9 +334,9 @@ export const useMenu = defineStore(
const setupPiniaMenuStore = async () => {
if (isSetupAppMenuLock.value) {
await setupAppMenu()
isSetupAppMenuLock.value = false
}
isSetupAppMenuLock.value = false
}
/** 监听路由变化并且更新路由菜单与菜单标签 */
@ -333,7 +347,7 @@ export const useMenu = defineStore(
const match = newData.match(reg)?.[1]
await setupPiniaMenuStore()
updateMenuKeyWhenRouteUpdate(match || '')
await updateMenuKeyWhenRouteUpdate(match || '')
},
{
immediate: true,

View File

@ -1,5 +1,5 @@
import { getAppDefaultLanguage } from '@/locales/helper'
import { setCache } from '@use-utils/cache'
import { setStorage } from '@use-utils/cache'
import { set } from 'lodash-es'
import { addClass, removeClass, colorToRgba } from '@/utils/element'
import { useI18n } from '@/locales/useI18n'
@ -46,7 +46,7 @@ export const useSetting = defineStore(
settingState.localeLanguage = key
setCache('localeLanguage', key, 'localStorage')
setStorage('localeLanguage', key, 'localStorage')
}
/** 切换主题色 */

View File

@ -20,7 +20,7 @@
*/
import { isEmpty } from 'lodash-es'
import { removeCache } from '@/utils/cache'
import { removeStorage } from '@/utils/cache'
import type {
SigninForm,
@ -79,7 +79,7 @@ export const useSignin = defineStore(
*/
const logout = () => {
window.$message.info('账号退出中...')
removeCache('all-sessionStorage')
removeStorage('all-sessionStorage')
setTimeout(() => window.location.reload())
}

View File

@ -42,3 +42,9 @@ export type CipherParams = CryptoJS.lib.CipherParams
export type AnyFunc = (...args: any[]) => any
export type AnyVoidFunc = (...args: any[]) => void
export type PartialCSSStyleDeclaration = Partial<
Record<keyof CSSStyleDeclaration, string>
>
export type ElementSelector = string | `attr:${string}`

View File

@ -18,16 +18,26 @@ import type { CacheType } from '@/types/modules/utils'
* @param key key
* @param value
*/
export const setCache = <T = unknown>(
export const setStorage = <T = unknown>(
key: string,
value: T,
type: CacheType = 'sessionStorage',
) => {
const waitCacheValue = JSON.stringify(value)
if (!key) {
console.error('Failed to set stored data: key is empty or undefined')
type === 'localStorage'
? window.localStorage.setItem(key, waitCacheValue)
: window.sessionStorage.setItem(key, waitCacheValue)
return
}
try {
const waitCacheValue = JSON.stringify(value)
type === 'localStorage'
? window.localStorage.setItem(key, waitCacheValue)
: window.sessionStorage.setItem(key, waitCacheValue)
} catch (error) {
console.error(`Failed to set stored data for key '${key}'`, error)
}
}
/**
@ -35,16 +45,27 @@ export const setCache = <T = unknown>(
* @param key key
* @returns
*/
export const getCache = <T>(
export const getStorage = <T>(
key: string,
type: CacheType = 'sessionStorage',
storageType: CacheType = 'sessionStorage',
defaultValue?: T,
): T | null => {
const data =
type === 'localStorage'
? window.localStorage.getItem(key)
: window.sessionStorage.getItem(key)
try {
const data =
storageType === 'localStorage'
? window.localStorage.getItem(key)
: window.sessionStorage.getItem(key)
return Object.is(data, null) ? null : JSON.parse(data as string)
if (data === null) {
return defaultValue ?? null
}
return JSON.parse(data) as T
} catch (error) {
console.error(`Failed to get stored data for key '${key}'`, error)
return defaultValue ?? null
}
}
/**
@ -56,7 +77,7 @@ export const getCache = <T>(
* - all-sessionStorage: 删除所有 sessionStorage
* - all-localStorage: 删除所有 localStorage
*/
export const removeCache = (
export const removeStorage = (
key: string | 'all' | 'all-sessionStorage' | 'all-localStorage',
type: CacheType = 'sessionStorage',
) => {
@ -78,6 +99,12 @@ export const removeCache = (
break
default:
if (!key) {
console.error('Failed to remove stored data: key is empty or undefined')
return
}
type === 'localStorage'
? window.localStorage.removeItem(key)
: window.sessionStorage.removeItem(key)

View File

@ -1,7 +1,11 @@
import { isValueType } from '@use-utils/hook'
import { APP_REGEX } from '@/appConfig/regConfig'
import type { EventListenerOrEventListenerObject } from '@/types/modules/utils'
import type {
EventListenerOrEventListenerObject,
PartialCSSStyleDeclaration,
ElementSelector,
} from '@/types/modules/utils'
/**
*
@ -116,6 +120,8 @@ export const hasClass = (element: HTMLElement, className: string) => {
* @param el Target element dom
* @param styles (, )
*
*
* @example
* style of string
* ```
* const styles = 'width: 100px; height: 100px; background: red;'
@ -132,27 +138,37 @@ export const hasClass = (element: HTMLElement, className: string) => {
* addStyle(styles)
* ```
*/
export const addStyle = <K extends keyof CSSStyleDeclaration & string>(
export const addStyle = (
el: HTMLElement,
styles: K | Partial<CSSStyleDeclaration>,
styles: PartialCSSStyleDeclaration | string,
) => {
if (el) {
if (isValueType<object>(styles, 'Object')) {
Object.keys(styles).forEach((item) => {
el.style[item] = styles[item]
})
} else if (isValueType<string>(styles, 'String')) {
const _styles = styles
_styles.split(';').forEach((item) => {
const [_k, _v] = item.split(':')
if (_k && _v) {
el.style[_k.trim()] = _v.trim()
}
})
}
if (!el) {
return
}
let styleObj: PartialCSSStyleDeclaration
if (isValueType<string>(styles, 'String')) {
styleObj = styles.split(';').reduce((pre, curr) => {
const [key, value] = curr.split(':').map((s) => s.trim())
if (key && value) {
pre[key] = value
}
return pre
}, {} as PartialCSSStyleDeclaration)
} else {
styleObj = styles
}
Object.keys(styleObj).forEach((key) => {
const value = styleObj[key]
if (key in el.style) {
el.style[key] = value
}
})
}
/**
@ -160,15 +176,17 @@ export const addStyle = <K extends keyof CSSStyleDeclaration & string>(
* @param el Target element dom
* @param styles
*/
export const removeStyle = <K extends keyof CSSStyleDeclaration & string>(
export const removeStyle = (
el: HTMLElement,
styles: K[],
styles: (keyof CSSStyleDeclaration & string)[],
) => {
if (el) {
styles.forEach((curr) => {
el.style.removeProperty(curr)
})
if (!el) {
return
}
styles.forEach((curr) => {
el.style.removeProperty(curr)
})
}
/**
@ -222,33 +240,33 @@ export const colorToRgba = (color: string, alpha = 1) => {
* :
*
* class:
* const el = getElement('.demo')
* const el = getElements('.demo')
* id:
* const el = getElement('#demo')
* const el = getElements('#demo')
* attribute:
* const el = getElement('attr:type=button')
* const el = getElements('attr:type=button')
*
* const el = getElement('attr:type')
* const el = getElements('attr:type')
*/
export const getElement = <T extends Element>(element: string) => {
if (!element) {
export const getElements = <T extends Element = Element>(
selector: ElementSelector,
) => {
if (!selector) {
return null
}
let queryParam: string
if (element.startsWith('attr:')) {
queryParam = '[' + element.replace('attr:', '') + ']'
} else {
queryParam = element
}
const queryParam = selector.startsWith('attr:')
? `[${selector.replace('attr:', '')}]`
: selector
try {
const el = Array.from(document.querySelectorAll<T>(queryParam))
const elements = Array.from(document.querySelectorAll<T>(queryParam))
return el
} catch (e) {
return []
return elements
} catch (error) {
console.error(`Failed to get elements for selector '${selector}'`, error)
return null
}
}

View File

@ -1,6 +1,6 @@
import { NForm, NFormItem, NInput, NButton, NSpace, NDivider } from 'naive-ui'
import { setCache } from '@/utils/cache'
import { setStorage } from '@/utils/cache'
import { setSpin } from '@/spin'
import { useSignin } from '@/store'
import { useI18n } from '@/locales/useI18n'
@ -55,8 +55,8 @@ const Signin = defineComponent({
window.$message.success(`欢迎${signinForm.value.name}登陆~`)
setCache(APP_CATCH_KEY.token, 'tokenValue')
setCache(APP_CATCH_KEY.signin, res.data)
setStorage(APP_CATCH_KEY.token, 'tokenValue')
setStorage(APP_CATCH_KEY.signin, res.data)
router.push(path)
}, 2 * 1000)