From 6fcb23018290cec01cf7b9cadbbd839e69963812 Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 16:59:05 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat(menu):=20=E8=8F=9C=E5=8D=95=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/menu/__tests__/menu.spec.ts | 101 +++++ packages/devui-vue/devui/menu/index.ts | 21 + .../devui/menu/src/components/menu-item.tsx | 175 ++++++++ .../devui/menu/src/components/sub-menu.tsx | 169 +++++++ .../devui-vue/devui/menu/src/hooks/Layers.ts | 104 +++++ .../devui/menu/src/hooks/addActiveParent.ts | 10 + .../devui/menu/src/hooks/initSelect.ts | 20 + packages/devui-vue/devui/menu/src/menu.scss | 423 ++++++++++++++++++ packages/devui-vue/devui/menu/src/menu.tsx | 48 ++ .../devui/menu/src/styles/clear.scss | 7 + 10 files changed, 1078 insertions(+) create mode 100644 packages/devui-vue/devui/menu/__tests__/menu.spec.ts create mode 100644 packages/devui-vue/devui/menu/index.ts create mode 100644 packages/devui-vue/devui/menu/src/components/menu-item.tsx create mode 100644 packages/devui-vue/devui/menu/src/components/sub-menu.tsx create mode 100644 packages/devui-vue/devui/menu/src/hooks/Layers.ts create mode 100644 packages/devui-vue/devui/menu/src/hooks/addActiveParent.ts create mode 100644 packages/devui-vue/devui/menu/src/hooks/initSelect.ts create mode 100644 packages/devui-vue/devui/menu/src/menu.scss create mode 100644 packages/devui-vue/devui/menu/src/menu.tsx create mode 100644 packages/devui-vue/devui/menu/src/styles/clear.scss diff --git a/packages/devui-vue/devui/menu/__tests__/menu.spec.ts b/packages/devui-vue/devui/menu/__tests__/menu.spec.ts new file mode 100644 index 0000000000..afca3042d9 --- /dev/null +++ b/packages/devui-vue/devui/menu/__tests__/menu.spec.ts @@ -0,0 +1,101 @@ +import { mount, shallowMount } from '@vue/test-utils'; +import { reactive, ref } from 'vue'; +import { Menu,SubMenu,MenuItem } from '../index'; + +const factory_Menu = (value: Record) => shallowMount(Menu, value); + +describe('menu test', () => { + it('menu - defaultMode test', async ()=>{ + // + const menu = factory_Menu({}); + expect(menu.classes().indexOf('vertical')).toBe(1); + }); + it('menu - dynamic - mode', async ()=>{ + const menu = factory_Menu({ + props: { + 'mode': 'horizontal' + } + }); + expect(menu.classes().indexOf('horizontal')).not.toBe(-1); + }); + + // 参数动态测试 - defaultSelectKeys + it('menu - dynamic attr - defaultSelectKeys ', async ()=>{ + // + const wrapper = mount({ + components: { + Menu, + SubMenu, + MenuItem + }, + template: ` + + + Test + + + + `, + setup(){ + const selectKeys = ref(['test']); + const clickHandle = () => { + selectKeys.value.pop(); + }; + return { + selectKeys, + clickHandle + }; + } + }); + expect(wrapper.find('li').classes().indexOf('devui-menu-item-select')).not.toBe(-1); + await wrapper.find('button').trigger('click'); + expect(wrapper.find('li').classes().indexOf('devui-menu-item-select')).toBe(-1); + }); + // 参数动态测试 - openKeys + it('menu - dynamic attr - openKeys', async () => { + // + const wrapper = mount({ + components: {Menu,SubMenu,MenuItem}, + template: ` + + + + SubMenu > Item 1 + + + SubMenu > Item 2 + + + + + SubMenu2 > Item 1 + + + SubMenu2 > Item 2 + + + + + `, + setup(){ + const defaultOpenKey = ref(['1']); + const change = ()=>{ + if (defaultOpenKey.value.length < 2){ + defaultOpenKey.value.push('2'); + } else { + defaultOpenKey.value.pop(); + } + }; + return { + defaultOpenKey, + change + }; + } + }); + console.log(wrapper.findAll('ul')[2].classes()); + await wrapper.find('button').trigger('click'); + console.log(wrapper.findAll('ul')[2].classes()); + await wrapper.find('button').trigger('click'); + console.log(wrapper.findAll('ul')[2].classes()); + }); +}); diff --git a/packages/devui-vue/devui/menu/index.ts b/packages/devui-vue/devui/menu/index.ts new file mode 100644 index 0000000000..c032fa4e89 --- /dev/null +++ b/packages/devui-vue/devui/menu/index.ts @@ -0,0 +1,21 @@ +import type { App } from 'vue'; +import MenuItem from './src/components/menu-item'; +import SubMenu from './src/components/sub-menu'; +import Menu from './src/menu'; + +Menu.install = function(app: App): void { + app.component(Menu.name, Menu); + app.component(MenuItem.name, MenuItem); + app.component(SubMenu.name, SubMenu); +}; + +export { Menu,SubMenu,MenuItem }; + +export default { + title: 'Menu 菜单', + category: '布局', + status: "90%", // TODO: 组件若开发完成则填入"100%",并删除该注释 + install(app: App): void { + app.use(Menu as any); + } +}; diff --git a/packages/devui-vue/devui/menu/src/components/menu-item.tsx b/packages/devui-vue/devui/menu/src/components/menu-item.tsx new file mode 100644 index 0000000000..5946c15ebf --- /dev/null +++ b/packages/devui-vue/devui/menu/src/components/menu-item.tsx @@ -0,0 +1,175 @@ +import { changeKey } from '../hooks/Layers'; +import { defineComponent, + getCurrentInstance, + onMounted, + ref, + Transition, + watch, + inject, + Ref, + reactive, + toRefs, +} from "vue"; +import { MenuItemProps, menuItemProps } from "../types/menu-item-type"; +import { useInitSelect } from '../hooks/initSelect'; +import { addActiveParent } from '../hooks/addActiveParent'; + + +export default defineComponent({ + name: 'DMenuItem', + props: menuItemProps, + setup(props: MenuItemProps, ctx){ + const instance = getCurrentInstance(); + const key = String(instance?.vnode.key); + const mode = inject('mode') as Ref<('vertical' | 'horizontal')>; + const multiple = inject('multiple') as boolean; + const indent = inject('defaultIndent'); + const isCollapsed = inject('isCollapsed') as Ref; + const defaultSelectKey = (inject('defaultSelectKey') as string[]); + const {disabled} = toRefs(props); + const isSelect = ref(useInitSelect(defaultSelectKey, key, multiple, disabled)); + const isLayer1 = ref(true); + const rootMenuEmit = inject('rootMenuEmit') as (eventName: string, ...args: unknown[]) => void; + const classObject: Record = reactive({ + 'devui-menu-item': true, + 'devui-menu-item-isCollapsed': isCollapsed.value, + 'devui-isCollapsed-item': isCollapsed.value, + 'devui-menu-item-select': isSelect.value, + 'devui-menu-item-disabled': disabled.value + }); + const onClick = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + const ele = e.currentTarget as HTMLElement; + if (!props.disabled){ + if (!multiple){ + changeKey(ele,e); + ele.classList.add('devui-menu-item-select'); + } else { + if (ele.classList.contains('devui-menu-item-select')){ + ele.classList.remove('devui-menu-item-select'); + rootMenuEmit('deselect', {type: 'deselect', el: ele, e}); + return; + } else { + ele.classList.add('devui-menu-item-select'); + } + } + rootMenuEmit('select', {type: 'select', el: ele, e}); + } + if (mode.value === 'vertical'){ + const target = (e.currentTarget as HTMLElement); + addActiveParent(target); + } + if (mode.value === 'horizontal') { + const ul = ele.parentElement?.parentElement; + ul?.classList.add('devui-menu-active-parent'); + } + }; + const icons = {ctx.slots.icon?.()}; + const menuItems = ref(null); + // watchEffect(()=>{ + // pushItem({el: menuItems.value as HTMLElement | null}); + // },{flush:'post'}); + watch(disabled, ()=> {classObject['devui-menu-item-select'] = false;}); + watch(defaultSelectKey, (n)=>{ + isSelect.value = useInitSelect(n,key,multiple,disabled); + classObject['devui-menu-item-select'] = isSelect.value; + }); + onMounted(()=>{ + let oldPadding = ''; + const ele = (menuItems.value) as unknown as HTMLElement; + if (mode.value === 'vertical'){ + if (ele.parentElement?.parentElement?.classList.contains('devui-menu')){ + isLayer1.value = true; + if (isLayer1.value){ + ele.style.paddingRight = ``; + ele.style.paddingLeft = `${indent}px`; + } + watch(isCollapsed, (val)=>{ + if (val){ + if (ele.style.padding !== '0'){ + oldPadding = ele.style.padding; + } + setTimeout(() => { + ele.style.padding = '0'; + ele.style.width = ''; + ele.style.textAlign = `center`; + }, 300); + ele.style.display=`block`; + } else { + ele.style.padding = `${oldPadding}`; + ele.style.textAlign = ``; + ele.style.display=`flex`; + } + }); + } else { + isLayer1.value = false; + } + } + }); + return () => { + return ( + mode.value === 'vertical' ? +
+
  • + {ctx.slots.icon !== undefined && + icons + } + { props.href === '' ? + + + {ctx.slots.default?.()} + + + : + + + {ctx.slots.default?.()} + + + } +
  • +
    + : +
  • + {ctx.slots.icon !== undefined && + icons + } + { props.href === '' ? + + + {ctx.slots.default?.()} + + + : + + + {ctx.slots.default?.()} + + + } +
  • + ); + }; + }, +}); diff --git a/packages/devui-vue/devui/menu/src/components/sub-menu.tsx b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx new file mode 100644 index 0000000000..02fa032e02 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx @@ -0,0 +1,169 @@ +import { + ComponentInternalInstance, + defineComponent, + getCurrentInstance, + inject, + onMounted, + Ref, + ref, + watchEffect, + watch, +} from 'vue'; +import { addLayer, pushElement, changeKey,getLayer } from '../hooks/Layers'; +import { SubMenuProps, subMenuProps } from '../types/sub-menu'; +export default defineComponent({ + name: 'DSubMenu', + props: subMenuProps, + setup(props: SubMenuProps, ctx){ + const isShow = ref(true); + const {vnode:{key}} = getCurrentInstance() as ComponentInternalInstance; + const key_ = String(key); + const isOpen = ref(false); + const defaultOpenKeys = (inject('openKeys') as string[]); + const indent = inject('defaultIndent'); + const isCollapsed = inject('isCollapsed') as Ref; + const mode = inject('mode') as Ref; + const parentEmit = inject('rootMenuEmit') as (eventName: 'submenu-change', ...args: any[]) => void; + if (key_ === 'null'){ + console.warn(`[devui][menu]: Key can not be null`); + } else { + if (defaultOpenKeys.includes(key_)){ + isOpen.value = true; + } else { + isOpen.value = false; + } + } + const clickHandle = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + if (mode.value === 'horizontal'){ + const ele = e.currentTarget as HTMLElement; + changeKey(ele, e); + ele.classList.add('devui-menu-item-select'); + } + if (!props.disable && mode.value !== 'horizontal'){ + const target = e.target as HTMLElement; + let cur = e.target as HTMLElement; + if (target.tagName === 'UL'){ + if (target.classList.contains('devui-submenu-open')){ + isOpen.value = !isOpen.value; + } else { + isOpen.value = isOpen.value; + } + } else { + while (cur && cur.tagName !== 'UL'){ + if (cur.tagName === 'LI'){ + break; + } + cur = cur.parentElement as HTMLElement; + } + if (cur.tagName === 'UL'){ + if (cur.classList.contains('devui-submenu-open')){ + isOpen.value = false; + } else { + isOpen.value = true; + } + } + } + parentEmit('submenu-change', {type: 'submenu-change', state: isOpen.value, el: cur}); + } + }; + const subMenu = ref(null); + let title = ref(null); + let oldPadding = ''; + const class_layer = ref(''); + watchEffect(()=>{ + title = title.value as any; + pushElement({el: subMenu.value} as any); + },{'flush':'post'}); + watch(defaultOpenKeys, (n,v)=>{ + if (n.includes(key_)){ + isOpen.value = true; + } else { + isOpen.value = false; + } + }); + onMounted(()=>{ + const el = title as unknown as HTMLElement; + const e = subMenu.value as unknown as HTMLElement; + addLayer(); + class_layer.value = `layer_${Array.from(e.classList).at(-1)?.replace('layer_','')}`; + watch(isCollapsed, (newValue)=>{ + const layer = Number(getLayer(e)); + if (!Number.isNaN(layer)){ + if (layer > 2){ + if (isCollapsed.value){ + isShow.value = false; + } else { + isShow.value = true; + } + } + } + if (newValue){ + if (el.style.padding !== '0'){ + oldPadding = el.style.padding; + } + setTimeout(() => { + el.style.padding = '0'; + el.style.width = ''; + el.style.textAlign = `center`; + }, 300); + el.style.display=`block`; + } else { + el.style.padding = `${oldPadding}`; + el.style.textAlign = ``; + el.style.display=`flex`; + } + }); + }); + return () => { + return ( +
      + { + props.title ? +
      + {ctx.slots?.icon?.()} + + {props.title} + + +
      + : +
      + + {ctx.slots.icon?.()} + +
      + } + {mode.value === 'horizontal' ? +
      + {ctx.slots.default?.()} +
      : + ctx.slots.default?.() + } +
    + ); + }; + } +}); diff --git a/packages/devui-vue/devui/menu/src/hooks/Layers.ts b/packages/devui-vue/devui/menu/src/hooks/Layers.ts new file mode 100644 index 0000000000..0d8f560bde --- /dev/null +++ b/packages/devui-vue/devui/menu/src/hooks/Layers.ts @@ -0,0 +1,104 @@ +import { Ref,ref } from "vue"; +interface clickEvent extends MouseEvent{ + path?: HTMLElement[] | Element[]; +} +const elements: JSX.Element[] = []; +let parents: HTMLElement[] = []; +const defaultIndent: Ref = ref(24); +export function setDefaultIndent(indent: number): void{ + defaultIndent.value = indent; +} +export function pushElement(element: JSX.Element): void{ + elements.push(element); +} +export function addLayer(): void{ + parents = []; + elements.forEach((val)=>{ + parents.push( + ((val.el as HTMLElement).parentElement as HTMLElement)); + }); + // dfs + const stack = [...parents]; + const getLayerFromClass = (className: string) => /layer_(\d*)/gim.exec(className)?.[1]; + while (stack.length){ + const shiftItem = stack.shift() as HTMLElement; + if (shiftItem?.classList.contains('devui-menu')){ + const children = shiftItem.children; + stack.unshift(...Array.from(children) as HTMLElement[]); + continue; + } else { + if (shiftItem.tagName === 'DIV'){ + if (shiftItem.classList.contains('devui-menu-item-vertical-wrapper')){ + const parent = shiftItem.parentElement; + stack.unshift(...Array.from(shiftItem.children) as HTMLElement[]); + if (parent?.classList.contains('devui-menu')){ + shiftItem.classList.add('layer_1'); + } else { + let layer: string|number|undefined = getLayerFromClass((parent?.classList.value || '') as string); + layer = Number(layer); + shiftItem.classList.add(`layer_${layer}`); + } + } else { + const parent = shiftItem.parentElement; + let layer: string|number|undefined = getLayerFromClass((parent?.classList.value || '') as string); + layer = Number(layer); + shiftItem.classList.add(`layer_${layer}`); + shiftItem.style.paddingLeft = `${(layer === 2 ? 1 : layer-1)*defaultIndent.value}px`; + } + } + if (shiftItem.tagName === 'UL'){ + const parent = shiftItem.parentElement; + const children = shiftItem.children; + for (let i=0;i): +boolean{ + const isSelect = ref(false); + if(!isMutiple){ + if (defaultSelectKeys[0] === keys && !disabled.value){ + isSelect.value = true; + } else { + isSelect.value = false; + } + } else{ + if (defaultSelectKeys.includes(keys)){ + isSelect.value = true; + } else { + isSelect.value = false; + } + } + return isSelect.value; +} diff --git a/packages/devui-vue/devui/menu/src/menu.scss b/packages/devui-vue/devui/menu/src/menu.scss new file mode 100644 index 0000000000..886e5872c9 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/menu.scss @@ -0,0 +1,423 @@ +@import '../../styles-var/devui-var.scss'; +@import './styles/clear.scss'; + +$devui-menu-item-margin: 10px; + +.fade-enter-active, +.fade-leave-active { + transition: opacity 300ms ease; +} + +.fade-leave-to { + display: none; +} + +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + +.devui-menu-icon + span { + margin-left: $devui-menu-item-margin; +} + +.devui-menu-item-disabled, +.devui-submenu-disabled { + color: $devui-menu-item-disabled !important; + cursor: not-allowed !important; +} + +.devui-menu-item-disabled:hover, +.devui-submenu-disabled:hover { + color: $devui-menu-item-disabled !important; + cursor: not-allowed !important; +} + +.devui-sub-menu-disabled:hover { + span { + color: $devui-menu-item-disabled !important; + } +} + +.horizontal { + display: flex; + box-sizing: border-box; + line-height: $devui-line-height-base; + background: $devui-menu-bg; + padding: 14px 20px; + + .devui-menu-item { + display: flex; + position: relative; + box-sizing: content-box; + padding: 0 20px !important; + line-height: 24px; + cursor: pointer; + } + + &.devui-menu-item { + position: relative; + box-sizing: content-box; + padding: 0 20px; + cursor: pointer; + } + + .devui-menu-item::after { + content: ''; + display: block; + position: absolute; + left: 20px; + right: 20px; + bottom: 0; + width: auto; + height: 2px; + } + + ::after { + transition: all 200ms $devui-animation-ease-in-out-smooth; + background: transparent; + } + + .devui-menu-item-select, + .devui-menu-active-parent { + span, + a { + color: $devui-menu-item-select; + } + + &::after { + display: block; + position: absolute; + left: 20px; + right: 20px; + bottom: 0; + width: auto; + height: 2px; + content: ''; + opacity: 1; + background: $devui-brand; + } + } + + .devui-menu-item:hover { + & span, + a { + color: $devui-menu-item-select; + } + + &::after { + background: $devui-brand; + } + } + + .devui-submenu { + margin: 0; + padding: 0; + position: relative; + + div.devui-submenu-title { + padding: 0 20px; + + span { + margin: 0; + } + } + + &::after { + content: ''; + display: block; + position: absolute; + left: 20px; + right: 20px; + bottom: 0; + width: auto; + height: 2px; + } + + .devui-menu-item-horizontal-wrapper { + transition: all 0.8s ease-in-out; + position: absolute; + margin-top: 10px; + padding: 0 !important; + max-height: 0; + overflow: hidden; + background: $devui-menu-bg; + opacity: 0; + + .devui-menu-item { + margin-top: 5px; + } + } + + &:hover { + cursor: pointer; + + & span, + a { + color: $devui-menu-item-select; + } + + &::after { + background: $devui-brand; + } + + div.devui-menu-item-horizontal-wrapper { + opacity: 1; + visibility: visible; + max-height: calc(100vh - 100px); + padding: 10px 0 !important; + border-radius: 8px; + + .devui-menu-item { + margin-top: 5px; + } + } + } + } +} + +.vertical { + padding: 0; + transition: width 0.5s ease, padding 0.5s ease; + border-right: $devui-line 1px solid; + background: $devui-area !important; + + li, + ul { + transition: height 800ms ease, max-height 400ms ease; + } + + ::after { + transition: all 300ms ease-in-out; + background: transparent; + } + + .layer_1 { + margin: 0 !important; + } + + .layer_2 { + // 第一级子菜单 + & > div.devui-submenu-title { + margin: 0 !important; + background: $devui-block; + } + } + + li.devui-isCollapsed-item { + padding: 0; + margin: auto; + } + + &.devui-menu-collapsed { + .devui-menu-icon { + margin: auto; + } + + & ul li { + display: none !important; + } + + .devui-submenu { + div.devui-submenu-title { + .devui-menu-icon { + margin: auto; + } + } + } + } + + .devui-menu-item-vertical-wrapper { + padding-left: 0 !important; + } + + .devui-menu-item { + width: 100%; + height: 40px; + flex-grow: 1; + line-height: 40px; + cursor: pointer; + color: $devui-menu-item; + background: $devui-block; + display: flex; + + span:nth-child(2) { + // flex: auto; + text-align: left; + } + } + + div { + display: flex; + flex: auto; + } + + .devui-menu-item::after { + display: block; + position: absolute; + right: 0; + top: 0; + transform: scaleX(0); + content: ''; + opacity: 1; + background: $devui-menu-item-selectBar; + } + + .devui-menu-item-select { + background: $devui-primary-bg !important; + position: relative; + + span, + a { + color: $devui-menu-item-select; + } + + &::after { + display: block; + position: absolute; + right: 0; + top: 0; + height: 100%; + width: 4px; + content: ''; + opacity: 1; + background: var(--devui-brand, #5e7ce0); + transform: scaleX(1); + } + } + + .devui-submenu > div:hover { + span.devui-submenu-title-content { + color: $devui-menu-item-select; + } + } + + .devui-menu-item:hover { + color: $devui-menu-item-select; + } + + li.devui-menu-item, + div.devui-submenu-title { + white-space: nowrap; + overflow: hidden; + + span:nth-child(2) { + overflow: hidden; + text-overflow: ellipsis; + + span { + overflow: hidden; + text-overflow: ellipsis; + } + } + } + + .devui-submenu-open { + & > div { + color: $devui-menu-item-select !important; + } + + height: auto; + + li, + ul { + opacity: 1; + visibility: visible; + } + + ul { + max-height: 100px; + overflow: hidden; + } + } + + .devui-submenu-close { + & > div { + color: $devui-menu-item; + } + + li { + height: 0; + opacity: 0; + visibility: hidden; + overflow-y: hidden; + } + + ul { + max-height: 0; + overflow: hidden; + } + } + + .devui-menu-item-isCollapsed { + width: fit-content; + + .devui-menu-icon { + margin: auto; + } + } + + // sub menu + ul.devui-submenu { + margin: 0; + padding: 0; + + div.devui-submenu-title { + display: flex; + cursor: pointer; + width: 100%; + height: 40px; + margin: 4px 0; + line-height: 40px; + padding-left: 18px; + align-items: center; + color: $devui-menu-item; + + &:nth-child(1) { + font-size: $devui-font-size-lg; + } + + span.devui-submenu-title-content { + font-size: $devui-font-size-lg; + flex: auto; + } + + span.devui-menu-icon { + text-align: center; + } + } + + .devui-menu-item { + display: flex; + + & > span { + flex: auto; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + transition: all 0.5s ease; + color: $devui-menu-item-sub; + } + } + + .devui-menu-item:hover { + & > span { + color: $devui-menu-item-select; + } + } + + .devui-menu-item-select { + * { + color: $devui-menu-item-select !important; + } + } + } + + ul li ~ ul > div { + margin-top: 0 !important; + } + + ul li { + background: $devui-area !important; + } +} diff --git a/packages/devui-vue/devui/menu/src/menu.tsx b/packages/devui-vue/devui/menu/src/menu.tsx new file mode 100644 index 0000000000..7bbb74f701 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/menu.tsx @@ -0,0 +1,48 @@ +import { + defineComponent, + provide, + ref, + computed, +} from 'vue'; +import { menuProps, MenuProps } from './types/menu-types'; +import './menu.scss'; +import {setDefaultIndent} from './hooks/Layers'; + +export default defineComponent({ + name: 'DMenu', + props: menuProps, + emits: ['select','dselect', 'submenu-change'], + setup(props: MenuProps, ctx) { + const isCollapsed = computed(()=>props.collapsed); + const mode = computed(()=>props['mode']); + provide('isCollapsed',isCollapsed); + provide('defaultIndent', props['indentSize']); + provide('multiple', props['multiple']); + provide('openKeys', props.openKeys); + provide('defaultSelectKey',props.defaultSelectKeys); + provide('mode', mode); + provide('collapsedIndent', ref(props['collapsedIndent'])); + provide('rootMenuEmit', ctx.emit); + setDefaultIndent(props['indentSize']); + return () => { + return ( +
      + {ctx.slots.default?.()} +
    + ); + }; + } +}); diff --git a/packages/devui-vue/devui/menu/src/styles/clear.scss b/packages/devui-vue/devui/menu/src/styles/clear.scss new file mode 100644 index 0000000000..1e9952055c --- /dev/null +++ b/packages/devui-vue/devui/menu/src/styles/clear.scss @@ -0,0 +1,7 @@ +a { + text-decoration: none; +} + +ul li { + list-style: none !important; +} From 9eaaf0c635db65d8d4f26a64a8ccd75bead98d8e Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 17:05:14 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(menu):=20menu=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devui-theme/src/theme/theme-data.ts | 14 +- .../devui-vue/devui/style/theme/_color.scss | 16 +- .../devui-vue/docs/components/menu/index.md | 266 ++++++++++++++++++ .../docs/en-US/components/menu/index.md | 264 +++++++++++++++++ 4 files changed, 558 insertions(+), 2 deletions(-) create mode 100644 packages/devui-vue/docs/components/menu/index.md create mode 100644 packages/devui-vue/docs/en-US/components/menu/index.md diff --git a/packages/devui-theme/src/theme/theme-data.ts b/packages/devui-theme/src/theme/theme-data.ts index cd82585e08..60782dcf1e 100644 --- a/packages/devui-theme/src/theme/theme-data.ts +++ b/packages/devui-theme/src/theme/theme-data.ts @@ -136,7 +136,13 @@ export const devuiLightTheme: Theme = new Theme({ 'devui-z-index-dropdown': '1052', 'devui-z-index-modal': '1050', 'devui-z-index-drawer': '1040', - 'devui-z-index-framework': '1000' + 'devui-z-index-framework': '1000', + + // Menu + 'devui-menu-item': '#252b3a', + 'devui-menu-item-sub':'#6C6C6C', + 'devui-menu-item-hover': '#0f0f0f', + 'devui-menu-disabled': '#919191' }, isDark: false, }); @@ -281,6 +287,12 @@ export const devuiDarkTheme: Theme = new Theme({ 'devui-primary-bg': '#383D4F', 'devui-default-line': '#5e7ce0', 'devui-default-bg': '#383838', + + // Menu + 'devui-menu-item': '#dcdcdc', + 'devui-menu-item-sub':'#c6c6c6', + 'devui-menu-item-hover': '#fff', + 'devui-menu-disabled': '#919191' }, extends: 'devui-light-theme', isDark: true, diff --git a/packages/devui-vue/devui/style/theme/_color.scss b/packages/devui-vue/devui/style/theme/_color.scss index 4db1ea0207..00a8c60894 100755 --- a/packages/devui-vue/devui/style/theme/_color.scss +++ b/packages/devui-vue/devui/style/theme/_color.scss @@ -49,7 +49,6 @@ $devui-icon-fill-active: var(--devui-icon-fill-active, #5e7ce0); // $devui-icon-fill-active-hover: var(--devui-icon-fill-active-hover, #526ecc); // svg图标 高亮填充色悬停反馈色 // 表单 $devui-form-control-line: var(--devui-form-control-line, #adb0b8); // 表单控件边框色,同 边框分割线 -$devui-form-control-bg: var(--devui-form-control-bg, #ffffff); // 表单控件背景色 $devui-form-control-line-hover: var(--devui-form-control-line-hover, #575d6c); // 表单控件边框悬停反馈色 $devui-form-control-line-active: var(--devui-form-control-line-active, #5e7ce0); // 表单控件边框激活色,用于获得焦点 $devui-form-control-line-active-hover: var(--devui-form-control-line-active-hover, #344899); // 表单控件边框激活色,用于获得焦点且悬停 @@ -67,6 +66,7 @@ $devui-disabled-line: var(--devui-disabled-line, #dfe1e6); // disabled边框颜 $devui-disabled-text: var(--devui-disabled-text, #adb0b8); // disabled文字颜色 $devui-primary-disabled: var(--devui-primary-disabled, #beccfa); //主要按钮disabled状态文字颜色 $devui-icon-fill-active-disabled: var(--devui-icon-fill-active-disabled, #beccfa); // svg图标激活状态禁用色 +$devui-icon-fill-active-disabled: var(--devui-icon-fill-active-disabled, #beccfa); // svg图标激活状态禁用色 // 特殊背景色 $devui-label-bg: var(--devui-label-bg, #eef0f5); // 默认标签化选项背景色 $devui-connected-overlay-bg: var(--devui-connected-overlay-bg, #ffffff); // 有连接点的弹出菜单层背景色 @@ -105,3 +105,17 @@ $devui-primary-bg: var(--devui-primary-bg, #f2f5fc); // 主要底色 $devui-default-line: var(--devui-default-line, #5e7ce0);// 默认边框 $devui-default-bg: var(--devui-default-bg, #f3f6f8); // 默认底色 + +// Menu + +// color + +$devui-menu-item: var(--devui-menu-item); +$devui-menu-item-sub: var(--devui-menu-item-sub); +$devui-menu-item-disabled: var(--devui-menu-disabled); +$devui-menu-item-select: var(--devui-menu-item-hover); + +$devui-menu-item-selectBar: var(--devui-primary-hover, #5e7ce0); +$devui-menu-active-parent: var(--devui-icon-fill-active); +$devui-menu-bg: var(--devui-global-bg-normal); +$devui-menu-bg-level: var(--devui-global-bg); diff --git a/packages/devui-vue/docs/components/menu/index.md b/packages/devui-vue/docs/components/menu/index.md new file mode 100644 index 0000000000..3d1c161045 --- /dev/null +++ b/packages/devui-vue/docs/components/menu/index.md @@ -0,0 +1,266 @@ +# Menu 菜单 + +Menu 组件通常用于导航. + +### 何时使用 + +在需要收纳,排列,展示一系列选项时. + +### 基本用法 + +:::demo + +```vue + +``` + +::: + +### 垂直菜单 + +垂直菜单一般在后台中较为广泛使用,子菜单可以嵌入菜单中 + +:::demo + +```vue + +``` + +::: + +### 默认展开 + +通过设置`open-keys`可以修改展开的子菜单项目. + +:::demo + +```vue + +``` + +::: + +### 收缩菜单 + +:::demo + +```vue + + Collapsed + + + + +``` + +::: + +### 取消多选 + +:::demo + +```vue + +``` + +::: + +### 响应式参数 + +例如,`width`, `open-keys`, `default-select-keys`等参数均为响应式 + +:::demo + +```vue + + + +``` + +::: + +## d-menu + +### d-menu 参数 + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| ------------------- | ---------- | ---------- | -------------------------- | ------------------------- | ---------- | +| width | String | '' | 用于控制菜单宽度 | [响应式参数](#响应式参数) | | +| collapsed | Boolean | false | 用于决定菜单是否收起 | [收缩面板](#收缩面板) | | +| collapsed-indent | Number | 24 | 收起时图表距离菜单的距离 | / | | +| indent-size | indentSize | 24 | 未收起时二级菜单的缩进大小 | / | | +| multiple | Boolean | false | 是否可以多选 | / | | +| mode | menuMode | 'vertical' | 菜单类型 | [基本用法](#基本用法) | | +| open-keys | Array | [] | 默认展开的子菜单 key 值 | [默认展](#默认展开) | | +| default-select-keys | Array | [] | 默认选择菜单项 key 值 | / | | + +### d-menu 事件 + +| 事件 | 类型 | 说明 | 跳转 Demo | +| -------------- | -------------------------------------------------------------------------- | ---------------------------------------------------- | --------- | +| select | ```(e: {type:'select', el: HTMLElement})=>void``` | 选中菜单项时触发该事件,被禁用的选项不会被触发 | | +| dselect | ```(e: {type: 'dselect', el: HTMLElement})=>void``` | 取消选中时触发该事件,如果菜单不是多选菜单不会被触发 | | +| submenu-change | ```(e: {type: 'submenu-change': el: HTMLElement: state: boolean})=>void``` | 子菜单状态被更改时会触发 | + +## d-menu-item + + +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :----: | :----: | :----: | :----: | :---------: | ---------- | +|disable|boolean|false|是否禁用||| +|key|string|''|菜单项的key值,需唯一||| +|href|string|''|单击菜单项后跳转的页面|[基本用法](#基本用法)| + +## d-sub-menu +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | 全局配置项 | +| :----: | :----: | :----: | :----: | :---------: | ---------- | +|title|String|''|子菜单标题||| +|disable|boolean|false|是否禁用子菜单||| + +## 接口及其定义 + +``` typescript +export type menuMode = 'vertical' | 'horizontal'; +``` diff --git a/packages/devui-vue/docs/en-US/components/menu/index.md b/packages/devui-vue/docs/en-US/components/menu/index.md new file mode 100644 index 0000000000..ca9ef03f60 --- /dev/null +++ b/packages/devui-vue/docs/en-US/components/menu/index.md @@ -0,0 +1,264 @@ +# Menu + +Menu component is usually used for navigation + +### When to used. + +When it comes to packing, arranging, and displaying a range of options. + +### Basic Used + +:::demo + +```vue + +``` + +::: + +### vertical Menu + +vertical menu usually used in back-end. sub-menu can Embed in a menu + +:::demo + +```vue + +``` + +::: + +### default open + +Setting`open-keys`can change sub menu item opan state + +:::demo + +```vue + +``` + +::: + +### collapse menu + +To change `collapsed` can change menu collapsed status. + +:::demo + +```vue + + Collapsed + + + + +``` + +::: + +### cancel multi-selection + +:::demo + +```vue + +``` + +::: + +### dynamic argument + +For example, parameters such as 'width', 'open-keys', 'default-select-keys' can be modified dynamically + +:::demo + +```vue + + + +``` + +::: + +## d-menu + +### d-menu 参数 + +| argument | type | default value | introduce| Demo| global config | +| --- | --- | --- | --- | --- | --- | +| width | String | '' | controller menu width | [dynamic argument](#dynamic argument) | | +| collapsed | Boolean | false | controller menu collapsed status | [collapse menu](#collapse menu) | | +| collapsed-indent | Number | 24 | If menu is collapse icon sistance from the menu | / | | +| indent-size | indentSize | 24 | Not collapse sub menu indent size | / | | +| multiple | Boolean | false | can multiple if is true | / | | +| mode | menuMode | 'vertical' | menu types | [Basic Used](#Basic Used) | | +| open-keys | Array | [] | default open sub menu's key | [default open](#default open) | | +| default-select-keys | Array | [] | default select menu item's key | / | | + +### d-menu 事件 + +| event| type|introduce| Demo | +| :---: | :---: | :---: | :---: | :---: | :---: | +| select | `(e: {type:'select', el: HTMLElement})=>void` | select menu item will emit this event. if is disabled can't emit this event | +| dselect | `(e: {type: 'dselect', el: HTMLElement})=>void` | The event is triggered when unchecked, if the menu is not multi-select the menu is not triggered | | +| submenu-change | `(e: {type: 'submenu-change': el: HTMLElement: state: boolean})=>void` | Triggered when the submenu state is changed | + +## d-menu-item + +| argument | type | default value | introduce| Demo| global config | +| :---: | :---: | :---: | --- | --- | :---: | +| disable | boolean | false | Disabled this menu item. | | | +| key | string | '' | menu item's key. Must is unique | | | +| href | string | '' | click menu item will link to page url. | [基本用法](#基本用法) | + +## d-sub-menu + +| event| type|introduce| Demo | +| :---: | :---: | :---: | :---: | :---: | :---: | +| title | String | '' | sub menu's title | | | +| disable | boolean | false | disabled sub menu | | | + +## Interface & declare + +```typescript +export type menuMode = 'vertical' | 'horizontal'; +``` From 0bc9a67374e2414adf30d63cd4701b91a9d9b6e4 Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 17:09:14 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix(theme):=20=E6=81=A2=E5=A4=8D=E8=AF=AF?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/devui-vue/devui/style/theme/_color.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devui-vue/devui/style/theme/_color.scss b/packages/devui-vue/devui/style/theme/_color.scss index 00a8c60894..3b5b0cc096 100755 --- a/packages/devui-vue/devui/style/theme/_color.scss +++ b/packages/devui-vue/devui/style/theme/_color.scss @@ -49,6 +49,7 @@ $devui-icon-fill-active: var(--devui-icon-fill-active, #5e7ce0); // $devui-icon-fill-active-hover: var(--devui-icon-fill-active-hover, #526ecc); // svg图标 高亮填充色悬停反馈色 // 表单 $devui-form-control-line: var(--devui-form-control-line, #adb0b8); // 表单控件边框色,同 边框分割线 +$devui-form-control-bg: var(--devui-form-control-bg, #ffffff); // 表单控件背景色 $devui-form-control-line-hover: var(--devui-form-control-line-hover, #575d6c); // 表单控件边框悬停反馈色 $devui-form-control-line-active: var(--devui-form-control-line-active, #5e7ce0); // 表单控件边框激活色,用于获得焦点 $devui-form-control-line-active-hover: var(--devui-form-control-line-active-hover, #344899); // 表单控件边框激活色,用于获得焦点且悬停 @@ -66,7 +67,6 @@ $devui-disabled-line: var(--devui-disabled-line, #dfe1e6); // disabled边框颜 $devui-disabled-text: var(--devui-disabled-text, #adb0b8); // disabled文字颜色 $devui-primary-disabled: var(--devui-primary-disabled, #beccfa); //主要按钮disabled状态文字颜色 $devui-icon-fill-active-disabled: var(--devui-icon-fill-active-disabled, #beccfa); // svg图标激活状态禁用色 -$devui-icon-fill-active-disabled: var(--devui-icon-fill-active-disabled, #beccfa); // svg图标激活状态禁用色 // 特殊背景色 $devui-label-bg: var(--devui-label-bg, #eef0f5); // 默认标签化选项背景色 $devui-connected-overlay-bg: var(--devui-connected-overlay-bg, #ffffff); // 有连接点的弹出菜单层背景色 From 91f9724e03d7040998ae0f1e5ff616475e37f24f Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 21:23:26 +0800 Subject: [PATCH 4/6] fix(menu): pr#516 --- packages/devui-vue/devui/menu/index.ts | 10 +++------- .../devui-vue/devui/menu/src/components/menu-item.tsx | 8 ++++---- .../devui-vue/devui/menu/src/components/sub-menu.tsx | 4 ++-- .../devui/menu/src/{hooks => composables}/Layers.ts | 0 .../menu/src/{hooks => composables}/addActiveParent.ts | 0 .../menu/src/{hooks => composables}/initSelect.ts | 0 packages/devui-vue/devui/menu/src/menu.scss | 4 ++-- packages/devui-vue/devui/menu/src/menu.tsx | 4 ++-- packages/devui-vue/devui/menu/src/styles/clear.scss | 4 ---- packages/devui-vue/devui/style/core/_reset.scss | 5 +++++ packages/devui-vue/docs/components/menu/index.md | 2 +- 11 files changed, 19 insertions(+), 22 deletions(-) rename packages/devui-vue/devui/menu/src/{hooks => composables}/Layers.ts (100%) rename packages/devui-vue/devui/menu/src/{hooks => composables}/addActiveParent.ts (100%) rename packages/devui-vue/devui/menu/src/{hooks => composables}/initSelect.ts (100%) diff --git a/packages/devui-vue/devui/menu/index.ts b/packages/devui-vue/devui/menu/index.ts index c032fa4e89..6be639dbe3 100644 --- a/packages/devui-vue/devui/menu/index.ts +++ b/packages/devui-vue/devui/menu/index.ts @@ -3,12 +3,6 @@ import MenuItem from './src/components/menu-item'; import SubMenu from './src/components/sub-menu'; import Menu from './src/menu'; -Menu.install = function(app: App): void { - app.component(Menu.name, Menu); - app.component(MenuItem.name, MenuItem); - app.component(SubMenu.name, SubMenu); -}; - export { Menu,SubMenu,MenuItem }; export default { @@ -16,6 +10,8 @@ export default { category: '布局', status: "90%", // TODO: 组件若开发完成则填入"100%",并删除该注释 install(app: App): void { - app.use(Menu as any); + app.component(Menu.name, Menu); + app.component(MenuItem.name, MenuItem); + app.component(SubMenu.name, SubMenu); } }; diff --git a/packages/devui-vue/devui/menu/src/components/menu-item.tsx b/packages/devui-vue/devui/menu/src/components/menu-item.tsx index 5946c15ebf..f3700cd20d 100644 --- a/packages/devui-vue/devui/menu/src/components/menu-item.tsx +++ b/packages/devui-vue/devui/menu/src/components/menu-item.tsx @@ -1,4 +1,4 @@ -import { changeKey } from '../hooks/Layers'; +import { changeKey } from '../composables/Layers'; import { defineComponent, getCurrentInstance, onMounted, @@ -10,9 +10,9 @@ import { defineComponent, reactive, toRefs, } from "vue"; -import { MenuItemProps, menuItemProps } from "../types/menu-item-type"; -import { useInitSelect } from '../hooks/initSelect'; -import { addActiveParent } from '../hooks/addActiveParent'; +import { MenuItemProps, menuItemProps } from "../types/menu-item-types"; +import { useInitSelect } from '../composables/initSelect'; +import { addActiveParent } from '../composables/addActiveParent'; export default defineComponent({ diff --git a/packages/devui-vue/devui/menu/src/components/sub-menu.tsx b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx index 02fa032e02..a9ca18d54a 100644 --- a/packages/devui-vue/devui/menu/src/components/sub-menu.tsx +++ b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx @@ -9,8 +9,8 @@ import { watchEffect, watch, } from 'vue'; -import { addLayer, pushElement, changeKey,getLayer } from '../hooks/Layers'; -import { SubMenuProps, subMenuProps } from '../types/sub-menu'; +import { addLayer, pushElement, changeKey,getLayer } from '../composables/Layers'; +import { SubMenuProps, subMenuProps } from '../types/sub-menu-types'; export default defineComponent({ name: 'DSubMenu', props: subMenuProps, diff --git a/packages/devui-vue/devui/menu/src/hooks/Layers.ts b/packages/devui-vue/devui/menu/src/composables/Layers.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/hooks/Layers.ts rename to packages/devui-vue/devui/menu/src/composables/Layers.ts diff --git a/packages/devui-vue/devui/menu/src/hooks/addActiveParent.ts b/packages/devui-vue/devui/menu/src/composables/addActiveParent.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/hooks/addActiveParent.ts rename to packages/devui-vue/devui/menu/src/composables/addActiveParent.ts diff --git a/packages/devui-vue/devui/menu/src/hooks/initSelect.ts b/packages/devui-vue/devui/menu/src/composables/initSelect.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/hooks/initSelect.ts rename to packages/devui-vue/devui/menu/src/composables/initSelect.ts diff --git a/packages/devui-vue/devui/menu/src/menu.scss b/packages/devui-vue/devui/menu/src/menu.scss index 886e5872c9..07f5efc7b6 100644 --- a/packages/devui-vue/devui/menu/src/menu.scss +++ b/packages/devui-vue/devui/menu/src/menu.scss @@ -39,7 +39,7 @@ $devui-menu-item-margin: 10px; } } -.horizontal { +.devui-menu-horizontal { display: flex; box-sizing: border-box; line-height: $devui-line-height-base; @@ -176,7 +176,7 @@ $devui-menu-item-margin: 10px; } } -.vertical { +.devui-menu-vertical { padding: 0; transition: width 0.5s ease, padding 0.5s ease; border-right: $devui-line 1px solid; diff --git a/packages/devui-vue/devui/menu/src/menu.tsx b/packages/devui-vue/devui/menu/src/menu.tsx index 7bbb74f701..c51e27bc93 100644 --- a/packages/devui-vue/devui/menu/src/menu.tsx +++ b/packages/devui-vue/devui/menu/src/menu.tsx @@ -6,7 +6,7 @@ import { } from 'vue'; import { menuProps, MenuProps } from './types/menu-types'; import './menu.scss'; -import {setDefaultIndent} from './hooks/Layers'; +import {setDefaultIndent} from './composables/Layers'; export default defineComponent({ name: 'DMenu', @@ -30,7 +30,7 @@ export default defineComponent({ class={ [ `devui-menu`, - `${props['mode']}`, + `devui-menu-${props['mode']}`, props['collapsed'] ? 'devui-menu-collapsed' : '' ] } diff --git a/packages/devui-vue/devui/menu/src/styles/clear.scss b/packages/devui-vue/devui/menu/src/styles/clear.scss index 1e9952055c..8884c8ef2d 100644 --- a/packages/devui-vue/devui/menu/src/styles/clear.scss +++ b/packages/devui-vue/devui/menu/src/styles/clear.scss @@ -1,7 +1,3 @@ a { text-decoration: none; } - -ul li { - list-style: none !important; -} diff --git a/packages/devui-vue/devui/style/core/_reset.scss b/packages/devui-vue/devui/style/core/_reset.scss index 3b10cdcd8c..7f24257299 100755 --- a/packages/devui-vue/devui/style/core/_reset.scss +++ b/packages/devui-vue/devui/style/core/_reset.scss @@ -39,6 +39,11 @@ ol { padding: 0; } +ul, +li { + list-style: none; +} + p { margin: 0; padding: 0; diff --git a/packages/devui-vue/docs/components/menu/index.md b/packages/devui-vue/docs/components/menu/index.md index 3d1c161045..567fd84034 100644 --- a/packages/devui-vue/docs/components/menu/index.md +++ b/packages/devui-vue/docs/components/menu/index.md @@ -230,7 +230,7 @@ const changeDisabled = () => { | width | String | '' | 用于控制菜单宽度 | [响应式参数](#响应式参数) | | | collapsed | Boolean | false | 用于决定菜单是否收起 | [收缩面板](#收缩面板) | | | collapsed-indent | Number | 24 | 收起时图表距离菜单的距离 | / | | -| indent-size | indentSize | 24 | 未收起时二级菜单的缩进大小 | / | | +| indent-size | Number | 24 | 未收起时二级菜单的缩进大小 | / | | | multiple | Boolean | false | 是否可以多选 | / | | | mode | menuMode | 'vertical' | 菜单类型 | [基本用法](#基本用法) | | | open-keys | Array | [] | 默认展开的子菜单 key 值 | [默认展](#默认展开) | | From 2d7d561174efe88d20ff017b2ee1b4e465e71ff6 Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 21:36:42 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix(menu):=20=E4=BF=AE=E5=A4=8D=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=96=87=E4=BB=B6=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui/menu/src/components/menu-item.tsx | 6 +-- .../devui/menu/src/components/sub-menu.tsx | 2 +- ...ddActiveParent.ts => add-active-parent.ts} | 0 .../{initSelect.ts => init-select.ts} | 0 .../{Layers.ts => layer-composables.ts} | 0 packages/devui-vue/devui/menu/src/menu.tsx | 2 +- .../devui/menu/src/types/menu-item-types.ts | 14 +++++++ .../devui/menu/src/types/menu-types.ts | 40 +++++++++++++++++++ .../devui/menu/src/types/sub-menu-types.ts | 14 +++++++ 9 files changed, 73 insertions(+), 5 deletions(-) rename packages/devui-vue/devui/menu/src/composables/{addActiveParent.ts => add-active-parent.ts} (100%) rename packages/devui-vue/devui/menu/src/composables/{initSelect.ts => init-select.ts} (100%) rename packages/devui-vue/devui/menu/src/composables/{Layers.ts => layer-composables.ts} (100%) create mode 100644 packages/devui-vue/devui/menu/src/types/menu-item-types.ts create mode 100644 packages/devui-vue/devui/menu/src/types/menu-types.ts create mode 100644 packages/devui-vue/devui/menu/src/types/sub-menu-types.ts diff --git a/packages/devui-vue/devui/menu/src/components/menu-item.tsx b/packages/devui-vue/devui/menu/src/components/menu-item.tsx index f3700cd20d..a1a0c94ac4 100644 --- a/packages/devui-vue/devui/menu/src/components/menu-item.tsx +++ b/packages/devui-vue/devui/menu/src/components/menu-item.tsx @@ -1,4 +1,4 @@ -import { changeKey } from '../composables/Layers'; +import { changeKey } from '../composables/layer-composables'; import { defineComponent, getCurrentInstance, onMounted, @@ -11,8 +11,8 @@ import { defineComponent, toRefs, } from "vue"; import { MenuItemProps, menuItemProps } from "../types/menu-item-types"; -import { useInitSelect } from '../composables/initSelect'; -import { addActiveParent } from '../composables/addActiveParent'; +import { useInitSelect } from '../composables/init-select'; +import { addActiveParent } from '../composables/add-active-parent'; export default defineComponent({ diff --git a/packages/devui-vue/devui/menu/src/components/sub-menu.tsx b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx index a9ca18d54a..22801fb8df 100644 --- a/packages/devui-vue/devui/menu/src/components/sub-menu.tsx +++ b/packages/devui-vue/devui/menu/src/components/sub-menu.tsx @@ -9,7 +9,7 @@ import { watchEffect, watch, } from 'vue'; -import { addLayer, pushElement, changeKey,getLayer } from '../composables/Layers'; +import { addLayer, pushElement, changeKey,getLayer } from '../composables/layer-composables'; import { SubMenuProps, subMenuProps } from '../types/sub-menu-types'; export default defineComponent({ name: 'DSubMenu', diff --git a/packages/devui-vue/devui/menu/src/composables/addActiveParent.ts b/packages/devui-vue/devui/menu/src/composables/add-active-parent.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/composables/addActiveParent.ts rename to packages/devui-vue/devui/menu/src/composables/add-active-parent.ts diff --git a/packages/devui-vue/devui/menu/src/composables/initSelect.ts b/packages/devui-vue/devui/menu/src/composables/init-select.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/composables/initSelect.ts rename to packages/devui-vue/devui/menu/src/composables/init-select.ts diff --git a/packages/devui-vue/devui/menu/src/composables/Layers.ts b/packages/devui-vue/devui/menu/src/composables/layer-composables.ts similarity index 100% rename from packages/devui-vue/devui/menu/src/composables/Layers.ts rename to packages/devui-vue/devui/menu/src/composables/layer-composables.ts diff --git a/packages/devui-vue/devui/menu/src/menu.tsx b/packages/devui-vue/devui/menu/src/menu.tsx index c51e27bc93..7117e5a73d 100644 --- a/packages/devui-vue/devui/menu/src/menu.tsx +++ b/packages/devui-vue/devui/menu/src/menu.tsx @@ -6,7 +6,7 @@ import { } from 'vue'; import { menuProps, MenuProps } from './types/menu-types'; import './menu.scss'; -import {setDefaultIndent} from './composables/Layers'; +import {setDefaultIndent} from './composables/layer-composables'; export default defineComponent({ name: 'DMenu', diff --git a/packages/devui-vue/devui/menu/src/types/menu-item-types.ts b/packages/devui-vue/devui/menu/src/types/menu-item-types.ts new file mode 100644 index 0000000000..343e847f24 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/types/menu-item-types.ts @@ -0,0 +1,14 @@ +import { ExtractPropTypes } from "vue"; + +export const menuItemProps = { + disabled: { + type: Boolean, + default: false, + }, + href:{ + type: String, + default: '', + } +} as const; + +export type MenuItemProps = ExtractPropTypes; diff --git a/packages/devui-vue/devui/menu/src/types/menu-types.ts b/packages/devui-vue/devui/menu/src/types/menu-types.ts new file mode 100644 index 0000000000..179a03c5da --- /dev/null +++ b/packages/devui-vue/devui/menu/src/types/menu-types.ts @@ -0,0 +1,40 @@ +import { ExtractPropTypes } from "vue"; + +export type menuMode = 'vertical' | 'horizontal'; + +export const menuProps = { + width:{ + type: String, + default: '', + }, + collapsed: { + type: Boolean, + default: false + }, + collapsedIndent: { + type: Number, + default: 24 + }, + indentSize: { + type: Number, + default: 24 + }, + multiple:{ + type: Boolean, + default: false, + }, + openKeys: { + type: Array, + default: [] + }, + defaultSelectKeys: { + type: Array, + default: [], + }, + mode: { + type: String as () => menuMode, + default: 'vertical' + } +} as const; + +export type MenuProps = ExtractPropTypes; diff --git a/packages/devui-vue/devui/menu/src/types/sub-menu-types.ts b/packages/devui-vue/devui/menu/src/types/sub-menu-types.ts new file mode 100644 index 0000000000..af4593c799 --- /dev/null +++ b/packages/devui-vue/devui/menu/src/types/sub-menu-types.ts @@ -0,0 +1,14 @@ +import { ExtractPropTypes } from "vue"; + +export const subMenuProps = { + title: { + type: String, + default: '' + }, + disable: { + type: Boolean, + default: false + } +} as const; + +export type SubMenuProps = ExtractPropTypes; From db1c9c73e364f1dc2e5ca1929b974c48549f6982 Mon Sep 17 00:00:00 2001 From: GaoNengwWw Date: Mon, 18 Apr 2022 21:45:35 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix(menu):=20=E4=BF=AE=E5=A4=8D=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E9=80=BB=E8=BE=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devui-vue/devui/menu/src/composables/layer-composables.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/devui-vue/devui/menu/src/composables/layer-composables.ts b/packages/devui-vue/devui/menu/src/composables/layer-composables.ts index 0d8f560bde..e1feac8a44 100644 --- a/packages/devui-vue/devui/menu/src/composables/layer-composables.ts +++ b/packages/devui-vue/devui/menu/src/composables/layer-composables.ts @@ -85,6 +85,7 @@ export function changeKey(ele: HTMLElement,event: clickEvent): void{ break; } } + debugger; while (stack.length){ const shiftItem = stack.shift(); if (shiftItem?.tagName === 'UL' || @@ -92,6 +93,9 @@ export function changeKey(ele: HTMLElement,event: clickEvent): void{ stack.push(...Array.from(shiftItem?.children as unknown as Element[])); } if (shiftItem!==ele){ + if (shiftItem?.tagName === 'DIV'){ + stack.unshift(...Array.from(shiftItem?.children)); + } shiftItem?.classList.remove('devui-menu-item-select'); shiftItem?.classList.remove('devui-menu-active-parent'); }