'admin-21.01.29:适配移动端、部分布局同步优化'

This commit is contained in:
lyt 2021-01-29 18:33:32 +08:00
parent aa0653e7e4
commit 0c732bc543
16 changed files with 183 additions and 59 deletions

View File

@ -9,6 +9,7 @@
"element-plus": "^1.0.2-beta.30",
"mitt": "^2.1.0",
"nprogress": "^0.2.0",
"screenfull": "^5.1.0",
"sortablejs": "^1.13.0",
"vue": "^3.0.5",
"vue-router": "^4.0.2",

View File

@ -33,6 +33,7 @@ export interface RootStateTypes {
isBreadcrumbIcon: boolean,
isTagsviewIcon: boolean,
isCacheTagsView: boolean,
isSortableTagsView: boolean,
isFooter: boolean,
isGrayscale: boolean,
isInvert: boolean,

View File

@ -130,6 +130,7 @@ body,
@extend .flex;
flex-direction: column;
width: 100%;
overflow: hidden;
}
.flex-margin {
margin: auto;

View File

@ -917,3 +917,11 @@
.el-select-dropdown .el-scrollbar__wrap {
overflow-x: scroll !important;
}
/* Drawer 抽屉
------------------------------- */
.el-drawer__body {
width: 100%;
height: 100%;
overflow: auto;
}

View File

@ -0,0 +1,17 @@
@import './index.scss';
/* 页面宽度小于576px
------------------------------- */
@media screen and (max-width: $xs) {
.el-message-box {
width: 80% !important;
}
}
/* 页面宽度小于768px
------------------------------- */
@media screen and (max-width: $sm) {
.layout-navbars-breadcrumb-hide {
display: none;
}
}

View File

@ -1,2 +1,3 @@
@import './login.scss';
@import './error.scss';
@import './layout.scss';

View File

@ -29,6 +29,7 @@ export default {
isBreadcrumbIcon: false,
isTagsviewIcon: false,
isCacheTagsView: false,
isSortableTagsView: true,
isFooter: false,
isGrayscale: false,
isInvert: false,

View File

@ -1,10 +1,18 @@
<template>
<el-aside :class="setCollapseWidth">
<el-aside :class="setCollapseWidth" v-if="clientWidth > 1000">
<Logo v-if="setShowLogo" />
<el-scrollbar class="flex-auto" ref="layoutAsideScrollbarRef">
<Vertical :menuList="menuList" :class="setCollapseWidth" />
</el-scrollbar>
</el-aside>
<el-drawer v-model="getThemeConfig.isCollapse" :with-header="false" direction="ltr" size="220px" v-else>
<el-aside class="w100 h100">
<Logo v-if="setShowLogo" />
<el-scrollbar class="flex-auto" ref="layoutAsideScrollbarRef">
<Vertical :menuList="menuList" />
</el-scrollbar>
</el-aside>
</el-drawer>
</template>
<script lang="ts">
@ -17,10 +25,12 @@ import {
ref,
onBeforeMount,
onUnmounted,
nextTick,
} from "vue";
import { useStore } from "/@/store/index.ts";
import Logo from "/@/views/layout/logo/index.vue";
import Vertical from "/@/views/layout/navMenu/vertical.vue";
import { stat } from "fs";
export default {
name: "layoutAside",
components: { Logo, Vertical },
@ -29,22 +39,12 @@ export default {
const store = useStore();
const state = reactive({
menuList: [],
clientWidth: "",
});
// //
const setFilterRoutes = () => {
if (store.state.themeConfig.layout === "columns") return false;
state.menuList = filterRoutesFun(store.state.routes);
};
//
const filterRoutesFun = (arr: Array<object>) => {
return arr
.filter((item) => !item.meta.isHide)
.map((item) => {
item = Object.assign({}, item);
if (item.children) item.children = filterRoutesFun(item.children);
return item;
//
const getThemeConfig = computed(() => {
return store.state.themeConfig;
});
};
// /
const setCollapseWidth = computed(() => {
let { layout, isCollapse, menuBar } = store.state.themeConfig;
@ -79,6 +79,25 @@ export default {
(isShowLogo && layout === "columns")
);
});
// //
const setFilterRoutes = () => {
if (store.state.themeConfig.layout === "columns") return false;
state.menuList = filterRoutesFun(store.state.routes);
};
//
const filterRoutesFun = (arr: Array<object>) => {
return arr
.filter((item) => !item.meta.isHide)
.map((item) => {
item = Object.assign({}, item);
if (item.children) item.children = filterRoutesFun(item.children);
return item;
});
};
//
const initMenuFixed = (clientWidth: number) => {
state.clientWidth = clientWidth;
};
// themeConfig el-scrollbar
watch(store.state.themeConfig, (val) => {
if (val.isShowLogoChange !== val.isShowLogo) {
@ -88,6 +107,7 @@ export default {
});
//
onBeforeMount(() => {
initMenuFixed(document.body.clientWidth);
setFilterRoutes();
proxy.mittBus.on("setSendColumnsChildren", (res) => {
state.menuList = res.children;
@ -100,16 +120,21 @@ export default {
proxy.mittBus.on("getBreadcrumbIndexSetFilterRoutes", () => {
setFilterRoutes();
});
proxy.mittBus.on("layoutMobileResize", (res) => {
initMenuFixed(res.clientWidth);
});
});
//
onUnmounted(() => {
proxy.mittBus.off("setSendColumnsChildren");
proxy.mittBus.off("setSendClassicChildren");
proxy.mittBus.off("getBreadcrumbIndexSetFilterRoutes");
proxy.mittBus.off("layoutMobileResize");
});
return {
setCollapseWidth,
setShowLogo,
getThemeConfig,
...toRefs(state),
};
},

View File

@ -6,15 +6,9 @@
</template>
<script lang="ts">
import { computed, onBeforeMount, onMounted, onUnmounted } from "vue";
import { computed, onBeforeMount, onUnmounted, getCurrentInstance } from "vue";
import { useStore } from "/@/store/index.ts";
import {
setLocal,
getLocal,
setSession,
getSession,
removeSession,
} from "/@/utils/storage.ts";
import { getLocal } from "/@/utils/storage.ts";
import Defaults from "/@/views/layout/main/defaults.vue";
import Classic from "/@/views/layout/main/classic.vue";
import Transverse from "/@/views/layout/main/transverse.vue";
@ -23,37 +17,32 @@ export default {
name: "layout",
components: { Defaults, Classic, Transverse, Columns },
setup() {
const { proxy } = getCurrentInstance();
const store = useStore();
//
const getThemeConfig = computed(() => {
return store.state.themeConfig;
});
//
// ()
const onLayoutResize = () => {
const clientWidth = document.body.clientWidth;
console.log(clientWidth);
if (clientWidth < 1000) {
if (getLocal("themeConfig").layout === "defaults") return false;
setSession("oldThemeConfig", getLocal("themeConfig"));
const config = getLocal("themeConfig");
config.layout = "defaults";
console.log(config);
setLocal("themeConfig", config);
getThemeConfig.value.isCollapse = false;
proxy.mittBus.emit("layoutMobileResize", {
layout: "defaults",
clientWidth,
});
} else {
if (
getLocal("themeConfig").layout === getSession("oldThemeConfig").layout
)
return false;
setLocal("themeConfig", getSession("oldThemeConfig"));
proxy.mittBus.emit("layoutMobileResize", {
layout: getLocal("oldLayout") ? getLocal("oldLayout") : "defaults",
clientWidth,
});
}
};
//
onBeforeMount(() => {
window.addEventListener("resize", onLayoutResize);
});
//
onMounted(() => {
onLayoutResize();
window.addEventListener("resize", onLayoutResize);
});
//
onUnmounted(() => {

View File

@ -18,7 +18,9 @@ export default {
// logo classic logo
const setShowLogo = computed(() => {
let { isCollapse, layout } = store.state.themeConfig;
return !isCollapse || layout === "classic";
return (
!isCollapse || layout === "classic" || document.body.clientWidth < 1000
);
});
// logo /
const onThemeConfigChange = () => {

View File

@ -2,7 +2,7 @@
<div class="layout-navbars-breadcrumb" v-show="getThemeConfig.isBreadcrumb">
<i class="layout-navbars-breadcrumb-icon" :class="getThemeConfig.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
@click="onThemeConfigChange"></i>
<el-breadcrumb>
<el-breadcrumb class="layout-navbars-breadcrumb-hide">
<transition-group name="breadcrumb" mode="out-in">
<el-breadcrumb-item v-for="(v,k) in breadcrumbList" :key="v.meta.title">
<span v-if="k === breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">

View File

@ -192,6 +192,12 @@
<el-switch v-model="getThemeConfig.isCacheTagsView" @change="setLocalThemeConfig"></el-switch>
</div>
</div>
<div class="layout-breadcrumb-seting-bar-flex mt15">
<div class="layout-breadcrumb-seting-bar-flex-label">开启 TagsView 拖拽 </div>
<div class="layout-breadcrumb-seting-bar-flex-value">
<el-switch v-model="getThemeConfig.isSortableTagsView" @change="onSortableTagsViewChange"></el-switch>
</div>
</div>
<div class="layout-breadcrumb-seting-bar-flex mt15">
<div class="layout-breadcrumb-seting-bar-flex-label">开启 Footer</div>
<div class="layout-breadcrumb-seting-bar-flex-value">
@ -364,6 +370,7 @@ export default defineComponent({
setup() {
const { proxy } = getCurrentInstance();
const store = useStore();
//
const getThemeConfig = computed(() => {
return store.state.themeConfig;
});
@ -479,6 +486,11 @@ export default defineComponent({
}
setLocalThemeConfig();
};
// 4 --> TagsView
const onSortableTagsViewChange = () => {
proxy.mittBus.emit("openOrCloseSortable");
setLocalThemeConfig();
};
// 4 --> /
const onAddFilterChange = (attr: string) => {
if (attr === "grayscale") {
@ -515,6 +527,7 @@ export default defineComponent({
};
// 5
const onSetLayout = (layout: string) => {
setLocal("oldLayout", layout);
if (getThemeConfig.value.layout === layout) return false;
getThemeConfig.value.layout = layout;
getThemeConfig.value.isDrawer = false;
@ -526,6 +539,7 @@ export default defineComponent({
if (getThemeConfig.value.layout === "classic") {
getThemeConfig.value.isShowLogo = true;
getThemeConfig.value.isBreadcrumb = false;
getThemeConfig.value.isCollapse = false;
getThemeConfig.value.isClassicSplitMenu = false;
getThemeConfig.value.menuBar = "#FFFFFF";
getThemeConfig.value.menuBarColor = "#606266";
@ -535,6 +549,7 @@ export default defineComponent({
} else if (getThemeConfig.value.layout === "transverse") {
getThemeConfig.value.isShowLogo = true;
getThemeConfig.value.isBreadcrumb = false;
getThemeConfig.value.isCollapse = false;
getThemeConfig.value.isTagsview = false;
getThemeConfig.value.isClassicSplitMenu = false;
getThemeConfig.value.menuBarColor = "#FFFFFF";
@ -544,6 +559,7 @@ export default defineComponent({
} else if (getThemeConfig.value.layout === "columns") {
getThemeConfig.value.isShowLogo = true;
getThemeConfig.value.isBreadcrumb = true;
getThemeConfig.value.isCollapse = false;
getThemeConfig.value.isTagsview = true;
getThemeConfig.value.isClassicSplitMenu = false;
getThemeConfig.value.menuBar = "#FFFFFF";
@ -554,6 +570,7 @@ export default defineComponent({
} else {
getThemeConfig.value.isShowLogo = false;
getThemeConfig.value.isBreadcrumb = true;
getThemeConfig.value.isCollapse = true;
getThemeConfig.value.isTagsview = true;
getThemeConfig.value.isClassicSplitMenu = false;
getThemeConfig.value.menuBar = "#545c64";
@ -596,9 +613,19 @@ export default defineComponent({
};
onMounted(() => {
nextTick(() => {
//
proxy.mittBus.on("onMenuClick", () => {
onMenuBarHighlightChange();
});
//
proxy.mittBus.on("layoutMobileResize", (res) => {
if (getThemeConfig.value.layout === res.layout) return false;
getThemeConfig.value.layout = res.layout;
getThemeConfig.value.isDrawer = false;
initSetLayoutChange();
onMenuBarHighlightChange();
getThemeConfig.value.isCollapse = false;
});
//
setTimeout(() => {
//
@ -631,7 +658,9 @@ export default defineComponent({
});
});
onUnmounted(() => {
proxy.mittBus.off("onMenuClick", () => {});
//
proxy.mittBus.off("onMenuClick");
proxy.mittBus.off("layoutMobileResize");
});
return {
openDrawer,
@ -652,6 +681,7 @@ export default defineComponent({
setLocalThemeConfig,
onClassicSplitMenuChange,
onIsBreadcrumbChange,
onSortableTagsViewChange,
};
},
});

View File

@ -7,7 +7,8 @@
<i class="icon-skin iconfont" title="布局配置"></i>
</div>
<div class="layout-navbars-breadcrumb-user-icon"><i class="el-icon-bell" title="消息"></i></div>
<div class="layout-navbars-breadcrumb-user-icon mr10"><i class="icon-fullscreen iconfont" title="开全屏"></i></div>
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick"><i class="iconfont"
:title="isScreenfull ? '开全屏' : '关全屏'" :class="!isScreenfull?'icon-fullscreen':'icon-tuichuquanping'"></i></div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link">
<img src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=1813762643,1914315241&fm=26&gp=0.jpg"
@ -28,9 +29,17 @@
</template>
<script lang="ts">
import { ref, getCurrentInstance, computed } from "vue";
import {
ref,
getCurrentInstance,
computed,
reactive,
toRefs,
toRef,
} from "vue";
import { useRouter } from "vue-router";
import { ElMessageBox, ElMessage } from "element-plus";
import screenfull from "screenfull";
import { resetRoute } from "/@/router/index.ts";
import { useStore } from "/@/store/index.ts";
import { clearSession } from "/@/utils/storage.ts";
@ -40,6 +49,9 @@ export default {
const { proxy } = getCurrentInstance();
const router = useRouter();
const store = useStore();
const state = reactive({
isScreenfull: false,
});
//
const setFlexAutoStyle = computed(() => {
if (
@ -49,6 +61,15 @@ export default {
)
return { flex: 1 };
});
//
const onScreenfullClick = () => {
if (!screenfull.isEnabled) {
ElMessage.warning("暂不不支持全屏");
return false;
}
screenfull.toggle();
state.isScreenfull = !state.isScreenfull;
};
// icon
const onLayoutSetingClick = () => {
proxy.mittBus.emit("openSetingsDrawer");
@ -96,6 +117,8 @@ export default {
setFlexAutoStyle,
onLayoutSetingClick,
onHandleCommandClick,
onScreenfullClick,
...toRefs(state),
};
},
};

View File

@ -61,6 +61,7 @@ export default {
},
tagsRefsIndex: 0,
tagsViewList: [],
sortable: "",
});
// tagsView
const setTagsStyle = computed(() => {
@ -202,12 +203,15 @@ export default {
const initSortable = () => {
const el = document.querySelector(".layout-navbars-tagsview-ul");
if (!el) return false;
const sortable = Sortable.create(el, {
if (!getThemeConfig.value.isSortableTagsView)
state.sortable && state.sortable.destroy();
if (getThemeConfig.value.isSortableTagsView) {
state.sortable = Sortable.create(el, {
animation: 300,
dataIdAttr: "data-name",
onEnd: () => {
const sortEndList = [];
sortable.toArray().map((val) => {
state.sortable.toArray().map((val) => {
state.tagsViewList.map((v) => {
if (v.name === val) sortEndList.push({ ...v });
});
@ -215,6 +219,7 @@ export default {
addBrowserSetSession(sortEndList);
},
});
}
};
//
onBeforeMount(() => {
@ -222,11 +227,17 @@ export default {
proxy.mittBus.on("onCurrentContextmenuClick", (data: object) => {
onCurrentContextmenuClick(data);
});
// /
proxy.mittBus.on("openOrCloseSortable", () => {
initSortable();
});
});
//
onUnmounted(() => {
//
proxy.mittBus.off("onCurrentContextmenuClick");
// /
proxy.mittBus.off("openOrCloseSortable");
});
//
onBeforeUpdate(() => {
@ -266,6 +277,9 @@ export default {
.layout-navbars-tagsview {
flex: 1;
background-color: #ffffff;
::v-deep(.el-scrollbar__wrap) {
overflow-x: auto !important;
}
&-ul {
list-style: none;
margin: 0;

View File

@ -1,5 +1,5 @@
<template>
<el-menu router :default-active="defaultActive" background-color="transparent" :collapse="getThemeConfig.isCollapse"
<el-menu router :default-active="defaultActive" background-color="transparent" :collapse="setIsCollapse"
:unique-opened="getThemeConfig.isUniqueOpened" :collapse-transition="false">
<template v-for="val in menuList">
<el-submenu :index="val.path" v-if="val.children && val.children.length > 0" :key="val.path">
@ -27,6 +27,7 @@ import {
computed,
defineComponent,
getCurrentInstance,
onBeforeMount,
} from "vue";
import { useRoute, onBeforeRouteUpdate } from "vue-router";
import { useStore } from "/@/store/index.ts";
@ -57,14 +58,23 @@ export default defineComponent({
const getThemeConfig = computed(() => {
return store.state.themeConfig;
});
// /
const setIsCollapse = computed(() => {
return document.body.clientWidth < 1000
? false
: getThemeConfig.value.isCollapse;
});
//
onBeforeRouteUpdate((to) => {
state.defaultActive = to.path;
proxy.mittBus.emit("onMenuClick");
const clientWidth = document.body.clientWidth;
if (clientWidth < 1000) getThemeConfig.value.isCollapse = false;
});
return {
menuList,
getThemeConfig,
setIsCollapse,
...toRefs(state),
};
},

View File

@ -110,6 +110,7 @@ export default defineComponent({
.login-content-code-img {
width: 100%;
height: 40px;
line-height: 40px;
background-color: #ffffff;
border: 1px solid rgb(220, 223, 230);
color: #333;