vben
authored
5 years ago
1
<template>
vben
authored
4 years ago
2
<div :class="`${prefixCls}-dom`" :style="getDomStyle"></div>
vben
authored
5 years ago
3
4
<div
v-click-outside="handleClickOutside"
vben
authored
5 years ago
5
:style="getWrapStyle"
vben
authored
5 years ago
6
7
8
9
10
:class="[
prefixCls,
getMenuTheme,
{
open: openMenu,
vben
authored
5 years ago
11
mini: getCollapsed,
vben
authored
5 years ago
12
13
},
]"
vben
authored
5 years ago
14
v-bind="getMenuEvents"
vben
authored
5 years ago
15
16
>
<AppLogo :showTitle="false" :class="`${prefixCls}-logo`" />
vben
authored
5 years ago
17
18
19
<Trigger :class="`${prefixCls}-trigger`" />
vben
authored
5 years ago
20
21
22
23
24
25
26
27
28
<ScrollContainer>
<ul :class="`${prefixCls}-module`">
<li
:class="[
`${prefixCls}-module__item `,
{
[`${prefixCls}-module__item--active`]: item.path === activePath,
},
]"
Vben
authored
4 years ago
29
v-bind="getItemEvents(item)"
vben
authored
5 years ago
30
31
32
v-for="item in menuModules"
:key="item.path"
>
Vben
authored
4 years ago
33
<SimpleMenuTag :item="item" collapseParent dot />
vben
authored
5 years ago
34
<Icon
vben
authored
5 years ago
35
:class="`${prefixCls}-module__icon`"
vben
authored
5 years ago
36
:size="getCollapsed ? 16 : 20"
Vben
authored
4 years ago
37
:icon="item.icon || (item.meta && item.meta.icon)"
vben
authored
5 years ago
38
/>
vben
authored
4 years ago
39
40
41
<p :class="`${prefixCls}-module__name`">
{{ t(item.name) }}
</p>
vben
authored
5 years ago
42
43
44
45
46
47
</li>
</ul>
</ScrollContainer>
<div :class="`${prefixCls}-menu-list`" ref="sideRef" :style="getMenuStyle">
<div
vben
authored
5 years ago
48
v-show="openMenu"
vben
authored
5 years ago
49
50
51
52
53
54
55
56
:class="[
`${prefixCls}-menu-list__title`,
{
show: openMenu,
},
]"
>
<span class="text"> {{ title }}</span>
vben
authored
5 years ago
57
58
<Icon
:size="16"
vben
authored
5 years ago
59
:icon="getMixSideFixed ? 'ri:pushpin-2-fill' : 'ri:pushpin-2-line'"
vben
authored
5 years ago
60
61
62
class="pushpin"
@click="handleFixedMenu"
/>
vben
authored
5 years ago
63
64
</div>
<ScrollContainer :class="`${prefixCls}-menu-list__content`">
vben
authored
5 years ago
65
<SimpleMenu
vben
authored
5 years ago
66
67
:items="chilrenMenus"
:theme="getMenuTheme"
vben
authored
5 years ago
68
mixSider
vben
authored
5 years ago
69
70
71
72
73
74
75
76
77
78
79
80
81
@menuClick="handleMenuClick"
/>
</ScrollContainer>
<div
v-show="getShowDragBar && openMenu"
:class="`${prefixCls}-drag-bar`"
ref="dragBarRef"
></div>
</div>
</div>
</template>
<script lang="ts">
import type { Menu } from '/@/router/types';
vben
authored
5 years ago
82
83
84
85
86
import type { CSSProperties } from 'vue';
import type { RouteLocationNormalized } from 'vue-router';
import { defineComponent, onMounted, ref, computed, unref } from 'vue';
vben
authored
5 years ago
87
import { ScrollContainer } from '/@/components/Container';
Vben
authored
4 years ago
88
import { SimpleMenuTag } from '/@/components/SimpleMenu';
vben
authored
5 years ago
89
import Icon from '/@/components/Icon';
vben
authored
5 years ago
90
import { AppLogo } from '/@/components/Application';
vben
authored
5 years ago
91
92
import Trigger from '../trigger/HeaderTrigger.vue';
vben
authored
5 years ago
93
94
import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
import { useDragLine } from './useLayoutSider';
vben
authored
5 years ago
95
import { useGlobSetting } from '/@/hooks/setting';
vben
authored
5 years ago
96
97
98
import { useDesign } from '/@/hooks/web/useDesign';
import { useI18n } from '/@/hooks/web/useI18n';
import { useGo } from '/@/hooks/web/usePage';
vben
authored
5 years ago
99
vben
authored
5 years ago
100
import { SIDE_BAR_SHOW_TIT_MINI_WIDTH, SIDE_BAR_MINI_WIDTH } from '/@/enums/appEnum';
vben
authored
5 years ago
101
102
import clickOutside from '/@/directives/clickOutside';
vben
authored
5 years ago
103
import { getShallowMenus, getChildrenMenus, getCurrentParentPath } from '/@/router/menus';
Vben
authored
4 years ago
104
import { listenerRouteChange } from '/@/logics/mitt/routeChange';
vben
authored
5 years ago
105
import { SimpleMenu } from '/@/components/SimpleMenu';
vben
authored
5 years ago
106
107
108
109
110
111
export default defineComponent({
name: 'LayoutMixSider',
components: {
ScrollContainer,
AppLogo,
vben
authored
5 years ago
112
SimpleMenu,
vben
authored
5 years ago
113
Icon,
vben
authored
5 years ago
114
Trigger,
Vben
authored
4 years ago
115
SimpleMenuTag,
vben
authored
5 years ago
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
},
directives: {
clickOutside,
},
setup() {
let menuModules = ref<Menu[]>([]);
const activePath = ref('');
const chilrenMenus = ref<Menu[]>([]);
const openMenu = ref(false);
const dragBarRef = ref<ElRef>(null);
const sideRef = ref<ElRef>(null);
const currentRoute = ref<Nullable<RouteLocationNormalized>>(null);
const { prefixCls } = useDesign('layout-mix-sider');
const go = useGo();
const { t } = useI18n();
const {
getMenuWidth,
getCanDrag,
getCloseMixSidebarOnChange,
getMenuTheme,
vben
authored
5 years ago
137
getMixSideTrigger,
vben
authored
5 years ago
138
139
140
141
getRealWidth,
getMixSideFixed,
mixSideHasChildren,
setMenuSetting,
vben
authored
5 years ago
142
143
getIsMixSidebar,
getCollapsed,
vben
authored
5 years ago
144
} = useMenuSetting();
vben
authored
5 years ago
145
vben
authored
5 years ago
146
147
148
149
150
151
152
153
const { title } = useGlobSetting();
useDragLine(sideRef, dragBarRef, true);
const getMenuStyle = computed(
(): CSSProperties => {
return {
width: unref(openMenu) ? `${unref(getMenuWidth)}px` : 0,
vben
authored
5 years ago
154
left: `${unref(getMixSideWidth)}px`,
vben
authored
5 years ago
155
156
157
158
};
}
);
vben
authored
5 years ago
159
const getIsFixed = computed(() => {
vben
authored
4 years ago
160
/* eslint-disable-next-line */
vben
authored
5 years ago
161
162
163
mixSideHasChildren.value = unref(chilrenMenus).length > 0;
const isFixed = unref(getMixSideFixed) && unref(mixSideHasChildren);
if (isFixed) {
vben
authored
4 years ago
164
/* eslint-disable-next-line */
vben
authored
5 years ago
165
166
167
168
169
openMenu.value = true;
}
return isFixed;
});
vben
authored
5 years ago
170
171
172
173
const getMixSideWidth = computed(() => {
return unref(getCollapsed) ? SIDE_BAR_MINI_WIDTH : SIDE_BAR_SHOW_TIT_MINI_WIDTH;
});
vben
authored
5 years ago
174
175
176
const getDomStyle = computed(
(): CSSProperties => {
const fixedWidth = unref(getIsFixed) ? unref(getRealWidth) : 0;
vben
authored
5 years ago
177
178
179
180
181
182
183
184
185
const width = `${unref(getMixSideWidth) + fixedWidth}px`;
return getWrapCommonStyle(width);
}
);
const getWrapStyle = computed(
(): CSSProperties => {
const width = `${unref(getMixSideWidth)}px`;
return getWrapCommonStyle(width);
vben
authored
5 years ago
186
187
188
}
);
vben
authored
5 years ago
189
const getMenuEvents = computed(() => {
vben
authored
5 years ago
190
191
192
193
194
195
196
return !unref(getMixSideFixed)
? {
onMouseleave: () => {
closeMenu();
},
}
: {};
vben
authored
5 years ago
197
198
});
vben
authored
5 years ago
199
200
201
202
203
204
const getShowDragBar = computed(() => unref(getCanDrag));
onMounted(async () => {
menuModules.value = await getShallowMenus();
});
Vben
authored
4 years ago
205
listenerRouteChange((route) => {
vben
authored
5 years ago
206
currentRoute.value = route;
vben
authored
5 years ago
207
setActive(true);
vben
authored
5 years ago
208
if (unref(getCloseMixSidebarOnChange)) {
vben
authored
5 years ago
209
closeMenu();
vben
authored
5 years ago
210
211
212
}
});
vben
authored
5 years ago
213
214
215
216
217
218
219
220
221
222
function getWrapCommonStyle(width: string): CSSProperties {
return {
width,
maxWidth: width,
minWidth: width,
flex: `0 0 ${width}`,
};
}
// Process module menu click
vben
authored
5 years ago
223
async function hanldeModuleClick(path: string, hover = false) {
vben
authored
5 years ago
224
225
226
const children = await getChildrenMenus(path);
if (unref(activePath) === path) {
vben
authored
5 years ago
227
if (!hover) {
vben
authored
5 years ago
228
229
230
231
232
if (!unref(openMenu)) {
openMenu.value = true;
} else {
closeMenu();
}
vben
authored
5 years ago
233
}
vben
authored
5 years ago
234
235
236
237
238
239
240
241
242
243
244
if (!unref(openMenu)) {
setActive();
}
} else {
openMenu.value = true;
activePath.value = path;
}
if (!children || children.length === 0) {
go(path);
chilrenMenus.value = [];
vben
authored
5 years ago
245
closeMenu();
vben
authored
5 years ago
246
247
248
249
250
return;
}
chilrenMenus.value = children;
}
vben
authored
5 years ago
251
// Set the currently active menu and submenu
vben
authored
5 years ago
252
async function setActive(setChildren = false) {
vben
authored
5 years ago
253
254
255
256
257
const path = currentRoute.value?.path;
if (!path) return;
const parentPath = await getCurrentParentPath(path);
activePath.value = parentPath;
// hanldeModuleClick(parentPath);
vben
authored
5 years ago
258
if (unref(getIsMixSidebar)) {
vben
authored
5 years ago
259
260
261
262
263
264
const activeMenu = unref(menuModules).find((item) => item.path === unref(activePath));
const p = activeMenu?.path;
if (p) {
const children = await getChildrenMenus(p);
if (setChildren) {
chilrenMenus.value = children;
vben
authored
5 years ago
265
266
267
268
if (unref(getMixSideFixed)) {
openMenu.value = children.length > 0;
}
vben
authored
5 years ago
269
270
271
272
273
274
}
if (children.length === 0) {
chilrenMenus.value = [];
}
}
}
vben
authored
5 years ago
275
276
277
278
279
280
281
}
function handleMenuClick(path: string) {
go(path);
}
function handleClickOutside() {
vben
authored
5 years ago
282
setActive(true);
vben
authored
5 years ago
283
closeMenu();
vben
authored
5 years ago
284
285
}
vben
authored
5 years ago
286
287
288
289
290
291
292
293
294
295
296
function getItemEvents(item: Menu) {
if (unref(getMixSideTrigger) === 'hover') {
return {
onMouseenter: () => hanldeModuleClick(item.path, true),
};
}
return {
onClick: () => hanldeModuleClick(item.path),
};
}
vben
authored
5 years ago
297
298
299
300
301
302
function handleFixedMenu() {
setMenuSetting({
mixSideFixed: !unref(getIsFixed),
});
}
vben
authored
5 years ago
303
// Close menu
vben
authored
5 years ago
304
305
306
307
308
309
function closeMenu() {
if (!unref(getIsFixed)) {
openMenu.value = false;
}
}
vben
authored
5 years ago
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
return {
t,
prefixCls,
menuModules,
hanldeModuleClick,
activePath,
chilrenMenus,
getShowDragBar,
handleMenuClick,
getMenuStyle,
handleClickOutside,
sideRef,
dragBarRef,
title,
openMenu,
getMenuTheme,
vben
authored
5 years ago
326
327
getItemEvents,
getMenuEvents,
vben
authored
5 years ago
328
329
330
getDomStyle,
handleFixedMenu,
getMixSideFixed,
vben
authored
5 years ago
331
332
getWrapStyle,
getCollapsed,
vben
authored
5 years ago
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
};
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-layout-mix-sider';
@width: 80px;
.@{prefix-cls} {
position: fixed;
top: 0;
left: 0;
z-index: @layout-mix-sider-fixed-z-index;
height: 100%;
overflow: hidden;
background: @sider-dark-bg-color;
vben
authored
5 years ago
348
transition: all 0.2s ease 0s;
vben
authored
5 years ago
349
vben
authored
5 years ago
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
&-dom {
height: 100%;
overflow: hidden;
transition: all 0.2s ease 0s;
}
&-logo {
display: flex;
height: @header-height;
padding-left: 0 !important;
justify-content: center;
img {
width: @logo-width;
height: @logo-width;
}
}
&.light {
.@{prefix-cls}-logo {
border-bottom: 1px solid rgb(238, 238, 238);
}
&.open {
vben
authored
5 years ago
374
> .scrollbar {
vben
authored
5 years ago
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
border-right: 1px solid rgb(238, 238, 238);
}
}
.@{prefix-cls}-module {
&__item {
font-weight: normal;
color: rgba(0, 0, 0, 0.65);
&--active {
color: @primary-color;
background: unset;
}
}
}
vben
authored
5 years ago
390
.@{prefix-cls}-menu-list {
vben
authored
5 years ago
391
392
393
394
&__content {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.1);
}
vben
authored
5 years ago
395
396
397
398
399
400
401
402
403
404
&__title {
.pushpin {
color: rgba(0, 0, 0, 0.35);
&:hover {
color: rgba(0, 0, 0, 0.85);
}
}
}
}
vben
authored
5 years ago
405
}
vben
authored
5 years ago
406
@border-color: @sider-dark-lighten-1-bg-color;
vben
authored
5 years ago
407
408
409
410
&.dark {
&.open {
.@{prefix-cls}-logo {
Vben
authored
4 years ago
411
// border-bottom: 1px solid @border-color;
vben
authored
5 years ago
412
413
}
vben
authored
5 years ago
414
> .scrollbar {
vben
authored
5 years ago
415
border-right: 1px solid @border-color;
vben
authored
5 years ago
416
417
418
419
420
421
422
423
}
}
.@{prefix-cls}-menu-list {
background: @sider-dark-bg-color;
&__title {
color: @white;
border-bottom: none;
vben
authored
5 years ago
424
border-bottom: 1px solid @border-color;
vben
authored
5 years ago
425
426
427
428
}
}
}
vben
authored
5 years ago
429
> .scrollbar {
vben
authored
5 years ago
430
height: calc(100% - @header-height - 38px);
vben
authored
5 years ago
431
432
}
vben
authored
5 years ago
433
434
435
436
437
438
439
440
441
442
&.mini &-module {
&__name {
display: none;
}
&__icon {
margin-bottom: 0;
}
}
vben
authored
5 years ago
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
&-module {
position: relative;
padding-top: 1px;
&__item {
position: relative;
padding: 12px 0;
color: rgba(255, 255, 255, 0.65);
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
color: @white;
}
// &:hover,
&--active {
font-weight: 700;
color: @white;
background: @sider-dark-darken-bg-color;
&::before {
position: absolute;
top: 0;
left: 0;
width: 3px;
height: 100%;
background: @primary-color;
content: '';
}
}
}
&__icon {
margin-bottom: 8px;
font-size: 24px;
vben
authored
5 years ago
479
transition: all 0.2s;
vben
authored
5 years ago
480
481
482
483
484
}
&__name {
margin-bottom: 0;
font-size: 12px;
vben
authored
5 years ago
485
transition: all 0.2s;
vben
authored
5 years ago
486
487
488
}
}
vben
authored
5 years ago
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
&-trigger {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 6px;
padding-left: 12px;
font-size: 18px;
color: rgba(255, 255, 255, 0.65);
cursor: pointer;
background: @sider-dark-bg-color;
}
&.light &-trigger {
color: rgba(0, 0, 0, 0.65);
background: #fff;
}
vben
authored
5 years ago
507
508
509
510
511
512
513
&-menu-list {
position: fixed;
top: 0;
width: 0;
width: 200px;
height: calc(100%);
background: #fff;
vben
authored
5 years ago
514
transition: all 0.2s;
vben
authored
5 years ago
515
516
517
518
&__title {
display: flex;
height: @header-height;
vben
authored
5 years ago
519
// margin-left: -6px;
vben
authored
5 years ago
520
521
522
523
524
525
font-size: 18px;
color: @primary-color;
border-bottom: 1px solid rgb(238, 238, 238);
opacity: 0;
transition: unset;
align-items: center;
vben
authored
5 years ago
526
justify-content: space-between;
vben
authored
5 years ago
527
528
&.show {
vben
authored
5 years ago
529
min-width: 130px;
vben
authored
5 years ago
530
531
532
opacity: 1;
transition: all 0.5s ease;
}
vben
authored
5 years ago
533
534
535
536
537
538
539
540
541
542
.pushpin {
margin-right: 6px;
color: rgba(255, 255, 255, 0.65);
cursor: pointer;
&:hover {
color: #fff;
}
}
vben
authored
5 years ago
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
}
&__content {
height: calc(100% - @header-height) !important;
.scrollbar__wrap {
height: 100%;
overflow-x: hidden;
}
.scrollbar__bar.is-horizontal {
display: none;
}
.ant-menu {
height: 100%;
}
.ant-menu-inline,
.ant-menu-vertical,
.ant-menu-vertical-left {
border-right: 1px solid transparent;
}
}
}
&-drag-bar {
position: absolute;
vben
authored
5 years ago
571
572
573
574
top: 50px;
right: -1px;
width: 1px;
height: calc(100% - 50px);
vben
authored
5 years ago
575
576
577
578
579
580
581
582
cursor: ew-resize;
background: #f8f8f9;
border-top: none;
border-bottom: none;
box-shadow: 0 0 4px 0 rgba(28, 36, 56, 0.15);
}
}
</style>