init
This commit is contained in:
403
src/component/menu/index.less
Normal file
403
src/component/menu/index.less
Normal file
@@ -0,0 +1,403 @@
|
||||
@import "../dropdown/index.less";
|
||||
@import "../popper/index.less";
|
||||
|
||||
.layui-nav .layui-show.layui-anim-upbit .layui-show.layui-anim-upbit {
|
||||
top: 0px;
|
||||
left: calc(100% + 5px);
|
||||
}
|
||||
|
||||
.layui-nav .layui-show.layui-anim-upbit .left-nav.layui-show.layui-anim-upbit,
|
||||
.layui-nav .layui-show.layui-anim-upbit .left-nav .layui-show.layui-anim-upbit {
|
||||
top: 0px;
|
||||
left: calc(-100% - 20px);
|
||||
}
|
||||
|
||||
.layui-nav .layui-show.layui-anim-upbit .layui-nav-item {
|
||||
height: 40px;
|
||||
display: block;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.layui-nav .layui-show.layui-anim-upbit .layui-nav-item.layui-this {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.layui-nav .layui-show.layui-anim-upbit .layui-nav-item.layui-this:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layui-nav {
|
||||
position: relative;
|
||||
padding: 0 20px;
|
||||
background-color: #393d49;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.layui-nav * {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item > a {
|
||||
display: block;
|
||||
padding: 0 30px;
|
||||
* {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-item.layui-this > a {
|
||||
* {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav .layui-this:after,
|
||||
.layui-nav-bar {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 3px;
|
||||
background-color: var(--global-checked-color);
|
||||
transition: all 0.2s;
|
||||
-webkit-transition: all 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.layui-nav-bar {
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.layui-nav[lay-bar="disabled"] .layui-nav-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layui-nav .layui-this:after {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.layui-nav-img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-right: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-more {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 8px;
|
||||
left: auto !important;
|
||||
margin-top: 0;
|
||||
font-size: 12.5px !important;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
-webkit-transition: all 0.2s;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-mored,
|
||||
.layui-nav-itemed > a .layui-nav-more {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.layui-nav-child {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 65px;
|
||||
min-width: 100%;
|
||||
line-height: 36px;
|
||||
padding: 5px 0;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
|
||||
border: 1px solid #eee;
|
||||
background-color: #fff;
|
||||
z-index: 100;
|
||||
border-radius: 2px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a {
|
||||
color: #666;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.layui-nav .layui-nav-child a:hover {
|
||||
background-color: #f6f6f6;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.layui-nav-child dd {
|
||||
margin: 1px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layui-nav-child dd.layui-this {
|
||||
background-color: #f6f6f6;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.layui-nav-child dd.layui-this:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layui-nav-child-r {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.layui-nav-child-c {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layui-nav.layui-nav-collapse {
|
||||
width: 60px;
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
.layui-nav-item > a {
|
||||
text-overflow: clip;
|
||||
}
|
||||
.layui-nav-more {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav-tree {
|
||||
padding: 0;
|
||||
width: 200px;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item {
|
||||
width: 100%;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
line-height: 42px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item > a {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding: 5px 23px 5px 23px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item * {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-more {
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item > a .layui-nav-more {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-item span {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-bar {
|
||||
width: 5px;
|
||||
height: 0;
|
||||
background-color: var(--global-primary-color);
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-this,
|
||||
.layui-nav-tree .layui-nav-child dd.layui-this,
|
||||
.layui-nav-tree .layui-this > a:hover {
|
||||
background-color: var(--global-primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-this:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.layui-nav-itemed > a,
|
||||
.layui-nav-tree .layui-nav-title a,
|
||||
.layui-nav-tree .layui-nav-title a:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child {
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child dd {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child a {
|
||||
color: #fff;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child,
|
||||
.layui-nav-tree .layui-nav-child a:hover {
|
||||
background: 0 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-nav-child {
|
||||
display: block;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.layui-nav-side {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow-x: hidden;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.layui-nav-light {
|
||||
background-color: #ffffff;
|
||||
* {
|
||||
color: grey !important;
|
||||
}
|
||||
.layui-nav-child {
|
||||
background-color: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav-tree {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.layui-nav-tree .layui-this * {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.layui-nav-tree.inverted .layui-this,
|
||||
.layui-nav-tree.inverted .layui-this:hover {
|
||||
border-radius: var(--global-border-radius);
|
||||
margin: 0px 6px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.layui-nav-tree.inverted .layui-this > a,
|
||||
.layui-nav-tree.inverted .layui-this:hover > a {
|
||||
border-radius: var(--global-border-radius);
|
||||
}
|
||||
|
||||
.layui-nav-tree.inverted .layui-this > a {
|
||||
padding: 5px 17px 5px 17px;
|
||||
}
|
||||
|
||||
.layui-nav-tree.not-level {
|
||||
.layui-nav-child {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* popup menu 样式开始 */
|
||||
.layui-sub-menu-popup-content {
|
||||
border: unset;
|
||||
border-radius: 2px;
|
||||
background-color: #393d49;
|
||||
.layui-nav-item {
|
||||
width: 100%;
|
||||
* {
|
||||
color: rgba(255, 255, 255, 0.7)
|
||||
}
|
||||
> a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-overflow: ellipsis;
|
||||
padding: 5px 15px 5px 15px;
|
||||
font-size: 13.5px;
|
||||
min-height: 30px;
|
||||
min-width: 60px;
|
||||
.layui-sub-menu-icon {
|
||||
margin-top: 2px;
|
||||
margin-right: 8px;
|
||||
|
||||
.layui-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.layui-nav-more {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 12.5px !important;
|
||||
margin-top: 0;
|
||||
margin-left: 25px;
|
||||
padding: 0;
|
||||
right: -8px;
|
||||
|
||||
.layui-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.layui-this {
|
||||
background-color: var(--global-primary-color);
|
||||
}
|
||||
|
||||
// fix style
|
||||
.layui-dropdown {
|
||||
display: block;
|
||||
width: -moz-available;
|
||||
width: -webkit-fill-available;
|
||||
width: fill-available;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-sub-menu-popup-theme {
|
||||
&-light {
|
||||
background-color: #FFF;
|
||||
|
||||
.layui-this {
|
||||
* {
|
||||
color: whitesmoke !important;
|
||||
}
|
||||
}
|
||||
|
||||
.layui-nav-item {
|
||||
* {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/* popup menu 样式结束 */
|
||||
5
src/component/menu/index.ts
Normal file
5
src/component/menu/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
112
src/component/menu/index.vue
Normal file
112
src/component/menu/index.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayMenu",
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ComputedRef, provide, Ref, ref, watch } from "vue";
|
||||
import { provideLevel } from "./useLevel";
|
||||
import "./index.less";
|
||||
|
||||
export interface MenuProps {
|
||||
selectedKey?: string;
|
||||
openKeys?: string[];
|
||||
tree?: boolean;
|
||||
theme?: string;
|
||||
inverted?: boolean | string;
|
||||
level?: boolean | string;
|
||||
collapse?: boolean | string;
|
||||
collapseTransition?: boolean | string;
|
||||
indent?: boolean | string; // 菜单栏是否缩进
|
||||
}
|
||||
|
||||
const emit = defineEmits([
|
||||
"update:selectedKey",
|
||||
"update:openKeys",
|
||||
"changeSelectedKey",
|
||||
"changeOpenKeys",
|
||||
]);
|
||||
|
||||
const props = withDefaults(defineProps<MenuProps>(), {
|
||||
selectedKey: "",
|
||||
openKeys: () => [],
|
||||
tree: false,
|
||||
theme: "dark",
|
||||
inverted: false,
|
||||
level: true,
|
||||
collapse: false,
|
||||
collapseTransition: true,
|
||||
indent: false,
|
||||
});
|
||||
|
||||
const isTree: ComputedRef<boolean> = computed(() => props.tree);
|
||||
const isCollapse: ComputedRef<boolean | string> = computed(
|
||||
() => props.collapse
|
||||
);
|
||||
const isCollapseTransition: ComputedRef = computed(
|
||||
() => props.collapseTransition
|
||||
);
|
||||
const oldOpenKeys: Ref = ref<string[]>(props.openKeys);
|
||||
const menuTheme = computed(() => props.theme);
|
||||
|
||||
const openKeys = computed({
|
||||
get() {
|
||||
return props.collapse ? [] : props.openKeys;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:openKeys", val);
|
||||
emit("changeOpenKeys", val);
|
||||
},
|
||||
});
|
||||
|
||||
const selectedKey = computed({
|
||||
get() {
|
||||
return props.selectedKey;
|
||||
},
|
||||
set(val) {
|
||||
emit("update:selectedKey", val);
|
||||
emit("changeSelectedKey", val);
|
||||
},
|
||||
});
|
||||
|
||||
const indent = computed(() => {
|
||||
return props.indent;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.collapse,
|
||||
() => {
|
||||
if (props.collapse) {
|
||||
oldOpenKeys.value = props.openKeys;
|
||||
openKeys.value = [];
|
||||
} else {
|
||||
openKeys.value = oldOpenKeys.value;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
provideLevel(1);
|
||||
provide("isTree", isTree);
|
||||
provide("selectedKey", selectedKey);
|
||||
provide("openKeys", openKeys);
|
||||
provide("isCollapse", isCollapse);
|
||||
provide("isCollapseTransition", isCollapseTransition);
|
||||
provide("menuTheme", menuTheme);
|
||||
provide("indent", indent);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul
|
||||
class="layui-nav"
|
||||
:class="[
|
||||
level ? '' : 'not-level',
|
||||
inverted ? 'inverted' : '',
|
||||
tree ? 'layui-nav-tree' : '',
|
||||
theme === 'dark' ? 'layui-nav-dark' : 'layui-nav-light',
|
||||
collapse ? 'layui-nav-collapse' : '',
|
||||
]"
|
||||
>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
</template>
|
||||
39
src/component/menu/useLevel.ts
Normal file
39
src/component/menu/useLevel.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
computed,
|
||||
inject,
|
||||
provide,
|
||||
reactive,
|
||||
Ref,
|
||||
isRef,
|
||||
ComputedRef,
|
||||
UnwrapNestedRefs,
|
||||
} from "vue";
|
||||
|
||||
export const LevelInjectionKey = Symbol("menuLevelKey");
|
||||
|
||||
export function provideLevel(level: Ref<number> | number) {
|
||||
const computedLevel = computed(() => (isRef(level) ? level.value : level));
|
||||
provide(
|
||||
LevelInjectionKey,
|
||||
reactive({
|
||||
level: computedLevel,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export default function useLevel(props?: { provideNextLevel?: boolean }) {
|
||||
const { provideNextLevel } = props || {};
|
||||
const levelContext = inject(LevelInjectionKey) as UnwrapNestedRefs<{
|
||||
level: ComputedRef<number>;
|
||||
}>;
|
||||
const level = computed(() => levelContext.level || 1);
|
||||
|
||||
if (provideNextLevel) {
|
||||
const nextLevel = computed(() => level.value + 1);
|
||||
provideLevel(nextLevel);
|
||||
}
|
||||
|
||||
return {
|
||||
level,
|
||||
};
|
||||
}
|
||||
18
src/component/menu/utils.ts
Normal file
18
src/component/menu/utils.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
// 处理菜单栏缩进
|
||||
export function indentHandle(obj: {
|
||||
indent: boolean | string;
|
||||
level: number;
|
||||
basePadding?: number;
|
||||
isTree?: boolean;
|
||||
}) {
|
||||
const { indent, level, basePadding = 0, isTree } = obj;
|
||||
const least: number = level - 1; // 第一层不缩进
|
||||
if (isTree && indent && least > 0) {
|
||||
const px =
|
||||
typeof indent === "boolean"
|
||||
? `${basePadding + 10 * least}px` // css样式表对<a>设定了23基础边距
|
||||
: indent.replace(/\d+/g, (s) => (basePadding + least * +s).toString());
|
||||
return `padding-left: ${px}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
Reference in New Issue
Block a user