diff --git a/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts b/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f842c738ef8fc3f81d2d1d81221799ba39477c55 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/__tests__/dropdown.spec.ts @@ -0,0 +1,8 @@ +import { mount } from '@vue/test-utils'; +import { Dropdown } from '../index'; + +describe('dropdown test', () => { + it('dropdown init render', async () => { + // todo + }) +}) diff --git a/packages/devui-vue/devui/dropdown/index.ts b/packages/devui-vue/devui/dropdown/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3bf24e74ca37403a1eae2eed6a957f4aa85ff86 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/index.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue' + +import Dropdown from './src/dropdown' + +Dropdown.install = function (app: App): void { + app.component(Dropdown.name, Dropdown) +} + +export { Dropdown } + +export default { + title: 'Dropdown 下拉菜单', + category: '导航', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + app.use(Dropdown as any) + } +} diff --git a/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts b/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..38d67100b7cbb1d68560049d486f54682e7195e0 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown-directive.ts @@ -0,0 +1,7 @@ +export const dDropdownDirective = { + +}; + +export const dDropdownMenuDirective = { + +}; diff --git a/packages/devui-vue/devui/dropdown/src/dropdown-types.ts b/packages/devui-vue/devui/dropdown/src/dropdown-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed072b108d800599d72ae479b878976cb3bf5667 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown-types.ts @@ -0,0 +1,45 @@ +import type { PropType, ExtractPropTypes, ComponentPublicInstance } from 'vue' + +export type TriggerType = 'click' | 'hover' | 'manually'; +export type CloseScopeArea = 'all' | 'blank' | 'none'; + + +export const dropdownProps = { + origin: { + type: Object as PropType, + required: true + }, + + isOpen: { + type: Boolean, + default: false + }, + + disabled: { + type: Boolean, + default: false + }, + + trigger: { + type: String as PropType, + default: 'click' + }, + + closeScope: { + type: String as PropType, + default: 'all' + }, + + closeOnMouseLeaveMenu: { + type: Boolean, + default: true + }, + + showAnimation: { + type: Boolean, + default: true + } + +} as const + +export type DropdownProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/dropdown/src/dropdown.scss b/packages/devui-vue/devui/dropdown/src/dropdown.scss new file mode 100644 index 0000000000000000000000000000000000000000..714db353ad2f7cb9973359c7e6ba912c6866645f --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown.scss @@ -0,0 +1,61 @@ +@import '@devui/styles-var/devui-var'; + +.devui-dropdown span { + &.icon-chevron-down, + &.icon-select-arrow { + display: inline-block; + vertical-align: text-top; + } +} + +.devui-dropdown-animation span { + &.icon-chevron-down, + &.icon-select-arrow { + transition: transform $devui-animation-duration-slow $devui-animation-ease-in-out-smooth; + } +} + +.devui-dropdown.open span { + &.icon-chevron-down, + &.icon-select-arrow { + transform: rotate(180deg); + } +} + + + +.devui-dropdown-fade { + @mixin d-dropdown-fade-animation { + animation-name: d-dropdown-fade; + animation-duration: 0.3s; + } + @keyframes d-dropdown-fade { + 0% { + opacity: 0; + transform: scaleY(0.9999) scaleY(0); + } + + 100% { + opacity: 1; + transform: scaleY(0.8) scaleY(4px); + } + } + + &-enter { + opacity: 0; + } + + &-enter-active { + @include d-dropdown-fade-animation; + } + + &-leave { + opacity: 1; + } + + &-leave-active { + @include d-dropdown-fade-animation; + + animation-direction: reverse; + } +} \ No newline at end of file diff --git a/packages/devui-vue/devui/dropdown/src/dropdown.tsx b/packages/devui-vue/devui/dropdown/src/dropdown.tsx new file mode 100644 index 0000000000000000000000000000000000000000..589d8c6359e64abf5b6a559acdcb86ca48fa7594 --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/dropdown.tsx @@ -0,0 +1,66 @@ +import { defineComponent, watch, ref, toRefs, Transition, computed } from 'vue' +import { dropdownProps, DropdownProps } from './dropdown-types' +import { useDropdown } from './use-dropdown'; + +import { FlexibleOverlay } from '../../overlay'; + +import './dropdown.scss' + +export default defineComponent({ + name: 'DDropdown', + props: dropdownProps, + emits: [], + setup(props: DropdownProps, ctx) { + const { + isOpen, + origin, + trigger, + closeScope, + closeOnMouseLeaveMenu, + } = toRefs(props); + + const visible = ref(false); + watch(isOpen, (value) => { + visible.value = value; + }, { immediate: true }); + + const position = { + originX: 'left', + originY: 'bottom', + overlayX: 'left', + overlayY: 'top' + } as const; + + const { dropdownEl } = useDropdown({ + visible, + origin, + trigger, + closeScope, + closeOnMouseLeaveMenu, + }); + + const animatedVisible = computed(() => { + return props.showAnimation ? visible.value : true; + }); + + return () => { + // let vnodes = ctx.slots.default?.() ?? []; + return ( + <> + + +
+ {ctx.slots.default?.()} +
+
+
+ + ) + }; + } +}) diff --git a/packages/devui-vue/devui/dropdown/src/use-dropdown.ts b/packages/devui-vue/devui/dropdown/src/use-dropdown.ts new file mode 100644 index 0000000000000000000000000000000000000000..596a4579311c3265eb8154b0137446fdc986929a --- /dev/null +++ b/packages/devui-vue/devui/dropdown/src/use-dropdown.ts @@ -0,0 +1,120 @@ +import { Ref, ref, watch } from 'vue'; +import { getElement } from '../../shared/util/dom'; +import { CloseScopeArea, TriggerType } from './dropdown-types'; + +function subscribeEvent(dom: Element | Document, type: string, callback: (event: E) => void) { + dom?.addEventListener(type, callback as any); + return () => { + dom?.removeEventListener(type, callback as any); + } +} + +type ReadonlyRef = Readonly>; + +interface UseDropdownProps { + visible: Ref + trigger: ReadonlyRef + origin: ReadonlyRef + closeScope: ReadonlyRef + closeOnMouseLeaveMenu: ReadonlyRef +} + +interface UseDropdownResult { + dropdownEl: Ref +} + +export const useDropdown = ({ + visible, + trigger, + origin, + closeScope, + closeOnMouseLeaveMenu +}: UseDropdownProps): UseDropdownResult => { + const dropdownElRef = ref(); + + const closeByScope = () => { + if (closeScope.value === 'none') { + return; + } + visible.value = false; + } + watch( + [trigger, origin, dropdownElRef], + ([trigger, origin, dropdownEl], ov, onInvalidate) => { + const originEl = getElement(origin); + if (!originEl || !dropdownEl) { + return; + } + const subscriptions = [ + subscribeEvent(dropdownEl, 'click', () => { + if (closeScope.value === 'all') { + visible.value = false; + } + }), + ]; + + if (trigger === 'click') { + // 点击触发 + subscriptions.push( + subscribeEvent(originEl, 'click', () => visible.value = !visible.value), + subscribeEvent(document, 'click', (e) => { + if (!visible.value) { + return; + } + const target = e.target as HTMLElement; + const isContain = originEl.contains(target) || dropdownEl.contains(target); + if (isContain) { + return; + } + closeByScope(); + }), + subscribeEvent(dropdownEl, 'mouseleave', () => { + // 判断鼠标是否已经进入 origin + if (closeOnMouseLeaveMenu.value) { + visible.value = false; + } + }) + ); + } else if (trigger === 'hover') { + // 鼠标悬浮触发 + let overlayEnter = false; + let originEnter = false; + const handleLeave = async (elementType: 'origin' | 'dropdown') => { + // 由于关联元素和 dropdown 元素间有间距, + // 悬浮时在两者之间移动可能会导致多次关闭打开, + // 所以需要给关闭触发节流。 + await new Promise((resolve) => setTimeout(resolve, 50)); + if ((elementType === 'origin' && overlayEnter) || (elementType === 'dropdown' && originEnter)) { + return; + } + closeByScope(); + }; + subscriptions.push( + subscribeEvent(originEl, 'mouseenter', () => { + originEnter = true; + visible.value = true; + }), + subscribeEvent(originEl, 'mouseleave', () => { + originEnter = false; + // 判断鼠标是否已经进入 overlay + if (!closeOnMouseLeaveMenu.value) { + handleLeave('origin'); + } + }), + subscribeEvent(dropdownEl, 'mouseenter', () => { + overlayEnter = true; + visible.value = true; + }), + subscribeEvent(dropdownEl, 'mouseleave', () => { + overlayEnter = false; + // 判断鼠标是否已经进入 origin + handleLeave('dropdown'); + }) + ); + } + onInvalidate(() => subscriptions.forEach(v => v())); + } + ); + + return { dropdownEl: dropdownElRef }; +} diff --git a/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx b/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx index 4a84b1c438ceec8a7745bf597c223ba16d4500a3..c4ccfa03ec89e41c599e1037da30dfdfdbcf17a8 100644 --- a/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx +++ b/packages/devui-vue/devui/overlay/src/fixed-overlay.tsx @@ -1,19 +1,13 @@ import { defineComponent, ref, renderSlot, CSSProperties, PropType } from 'vue'; import { CommonOverlay } from './common-overlay'; -import { overlayProps } from './overlay-types'; +import { fixedOverlayProps, FixedOverlayProps } from './overlay-types'; import { useOverlayLogic } from './utils'; import './overlay.scss'; export const FixedOverlay = defineComponent({ name: 'DFixedOverlay', - props: { - ...overlayProps, - overlayStyle: { - type: Object as PropType, - default: undefined, - }, - }, - setup(props, ctx) { + props: fixedOverlayProps, + setup(props: FixedOverlayProps, ctx) { const { backgroundClass, overlayClass, diff --git a/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx b/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx index 19c55c4f988267c2f0f427941ea9b7cada2ff06f..42556b58eac8d580e2c83d54579947b50d4b8a04 100644 --- a/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx +++ b/packages/devui-vue/devui/overlay/src/flexible-overlay.tsx @@ -1,5 +1,4 @@ import { - ComponentPublicInstance, CSSProperties, defineComponent, getCurrentInstance, @@ -7,41 +6,26 @@ import { nextTick, onBeforeUnmount, onMounted, - PropType, reactive, ref, - Ref, renderSlot, toRef, watch, } from 'vue'; import { CommonOverlay } from './common-overlay'; -import { overlayProps } from './overlay-types'; +import { OriginOrDomRef, flexibleOverlayProps, FlexibleOverlayProps, Point, Origin, ConnectionPosition } from './overlay-types'; import { useOverlayLogic } from './utils'; +import { getElement, isComponent } from '../../shared/util/dom'; + /** * 弹性的 Overlay,用于连接固定的和相对点 */ export const FlexibleOverlay = defineComponent({ name: 'DFlexibleOverlay', - props: { - origin: { - type: Object as PropType, - require: true, - }, - position: { - type: Object as PropType, - default: () => ({ - originX: 'left', - originY: 'top', - overlayX: 'left', - overlayY: 'top', - }), - }, - ...overlayProps, - }, + props: flexibleOverlayProps, emits: ['onUpdate:visible'], - setup(props, ctx) { + setup(props: FlexibleOverlayProps, ctx) { // lift cycle const overlayRef = ref(null); const positionedStyle = reactive({ position: 'absolute' }); @@ -70,10 +54,12 @@ export const FlexibleOverlay = defineComponent({ positionedStyle.left = `${point.x}px`; positionedStyle.top = `${point.y}px`; }; - const handleChange = () => - handleRectChange(overlay.getBoundingClientRect()); + const handleChange = () => handleRectChange(overlay.getBoundingClientRect()); + + const visibleRef = toRef(props, 'visible'); + const positionRef = toRef(props, 'position'); - watch(toRef(props, 'visible'), (visible, ov, onInvalidate) => { + watch(visibleRef, (visible, ov, onInvalidate) => { if (visible) { subscribeLayoutEvent(handleChange); } else { @@ -84,7 +70,7 @@ export const FlexibleOverlay = defineComponent({ }); }); - watch(toRef(props, 'position'), () => { + watch([visibleRef, positionRef], () => { handleChange(); }); @@ -97,8 +83,7 @@ export const FlexibleOverlay = defineComponent({ }, instance); if (origin instanceof Element) { - // Only when the style changing, you can change - // the position. + // Only when the style changing, you can change the position. const observer = new MutationObserver(handleChange); observer.observe(origin, { attributeFilter: ['style'], @@ -118,7 +103,12 @@ export const FlexibleOverlay = defineComponent({ return () => ( -
+
- | Rect; - -type Origin = Element | Rect; - -type HorizontalConnectionPos = 'left' | 'center' | 'right'; -type VerticalConnectionPos = 'top' | 'center' | 'bottom'; - -interface ConnectionPosition { - originX: HorizontalConnectionPos - originY: VerticalConnectionPos - overlayX: HorizontalConnectionPos - overlayY: VerticalConnectionPos -} /** * 获取原点,可能是 Element 或者 Rect @@ -207,6 +139,10 @@ function getOrigin(origin: OriginOrDomRef): Origin { return getElement(origin.value); } + if (isComponent(origin)) { + return getElement(origin); + } + // is point { x: number, y: number, width: number, height: number } return origin; } @@ -243,9 +179,9 @@ function calculatePosition( /** * 返回原点元素的 ClientRect * @param origin - * @returns {ClientRect} + * @returns {DOMRect} */ -function getOriginRect(origin: Origin): ClientRect { +function getOriginRect(origin: Origin): DOMRect { if (origin instanceof Element) { return origin.getBoundingClientRect(); } @@ -261,7 +197,7 @@ function getOriginRect(origin: Origin): ClientRect { right: origin.x + width, height, width, - }; + } as DOMRect; } /** diff --git a/packages/devui-vue/devui/overlay/src/overlay-types.ts b/packages/devui-vue/devui/overlay/src/overlay-types.ts index 766963dc7da907808927892546d38d77a990c303..f90ccfb71b1086cdc7f528fffd8447deeccba49b 100644 --- a/packages/devui-vue/devui/overlay/src/overlay-types.ts +++ b/packages/devui-vue/devui/overlay/src/overlay-types.ts @@ -1,4 +1,4 @@ -import { ExtractPropTypes, PropType, CSSProperties } from 'vue'; +import { ExtractPropTypes, PropType, StyleValue, ComponentPublicInstance, Ref } from 'vue'; export const overlayProps = { visible: { @@ -16,7 +16,7 @@ export const overlayProps = { default: '' }, backgroundStyle: { - type: [String, Object] as PropType + type: [String, Object] as PropType }, backdropClick: { type: Function, @@ -24,8 +24,84 @@ export const overlayProps = { backdropClose: { type: Boolean, default: true - } + }, + hasBackdrop: { + type: Boolean, + default: true + }, } as const; +export type OverlayProps = ExtractPropTypes; + + +export const fixedOverlayProps = { + ...overlayProps, + overlayStyle: { + type: [String, Object] as PropType, + default: undefined, + }, +}; + +export type FixedOverlayProps = ExtractPropTypes; + +export const flexibleOverlayProps = { + origin: { + type: Object as PropType, + require: true, + }, + position: { + type: Object as PropType, + default: () => ({ + originX: 'left', + originY: 'top', + overlayX: 'left', + overlayY: 'top', + }), + }, + ...overlayProps, +} + + +export interface ClientRect { + bottom: number + readonly height: number + left: number + right: number + top: number + readonly width: number +} + +export interface Point { + x: number + y: number +} + +export interface Rect { + x: number + y: number + width?: number + height?: number +} + +export type Origin = Element | Rect; + +type HorizontalConnectionPos = 'left' | 'center' | 'right'; +type VerticalConnectionPos = 'top' | 'center' | 'bottom'; + +export interface ConnectionPosition { + originX: HorizontalConnectionPos + originY: VerticalConnectionPos + overlayX: HorizontalConnectionPos + overlayY: VerticalConnectionPos +} + +export type OriginOrDomRef = + | Element + | ComponentPublicInstance + | Ref + | Rect + | null; + +export type FlexibleOverlayProps = ExtractPropTypes; + -export type OverlayProps = ExtractPropTypes; \ No newline at end of file diff --git a/packages/devui-vue/devui/overlay/src/overlay.scss b/packages/devui-vue/devui/overlay/src/overlay.scss index 66c0f4a87b04436cedac17fbeef45687f602b06d..d9c754e5c1ebcc378eae097817f9d83982d9ae0c 100644 --- a/packages/devui-vue/devui/overlay/src/overlay.scss +++ b/packages/devui-vue/devui/overlay/src/overlay.scss @@ -15,6 +15,10 @@ z-index: 1000; pointer-events: auto; } + + &__disabled { + pointer-events: none; + } } .devui-overlay-fade { diff --git a/packages/devui-vue/devui/overlay/src/utils.ts b/packages/devui-vue/devui/overlay/src/utils.ts index 262253e8f273a532e2f8ce789eb87d3f22a9e70a..4f115130a5184a1421f5153a7ee85751fe26053a 100644 --- a/packages/devui-vue/devui/overlay/src/utils.ts +++ b/packages/devui-vue/devui/overlay/src/utils.ts @@ -10,7 +10,11 @@ interface CommonInfo { export function useOverlayLogic(props: OverlayProps): CommonInfo { const backgroundClass = computed(() => { - return ['devui-overlay-background', 'devui-overlay-background__color', props.backgroundClass]; + return [ + 'devui-overlay-background', + props.backgroundClass, + !props.hasBackdrop ? 'devui-overlay-background__disabled' : 'devui-overlay-background__color', + ]; }); const overlayClass = computed(() => { return 'devui-overlay'; diff --git a/packages/devui-vue/devui/shared/util/dom.ts b/packages/devui-vue/devui/shared/util/dom.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2cb9566889c4cd5613a7b3001ee216343c6da26 --- /dev/null +++ b/packages/devui-vue/devui/shared/util/dom.ts @@ -0,0 +1,31 @@ +import { ComponentPublicInstance } from "@vue/runtime-core"; + +/** + * + * @param {any} origin + * @returns + */ +export function isComponent(target: any): target is ComponentPublicInstance { + return !!(target?.$el); +} + +/** + * 提取 Vue Intance 中的元素,如果本身就是元素,直接返回。 + * @param {any} element + * @returns {Element | null} + */ +export function getElement( + element: Element | ComponentPublicInstance | null +): Element | null { + if (element instanceof Element) { + return element; + } + if ( + element && + typeof element === 'object' && + element.$el instanceof Element + ) { + return element.$el; + } + return null; +} \ No newline at end of file diff --git a/packages/devui-vue/devui/style/core/_dropdown.scss b/packages/devui-vue/devui/style/core/_dropdown.scss index 085045d0498aa8864e4a4404185f2783f49df889..f6e6defa90af4388ee0952f12c7d45e0c345b40a 100755 --- a/packages/devui-vue/devui/style/core/_dropdown.scss +++ b/packages/devui-vue/devui/style/core/_dropdown.scss @@ -46,7 +46,6 @@ top: calc(100% - 1px); left: 0; z-index: 1000; - display: none; min-width: calc(min(100%, 102px)); margin: 4px 0; padding-bottom: 5px; @@ -67,9 +66,9 @@ margin-bottom: -1px; } - .open > & { - display: block; - } + // .open > & { + // display: block; + // } > li { position: relative; diff --git a/packages/devui-vue/devui/style/theme/_shadow.scss b/packages/devui-vue/devui/style/theme/_shadow.scss index a86b13c331a7dba9aaed874df0e7cb35f9bda5e9..313b2e33a44e6197d8a873a60c6134724a65e706 100644 --- a/packages/devui-vue/devui/style/theme/_shadow.scss +++ b/packages/devui-vue/devui/style/theme/_shadow.scss @@ -4,7 +4,7 @@ $devui-shadow-length-base: var(--devui-shadow-length-base, 0 1px 4px 0); //直 $devui-shadow-length-slide-left: var(--devui-shadow-length-slide-left, -2px 0 8px 0); //向左滑动时出现在右侧边缘的阴影 (dataTable固定右侧列向左滑动) $devui-shadow-length-slide-right: var(--devui-shadow-length-slide-right, 2px 0 8px 0); //向右滑动时出现在左侧边缘的阴影 (dataTable固定左侧列向右滑动) -$devui-shadow-length-connected-overlay : var(--devui-shadow-connected-overlay, 0 2px 8px 0); //有连接点的弹出(覆盖)层 (DatePicker Cascader Select TagsInput Pagination的下拉菜单等) +$devui-shadow-length-connected-overlay: var(--devui-shadow-connected-overlay, 0 2px 8px 0); //有连接点的弹出(覆盖)层 (DatePicker Cascader Select TagsInput Pagination的下拉菜单等) $devui-shadow-length-hover : var(--devui-shadow-length-hover, 0 4px 16px 0); //涉及到hover的地方 $devui-shadow-length-feedback-overlay : var(--devui-shadow-length-feedback-overlay, 0 4px 16px 0); //信息提示反馈类 (PopOver Tooltip Toast StepsGuide等) diff --git a/packages/devui-vue/docs/components/dropdown/index.md b/packages/devui-vue/docs/components/dropdown/index.md new file mode 100644 index 0000000000000000000000000000000000000000..296eb3ee9c948040a184e641372a527be92fefe3 --- /dev/null +++ b/packages/devui-vue/docs/components/dropdown/index.md @@ -0,0 +1,134 @@ +# Dropdown 下拉菜单 +按下弹出列表组件。 + +### 何时使用 +当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。 + + + +### 基本用法 + +:::demo + +```vue + + + + +``` +::: + +### d-dropdown + +d-dropdown 参数 + +| 参数 | 类型 | 默认 | 说明 | +| --------------------- | ------------------------------------ | ------- | --------------------------------------------------------------------------------------------------------------- | +| origin | `Element \| ComponentPublicInstance` | 无 | 必选,必须指定 dropdown 的关联元素 | +| isOpen | `boolean` | `false` | 可选,可以显示指定 dropdown 是否打开 | +| disabled | `boolean` | `false` | 可选,设置为 true 禁用 dropdown | +| trigger | `TriggerType` | `click` | 可选,dropdown 触发方式, click 为点击,hover 为悬停(也包含点击)、manually 为完全手动控制 | +| closeScope | `CloseScopeArea` | `all` | 可选,点击关闭区域,blank 点击非菜单空白才关闭, all 点击菜单内外都关闭,none 菜单内外均不关闭仅下拉按键可以关闭 | +| closeOnMouseLeaveMenu | `boolean` | `false` | 可选,是否进入菜单后离开菜单的时候关闭菜单 | +| showAnimation | `boolean` | `true` | 可选,是否开启动画 | + +TriggerType 类型 +```typescript +type TriggerType = 'click' | 'hover' | 'manually'; +``` + +CloseScopeArea 类型 +```typescript +type CloseScopeArea = 'all' | 'blank' | 'none'; +``` \ No newline at end of file diff --git a/packages/devui-vue/docs/components/overlay/index.md b/packages/devui-vue/docs/components/overlay/index.md index 2fecc9afc2d97df22e5275eda525ff4e4e227f41..7d604b356d6046ecc2c653440c4c767f0b0a4bf0 100644 --- a/packages/devui-vue/docs/components/overlay/index.md +++ b/packages/devui-vue/docs/components/overlay/index.md @@ -169,7 +169,7 @@ export default defineComponent({ -### API +### API d-fixed-overlay 参数 | 参数 | 类型 | 默认 | 说明 | @@ -178,8 +178,10 @@ d-fixed-overlay 参数 | onUpdate:visible | `(value: boolean) => void` | -- | 可选,遮罩层取消可见事件 | | backgroundBlock | `boolean` | false | 可选,如果为 true,背景不能滚动 | | backgroundClass | `string` | -- | 可选,背景的样式类 | +| backgroundStyle | `StyleValue` | -- | 可选,背景的样式 | | backdropClick | `() => void` | -- | 可选,点击背景触发的事件 | | backdropClose | `boolean` | false | 可选,如果为true,点击背景将触发 `onUpdate:visible`,默认参数是 false | +| hasBackdrop | `boolean` | true | 可选,如果为false,背景元素的 `point-event` 会设为 `none`,且不显示默认背景 | | overlayStyle | `CSSProperties` | -- | 可选,遮罩层的样式 | d-flexible-overlay 参数 @@ -190,7 +192,33 @@ d-flexible-overlay 参数 | onUpdate:visible | `(value: boolean) => void` | -- | 可选,遮罩层取消可见事件 | | backgroundBlock | `boolean` | false | 可选,如果为 true,背景不能滚动 | | backgroundClass | `string` | -- | 可选,背景的样式类 | +| backgroundStyle | `StyleValue` | -- | 可选,背景的样式 | | backdropClick | `() => void` | -- | 可选,点击背景触发的事件 | | backdropClose | `boolean` | false | 可选,如果为true,点击背景将触发 `onUpdate:visible`,参数是 false | -| origin | `Element \| ComponentPublicInstance \| { x: number, y: number, width?: number, height?: number }` | false | 必选,你必须指定起点元素才能让遮罩层与该元素连接在一起 | -| position | `{originX: HorizontalPos, originY: VerticalPos, overlayX: HorizontalPos, overlayY: VerticalPos } (type HorizontalPos = 'left' \| 'center' \| 'right') ( type VerticalPos = 'top' \| 'center' \| 'bottom')` | false | 可选,指定遮罩层与原点的连接点 | +| hasBackdrop | `boolean` | true | 可选,如果为false,背景元素的 `point-event` 会设为 `none`,且不显示默认背景 | +| origin | `Element \| ComponentPublicInstance \| Rect` | false | 必选,你必须指定起点元素才能让遮罩层与该元素连接在一起 | +| position | `ConnectionPosition` | false | 可选,指定遮罩层与原点的连接点 | + +Rect 数据结构 +```typescript +interface Rect { + x: number + y: number + width?: number + height?: number +} +``` + +ConnectionPosition 数据结构 +```typescript +type HorizontalConnectionPos = 'left' | 'center' | 'right'; +type VerticalConnectionPos = 'top' | 'center' | 'bottom'; + +export interface ConnectionPosition { + originX: HorizontalConnectionPos + originY: VerticalConnectionPos + overlayX: HorizontalConnectionPos + overlayY: VerticalConnectionPos +} +``` +