From 26b6f857cdfb5477d34cd524f07379fa38a9dd1a Mon Sep 17 00:00:00 2001 From: xiaoxian521 <1923740402@qq.com> Date: Sat, 20 Nov 2021 19:43:49 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=90=8C=E6=AD=A5=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E7=89=88=E5=88=86=E6=94=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 9 + src/layout/components/tag/index.scss | 318 +++++++++++++++++++++++ src/layout/components/tag/index.vue | 455 ++++++++++----------------------- src/layout/theme/auroraGreen-vars.scss | 3 +- src/layout/theme/default-vars.scss | 27 +- src/layout/theme/dusk-vars.scss | 3 +- src/layout/theme/light-vars.scss | 2 +- src/layout/theme/mingQing-vars.scss | 3 +- src/layout/theme/pink-vars.scss | 3 +- src/layout/theme/saucePurple-vars.scss | 3 +- src/layout/theme/volcano-vars.scss | 3 +- src/layout/theme/yellow-vars.scss | 3 +- src/layout/types.ts | 6 + src/plugins/fontawesome/index.ts | 2 + src/style/element-plus.scss | 6 - src/style/index.scss | 4 +- src/style/sidebar.scss | 28 +- src/style/transition.scss | 2 - 19 files changed, 513 insertions(+), 368 deletions(-) create mode 100644 src/layout/components/tag/index.scss diff --git a/package.json b/package.json index 6f405da..e09e508 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "path": "^0.12.7", "path-to-regexp": "^6.2.0", "pinia": "^2.0.0-rc.14", + "remixicon": "^2.5.0", "resize-observer-polyfill": "^1.5.1", "responsive-storage": "^1.0.11", "typescript-cookie": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3df28b..b18048d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,6 +49,7 @@ specifiers: postcss-import: 14.0.0 prettier: 2.3.2 pretty-quick: 3.1.1 + remixicon: ^2.5.0 resize-observer-polyfill: ^1.5.1 responsive-storage: ^1.0.11 rimraf: 3.0.2 @@ -93,6 +94,7 @@ dependencies: path: 0.12.7 path-to-regexp: 6.2.0 pinia: 2.0.2_typescript@4.4.2+vue@3.2.21 + remixicon: 2.5.0 resize-observer-polyfill: 1.5.1 responsive-storage: 1.0.11_vue@3.2.21 typescript-cookie: 1.0.0 @@ -5221,6 +5223,13 @@ packages: - supports-color dev: true + /remixicon/2.5.0: + resolution: + { + integrity: sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww== + } + dev: false + /repeat-string/1.6.1: resolution: { integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc= } engines: { node: ">=0.10" } diff --git a/src/layout/components/tag/index.scss b/src/layout/components/tag/index.scss new file mode 100644 index 0000000..adfacb9 --- /dev/null +++ b/src/layout/components/tag/index.scss @@ -0,0 +1,318 @@ +@keyframes scheduleInWidth { + from { + width: 0; + } + + to { + width: 100%; + } +} + +@keyframes scheduleOutWidth { + from { + width: 100%; + } + + to { + width: 0; + } +} + +@-webkit-keyframes rotate { + from { + -webkit-transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(360deg); + } +} + +@-moz-keyframes rotate { + from { + -moz-transform: rotate(0deg); + } + + to { + -moz-transform: rotate(360deg); + } +} + +@-o-keyframes rotate { + from { + -o-transform: rotate(0deg); + } + + to { + -o-transform: rotate(360deg); + } +} + +@keyframes rotate { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +.tags-view { + width: 100%; + font-size: 14px; + display: flex; + align-items: center; + box-shadow: 0 0 1px #888; + color: var(--el-text-color-regular); + background: #fff; + + .scroll-item { + border-radius: 3px 3px 0 0; + padding: 2px 6px; + display: inline-block; + position: relative; + margin-right: 4px; + height: 28px; + line-height: 25px; + transition: all 0.4s; + + .el-icon-close { + font-size: 10px; + color: #1890ff; + cursor: pointer; + + &:hover { + border-radius: 50%; + color: #fff; + background: #b4bccc; + font-size: 14px; + } + } + + &.is-closable:not(:first-child) { + &:hover { + padding-right: 8px; + } + } + } + + a { + text-decoration: none; + color: #666; + padding: 0 4px 0 4px; + } + + .scroll-container { + flex: 1; + overflow: hidden; + padding: 5px 0; + white-space: nowrap; + position: relative; + + .tab { + position: relative; + float: left; + list-style: none; + overflow: visible; + white-space: nowrap; + transition: transform 0.5s ease-in-out; + + .scroll-item { + transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); + + &:nth-child(1) { + margin-left: 5px; + } + } + } + } + + .right-button { + display: flex; + font-size: 16px; + + li { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 38px; + border-right: 1px solid #ccc; + cursor: pointer; + } + } + + /* 右键菜单 */ + .contextmenu { + margin: 0; + background: #fff; + position: absolute; + list-style-type: none; + padding: 5px 0; + border-radius: 4px; + color: #000000d9; + font-weight: normal; + font-size: 13px; + white-space: nowrap; + outline: 0; + box-shadow: 0 2px 8px rgb(0 0 0 / 15%); + + li { + width: 100%; + margin: 0; + padding: 7px 12px; + cursor: pointer; + display: flex; + align-items: center; + + &:hover { + background: #eee; + } + + svg { + display: block; + margin-right: 0.5em; + } + } + } +} + +.el-dropdown-menu { + padding: 0; + + li { + width: 100%; + margin: 0; + padding: 0 12px; + cursor: pointer; + display: flex; + align-items: center; + + svg { + display: block; + margin-right: 0.5em; + } + } +} + +.el-dropdown-menu__item:not(.is-disabled):hover { + color: #606266; + background: #f0f0f0; +} + +:deep(.el-dropdown-menu__item) i { + margin-right: 10px; +} + +.el-dropdown-menu__item--divided::before { + margin: 0; +} + +.el-dropdown-menu__item.is-disabled { + cursor: not-allowed; +} + +.is-active { + background-color: #eaf4fe; + position: relative; + color: #fff; + + a { + color: #1890ff; + } +} + +.ri-arrow-left-s-line { + width: 40px; + height: 38px; + line-height: 38px; + text-align: center; + font-size: 20px; + color: #00000073; + box-shadow: 5px 0 5px -6px #ccc; + + &:hover { + cursor: w-resize; + } +} + +.ri-arrow-right-s-line { + width: 40px; + height: 38px; + line-height: 38px; + text-align: center; + font-size: 20px; + border-right: 1px solid #ccc; + color: #00000073; + box-shadow: -5px 0 5px -6px #ccc; + + &:hover { + cursor: e-resize; + } +} + +/* 卡片模式 */ +.card-active { + border: 1px solid #1890ff; +} + +/* 卡片模式下鼠标移入显示蓝色边框 */ +.card-in { + border: 1px solid #1890ff; + color: #1890ff; + + a { + color: #1890ff; + } +} + +/* 卡片模式下鼠标移出隐藏蓝色边框 */ +.card-out { + border: none; + color: #666; + + a { + color: #666; + } +} + +/* 灵动模式 */ +.schedule-active { + width: 100%; + height: 2px; + position: absolute; + left: 0; + bottom: 0; + background: #1890ff; +} + +/* 灵动模式下鼠标移入显示蓝色进度条 */ +.schedule-in { + width: 100%; + height: 2px; + position: absolute; + left: 0; + bottom: 0; + background: #1890ff; + animation: scheduleInWidth 400ms ease-in; +} + +/* 灵动模式下鼠标移出隐藏蓝色进度条 */ +.schedule-out { + width: 0; + height: 2px; + position: absolute; + left: 0; + bottom: 0; + background: #1890ff; + animation: scheduleOutWidth 400ms ease-in; +} + +/* 刷新按钮动画效果 */ +.refresh-button { + -webkit-animation: rotate 600ms linear infinite; + -moz-animation: rotate 600ms linear infinite; + -o-animation: rotate 600ms linear infinite; + animation: rotate 600ms linear infinite; +} diff --git a/src/layout/components/tag/index.vue b/src/layout/components/tag/index.vue index 161cabd..111eb2a 100644 --- a/src/layout/components/tag/index.vue +++ b/src/layout/components/tag/index.vue @@ -24,15 +24,6 @@ import { getCurrentInstance, ComputedRef } from "vue"; -import { RouteConfigs, relativeStorageType, tagsViewsType } from "../../types"; -import { emitter } from "/@/utils/mitt"; -import { templateRef } from "@vueuse/core"; -import { handleAliveRoute, delAliveRoutes } from "/@/router"; -import { storageLocal } from "/@/utils/storage"; -import { useRoute, useRouter } from "vue-router"; -import { usePermissionStoreHook } from "/@/store/modules/permission"; -import { toggleClass, removeClass, hasClass } from "/@/utils/operate"; -import { transformI18n } from "/@/utils/i18n"; import close from "/@/assets/svg/close.svg"; import refresh from "/@/assets/svg/refresh.svg"; @@ -41,16 +32,108 @@ import closeLeft from "/@/assets/svg/close_left.svg"; import closeOther from "/@/assets/svg/close_other.svg"; import closeRight from "/@/assets/svg/close_right.svg"; -let refreshButton = "refresh-button"; -const instance = getCurrentInstance(); +import { emitter } from "/@/utils/mitt"; +import { templateRef, useResizeObserver, useDebounceFn } from "@vueuse/core"; +import { transformI18n } from "/@/utils/i18n"; +import { storageLocal } from "/@/utils/storage"; +import { useRoute, useRouter } from "vue-router"; +import { handleAliveRoute, delAliveRoutes } from "/@/router"; +import { usePermissionStoreHook } from "/@/store/modules/permission"; +import { toggleClass, removeClass, hasClass } from "/@/utils/operate"; +import { RouteConfigs, relativeStorageType, tagsViewsType } from "../../types"; -// 响应式storage -let relativeStorage: relativeStorageType; const route = useRoute(); const router = useRouter(); +const translateX = ref(0); +const activeIndex = ref(-1); +let refreshButton = "refresh-button"; +const instance = getCurrentInstance(); +let relativeStorage: relativeStorageType; const showTags = ref(storageLocal.getItem("tagsVal") || false); +const tabDom = templateRef("tabDom", null); const containerDom = templateRef("containerDom", null); -const activeIndex = ref(-1); +const scrollbarDom = templateRef("scrollbarDom", null); + +const dynamicTagView = () => { + const index = dynamicTagList.value.findIndex(item => { + return item.path === route.path; + }); + moveToView(index); +}; + +watch([route], () => { + dynamicTagView(); +}); + +useResizeObserver( + scrollbarDom, + useDebounceFn(() => { + dynamicTagView(); + }, 200) +); + +const tabNavPadding = 10; +const moveToView = (index: number): void => { + if (!instance.refs["dynamic" + index]) { + return; + } + const tabItemEl = instance.refs["dynamic" + index]; + const tabItemElOffsetLeft = (tabItemEl as HTMLElement).offsetLeft; + const tabItemOffsetWidth = (tabItemEl as HTMLElement).offsetWidth; + // 标签页导航栏可视长度(不包含溢出部分) + const scrollbarDomWidth = scrollbarDom.value + ? scrollbarDom.value.offsetWidth + : 0; + // 已有标签页总长度(包含溢出部分) + const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0; + + if (tabDomWidth < scrollbarDomWidth || tabItemElOffsetLeft === 0) { + translateX.value = 0; + } else if (tabItemElOffsetLeft < -translateX.value) { + // 标签在可视区域左侧 + translateX.value = -tabItemElOffsetLeft + tabNavPadding; + } else if ( + tabItemElOffsetLeft > -translateX.value && + tabItemElOffsetLeft + tabItemOffsetWidth < + -translateX.value + scrollbarDomWidth + ) { + // 标签在可视区域 + translateX.value = Math.min( + 0, + scrollbarDomWidth - + tabItemOffsetWidth - + tabItemElOffsetLeft - + tabNavPadding + ); + } else { + // 标签在可视区域右侧 + translateX.value = -( + tabItemElOffsetLeft - + (scrollbarDomWidth - tabNavPadding - tabItemOffsetWidth) + ); + } +}; + +const handleScroll = (offset: number): void => { + const scrollbarDomWidth = scrollbarDom.value + ? scrollbarDom.value?.offsetWidth + : 0; + const tabDomWidth = tabDom.value ? tabDom.value.offsetWidth : 0; + if (offset > 0) { + translateX.value = Math.min(0, translateX.value + offset); + } else { + if (scrollbarDomWidth < tabDomWidth) { + if (translateX.value >= -(tabDomWidth - scrollbarDomWidth)) { + translateX.value = Math.max( + translateX.value + offset, + scrollbarDomWidth - tabDomWidth + ); + } + } else { + translateX.value = 0; + } + } +}; const tagsViews = ref>([ { @@ -469,40 +552,50 @@ onBeforeMount(() => { diff --git a/src/layout/theme/auroraGreen-vars.scss b/src/layout/theme/auroraGreen-vars.scss index e6365fa..2fcea09 100644 --- a/src/layout/theme/auroraGreen-vars.scss +++ b/src/layout/theme/auroraGreen-vars.scss @@ -1,5 +1,4 @@ -// 极光绿 - +/* 极光绿 */ $subMenuActiveText: #fff; $menuBg: #0b1e15; $menuHover: #60ac80; diff --git a/src/layout/theme/default-vars.scss b/src/layout/theme/default-vars.scss index b9d8b91..8b2fd4a 100644 --- a/src/layout/theme/default-vars.scss +++ b/src/layout/theme/default-vars.scss @@ -1,24 +1,29 @@ /** -*此scss变量文件作为multipleScopeVars去编译时,会自动移除!default以达到变量提升 -*同时此scss变量文件作为默认主题变量文件,被其他.scss通过 @import 时,必需 !default + * 暗雅(默认) + * 此scss变量文件作为multipleScopeVars去编译时,会自动移除!default以达到变量提升 + * 同时此scss变量文件作为默认主题变量文件,被其他.scss通过 @import 时,必需 !default */ -// 暗雅(默认) - -// 菜单选中后字体样式 +/* 菜单选中后字体样式 */ $subMenuActiveText: #fff !default; -//菜单背景 + +/* 菜单背景 */ $menuBg: #001529 !default; -// 鼠标覆盖到菜单时的背景 + +/* 鼠标覆盖到菜单时的背景 */ $menuHover: #4091f7 !default; -// 子菜单背景 + +/* 子菜单背景 */ $subMenuBg: #0f0303 !default; -// 有无子集的激活菜单背景 + +/* 有无子集的激活菜单背景 */ $subMenuActiveBg: #4091f7 !default; $navTextColor: #fff !default; $menuText: rgba(254, 254, 254, 0.65) !default; -// logo背景颜色 + +/* logo背景颜色 */ $sidebarLogo: #002140 !default; -// 鼠标覆盖到菜单时的字体颜色 + +/* 鼠标覆盖到菜单时的字体颜色 */ $menuTitleHover: #fff !default; $menuActiveBefore: #4091f7 !default; diff --git a/src/layout/theme/dusk-vars.scss b/src/layout/theme/dusk-vars.scss index 6e38b94..bb34fee 100644 --- a/src/layout/theme/dusk-vars.scss +++ b/src/layout/theme/dusk-vars.scss @@ -1,5 +1,4 @@ -// 薄暮 - +/* 薄暮 */ $subMenuActiveText: #fff; $menuBg: #2a0608; $menuHover: #e13c39; diff --git a/src/layout/theme/light-vars.scss b/src/layout/theme/light-vars.scss index 2e07500..f83a084 100644 --- a/src/layout/theme/light-vars.scss +++ b/src/layout/theme/light-vars.scss @@ -1,4 +1,4 @@ -// 明亮 +/* 明亮 */ $subMenuActiveText: #409eff; $menuBg: #fff; $menuHover: #e0ebf6; diff --git a/src/layout/theme/mingQing-vars.scss b/src/layout/theme/mingQing-vars.scss index 5749c90..8b8b0af 100644 --- a/src/layout/theme/mingQing-vars.scss +++ b/src/layout/theme/mingQing-vars.scss @@ -1,5 +1,4 @@ -// 明青 - +/* 明青 */ $subMenuActiveText: #fff; $menuBg: #032121; $menuHover: #59bfc1; diff --git a/src/layout/theme/pink-vars.scss b/src/layout/theme/pink-vars.scss index 30d4a42..6a0403c 100644 --- a/src/layout/theme/pink-vars.scss +++ b/src/layout/theme/pink-vars.scss @@ -1,5 +1,4 @@ -// 粉红 - +/* 粉红 */ $subMenuActiveText: #fff; $menuBg: #28081a; $menuHover: #d84493; diff --git a/src/layout/theme/saucePurple-vars.scss b/src/layout/theme/saucePurple-vars.scss index 6d248a9..9bb55d1 100644 --- a/src/layout/theme/saucePurple-vars.scss +++ b/src/layout/theme/saucePurple-vars.scss @@ -1,5 +1,4 @@ -// 酱紫 - +/* 酱紫 */ $subMenuActiveText: #fff; $menuBg: #130824; $menuHover: #693ac9; diff --git a/src/layout/theme/volcano-vars.scss b/src/layout/theme/volcano-vars.scss index 5974ee6..aea4d33 100644 --- a/src/layout/theme/volcano-vars.scss +++ b/src/layout/theme/volcano-vars.scss @@ -1,5 +1,4 @@ -// 火山 - +/* 火山 */ $subMenuActiveText: #fff; $menuBg: #2b0e05; $menuHover: #e85f33; diff --git a/src/layout/theme/yellow-vars.scss b/src/layout/theme/yellow-vars.scss index 1410057..a0fe225 100644 --- a/src/layout/theme/yellow-vars.scss +++ b/src/layout/theme/yellow-vars.scss @@ -1,5 +1,4 @@ -// 黄色 - +/* 橘黄 */ $subMenuActiveText: #d25f00; $menuBg: #2b2503; $menuHover: #f6da4d; diff --git a/src/layout/types.ts b/src/layout/types.ts index 82ac814..1825d61 100644 --- a/src/layout/types.ts +++ b/src/layout/types.ts @@ -73,3 +73,9 @@ export type themeColorsType = { rgb: string; themeColor: string; }; + +export interface scrollbarDomType extends HTMLElement { + wrap?: { + offsetWidth: number; + }; +} diff --git a/src/plugins/fontawesome/index.ts b/src/plugins/fontawesome/index.ts index 7361bc2..562534e 100644 --- a/src/plugins/fontawesome/index.ts +++ b/src/plugins/fontawesome/index.ts @@ -8,6 +8,8 @@ import "font-awesome/css/font-awesome.css"; import { library } from "@fortawesome/fontawesome-svg-core"; import { faUserSecret } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; +// github.com/Remix-Design/RemixIcon/blob/master/README_CN.md#%E5%AE%89%E8%A3%85%E5%BC%95%E5%85%A5 +import "remixicon/fonts/remixicon.css"; export function useFontawesome(app: App) { library.add(faUserSecret); diff --git a/src/style/element-plus.scss b/src/style/element-plus.scss index 308d9b6..0b27889 100644 --- a/src/style/element-plus.scss +++ b/src/style/element-plus.scss @@ -1,5 +1,3 @@ -// cover some element-plus styles - .el-breadcrumb__inner, .el-breadcrumb__inner a { font-weight: 400 !important; @@ -15,7 +13,6 @@ display: none; } -// refine element ui upload .upload-container { .el-upload { width: 100%; @@ -27,17 +24,14 @@ } } -// dropdown .el-dropdown-menu { padding: 2px 0 2px 0 !important; } -// to fix el-date-picker css style .el-range-separator { box-sizing: content-box; } -// el-tooltip的权重 .is-dark { z-index: 99999 !important; } diff --git a/src/style/index.scss b/src/style/index.scss index 2543070..1eeeb9e 100644 --- a/src/style/index.scss +++ b/src/style/index.scss @@ -70,7 +70,7 @@ ul { display: none !important; } -// 灰色模式 +/* 灰色模式 */ .html-grey { filter: grayscale(100%); -webkit-filter: grayscale(100%); @@ -79,7 +79,7 @@ ul { -o-filter: grayscale(100%); } -// 色弱模式 +/* 色弱模式 */ .html-weakness { filter: invert(80%); -webkit-filter: invert(80%); diff --git a/src/style/sidebar.scss b/src/style/sidebar.scss index b82d9d7..d6f85a5 100644 --- a/src/style/sidebar.scss +++ b/src/style/sidebar.scss @@ -1,8 +1,7 @@ @import "../layout/theme/default-vars.scss"; @mixin merge-style( - // vertical模式下主体内容距离网页文档左侧的距离 - $sideBarWidth + /* vertical模式下主体内容距离网页文档左侧的距离 */ $sideBarWidth ) { $menuActiveText: #7a80b4; @@ -126,7 +125,6 @@ } } - // menu hover .submenu-title-noDropdown, .el-sub-menu__title { &:hover { @@ -155,12 +153,12 @@ background-color: $subMenuBg !important; } - // 无子集的激活菜单背景 + /* 无子集的激活菜单背景 */ .is-active.submenu-title-noDropdown.outer-most { background: $subMenuActiveBg; } - // 有子集的激活菜单背景 + /* 有子集的激活菜单背景 */ .is-active.nest-menu { background: $subMenuActiveBg !important; } @@ -319,7 +317,7 @@ } } - // vertical菜单折叠 + /* vertical菜单折叠 */ .el-menu--vertical { .el-menu--popup { background-color: $subMenuBg !important; @@ -355,7 +353,7 @@ } } - // 子菜单中还有子菜单 + /* 子菜单中还有子菜单 */ .el-menu .el-sub-menu__title { font-size: 12px; min-width: $sideBarWidth !important; @@ -396,7 +394,7 @@ } } - // horizontal菜单 + /* horizontal菜单 */ .el-menu--horizontal { & > .el-sub-menu .el-sub-menu__icon-arrow { position: static !important; @@ -425,13 +423,13 @@ } } - // 无子菜单时激活border-bottom + /* 无子菜单时激活border-bottom */ .router-link-exact-active > .submenu-title-noDropdown { height: 60px; border-bottom: 2px solid var(--el-menu-active-color); } - // 子菜单中还有子菜单 + /* 子菜单中还有子菜单 */ .el-menu .el-sub-menu__title { font-size: 12px; min-width: $sideBarWidth !important; @@ -464,7 +462,7 @@ } } - // 有子集的激活菜单背景 + /* 有子集的激活菜单背景 */ .is-active.nest-menu { background: $subMenuActiveBg !important; } @@ -484,7 +482,7 @@ min-width: $sideBarWidth !important; } - // 有子菜单 + /* 有子菜单 */ .el-menu--collapse .is-active.outer-most.el-sub-menu > .el-sub-menu__title::before { @@ -502,7 +500,7 @@ transform: translateY(0); } - // 无子菜单 + /* 无子菜单 */ .el-menu--collapse .is-active.submenu-title-noDropdown.outer-most::before { position: absolute; top: 0; @@ -530,7 +528,7 @@ top: 50%; } - // 手机端 + /* 手机端 */ .mobile { .fixed-header { width: 100% !important; @@ -604,7 +602,7 @@ body[layout="vertical"] { } } - // 菜单折叠 + /* 菜单折叠 */ .el-menu--collapse { margin-left: -5px; diff --git a/src/style/transition.scss b/src/style/transition.scss index b529f82..017c1d9 100644 --- a/src/style/transition.scss +++ b/src/style/transition.scss @@ -1,5 +1,3 @@ -// global transition css - /* fade */ .fade-enter-active, .fade-leave-active {