From ff44ce6a3ed949a531d6ea8775503191ab13964b Mon Sep 17 00:00:00 2001 From: zhuchenxi Date: Tue, 24 Aug 2021 11:46:54 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat(overlay):=20=E5=AE=8C=E6=88=90=20overl?= =?UTF-8?q?ay?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/overlay/index.ts | 31 +++ devui/overlay/src/common-overlay.tsx | 14 ++ devui/overlay/src/fixed-overlay.tsx | 62 ++++++ devui/overlay/src/flexible-overlay.tsx | 284 +++++++++++++++++++++++++ devui/overlay/src/overlay-types.ts | 21 ++ devui/overlay/src/overlay.scss | 58 +++++ devui/overlay/src/utils.ts | 18 ++ 7 files changed, 488 insertions(+) create mode 100644 devui/overlay/index.ts create mode 100644 devui/overlay/src/common-overlay.tsx create mode 100644 devui/overlay/src/fixed-overlay.tsx create mode 100644 devui/overlay/src/flexible-overlay.tsx create mode 100644 devui/overlay/src/overlay-types.ts create mode 100644 devui/overlay/src/overlay.scss create mode 100644 devui/overlay/src/utils.ts diff --git a/devui/overlay/index.ts b/devui/overlay/index.ts new file mode 100644 index 00000000..c9b8717c --- /dev/null +++ b/devui/overlay/index.ts @@ -0,0 +1,31 @@ +import type { App } from 'vue' +import {FixedOverlay} from './src/fixed-overlay'; +import {FlexibleOverlay } from './src/flexible-overlay'; + +FlexibleOverlay.install = function(app: App) { + app.component(FixedOverlay.name, FixedOverlay); +} + +FixedOverlay.install = function(app: App) { + app.component(FixedOverlay.name, FixedOverlay); +} + +export { FlexibleOverlay, FixedOverlay } + +export default { + title: 'Overlay 浮层', + category: '基础', + install(app: App): void { + app.use(FixedOverlay as any); + app.use(FlexibleOverlay as any); + if (!document.getElementById('d-overlay-anchor')) { + const overlayAnchor = document.createElement('div'); + overlayAnchor.setAttribute('id', 'd-overlay-anchor'); + overlayAnchor.style.position = 'fixed'; + overlayAnchor.style.left = '0'; + overlayAnchor.style.top = '0'; + overlayAnchor.style.zIndex = '1000'; + document.body.appendChild(overlayAnchor); + } + } +} diff --git a/devui/overlay/src/common-overlay.tsx b/devui/overlay/src/common-overlay.tsx new file mode 100644 index 00000000..2928bd39 --- /dev/null +++ b/devui/overlay/src/common-overlay.tsx @@ -0,0 +1,14 @@ +import { defineComponent, renderSlot, Teleport, Transition } from 'vue'; +import './overlay.scss'; + +export const CommonOverlay = defineComponent({ + setup(props, ctx) { + return () => ( + + + {renderSlot(ctx.slots, 'defalut')} + + + ) + } +}); diff --git a/devui/overlay/src/fixed-overlay.tsx b/devui/overlay/src/fixed-overlay.tsx new file mode 100644 index 00000000..fe6c25a8 --- /dev/null +++ b/devui/overlay/src/fixed-overlay.tsx @@ -0,0 +1,62 @@ +import { defineComponent, ref, renderSlot, CSSProperties, toRef } from 'vue'; +import { CommonOverlay } from './common-overlay'; +import { overlayProps } from './overlay-types'; +import './overlay.scss'; +import { overlayVisible } from './utils'; + +export const FixedOverlay = defineComponent({ + name: 'DFixedOverlay', + props: { + ...overlayProps, + wrapperStyle: { + type: Object as () => CSSProperties + }, + }, + setup(props, ctx) { + const visible = overlayVisible(toRef(props, 'backgroundBlock')); + + const clickBackground = (event: Event) => { + event.preventDefault(); + + props.backdropClick?.(); + if (props.backdropClose) { + visible.value = false; + } + }; + + const panelRef = ref(null); + + + return () => { + return ( + +
+
+
event.cancelBubble = true} + > + {renderSlot(ctx.slots, 'default')} +
+
+
+
+ ) + } + } +}); diff --git a/devui/overlay/src/flexible-overlay.tsx b/devui/overlay/src/flexible-overlay.tsx new file mode 100644 index 00000000..9c75bb93 --- /dev/null +++ b/devui/overlay/src/flexible-overlay.tsx @@ -0,0 +1,284 @@ +import { ComponentPublicInstance, CSSProperties, defineComponent, isRef, nextTick, onBeforeUnmount, onMounted, reactive, ref, Ref, renderSlot, toRef, watch } from 'vue'; +import { CommonOverlay } from './common-overlay'; +import { overlayProps } from './overlay-types'; +import { overlayVisible } from './utils'; + + +/** + * + */ +export const FlexibleOverlay = defineComponent({ + name: 'DFlexibleOverlay', + props: { + origin: { + type: Object as () => OriginOrDomRef, + default: () => ({ x: 0, y: 0 }) + }, + position: { + type: Object as () => ConnectionPosition, + default: () => ({ originX: 'left', originY: 'top', overlayX: 'left', overlayY: 'top' }) + }, + ...overlayProps + }, + setup(props, ctx) { + const overlayRef = ref(null); + const positionedStyle = reactive({ position: 'absolute' }); + + const visible = overlayVisible(toRef(props, 'backgroundBlock')); + + // lift cycle + onMounted(async () => { + await nextTick(); + + // 获取背景 + const overlay = overlayRef.value; + if (!overlay) { + return; + } + + // 获取原点 + const origin = getOrigin(props.origin); + if (!origin) { + return; + } + + const handleRectChange = (rect: DOMRect) => { + // TODO: add optimize for throttle + const point = calculatePosition(props.position, rect, origin); + + // set the current position style's value. + // the current position style is a 'ref'. + positionedStyle.left = `${point.x}px`; + positionedStyle.top = `${point.y}px`; + }; + const handleChange = () => handleRectChange(overlay.getBoundingClientRect()); + + flexibleLayoutChange(visible, handleChange); + + const resizeObserver = new ResizeObserver((entries) => { + handleRectChange(entries[0].contentRect); + }); + resizeObserver.observe(overlay as unknown as Element); + onBeforeUnmount(() => { + resizeObserver.disconnect(); + }); + + if (origin instanceof Element) { + // Only when the style changing, you can change + // the position. + const observer = new MutationObserver(handleChange); + observer.observe(origin, { + attributeFilter: ['style'], + }); + onBeforeUnmount(() => { + observer.disconnect(); + }); + } + }); + + const clickBackground = (event: Event) => { + event.preventDefault(); + + props.backdropClick?.(); + if (props.backdropClose) { + visible.value = false; + } + }; + + return ( + +
+
+
event.cancelBubble = true} + > + {renderSlot(ctx.slots, 'default')} +
+
+
+
+ ) + } +}); + +function getElement(element: Element | { $el: Element; } | null): Element | null { + if (element instanceof Element) { + return element; + } + if (element && typeof element === 'object' && element.$el instanceof Element) { + return element.$el; + } + return null; +} + + +interface ClientRect { + bottom: number + readonly height: number + left: number + right: number + top: number + readonly width: number +} + +interface Point { + x: number + y: number +} + +interface Rect { + x: number + y: number + width?: number + height?: number +} + + +type OriginOrDomRef = Element | Ref | 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 +} + +function getOrigin(origin: OriginOrDomRef): Origin { + // Check for Element so SVG elements are also supported. + if (origin instanceof Element) { + return origin; + } + + if (isRef(origin)) { + return getElement(origin.value); + } + + // is point { x: number, y: number, width: number, height: number } + return origin; +} + + +function calculatePosition(position: ConnectionPosition, panelOrRect: HTMLElement | DOMRect, origin: Origin): Point { + // get overlay rect + const originRect = getOriginRect(origin); + + // calculate the origin point + const originPoint = getOriginPoint(originRect, position); + + let rect: DOMRect; + if (panelOrRect instanceof HTMLElement) { + rect = panelOrRect.getBoundingClientRect(); + } else { + rect = panelOrRect; + } + + // calculate the overlay anchor point + return getOverlayPoint(originPoint, rect, position); +} + + +/** Returns the ClientRect of the current origin. */ +function getOriginRect(origin: Origin): ClientRect { + if (origin instanceof Element) { + return origin.getBoundingClientRect(); + } + // Origin is point + const width = origin.width || 0; + const height = origin.height || 0; + + // If the origin is a point, return a client rect as if it was a 0x0 element at the point. + return { + top: origin.y, + bottom: origin.y + height, + left: origin.x, + right: origin.x + width, + height, + width + }; +} + + + +function getOverlayPoint(originPoint: Point, rect: DOMRect, position: ConnectionPosition): Point { + let x: number; + const { width, height } = rect; + if (position.overlayX == 'center') { + x = originPoint.x - width / 2; + } else { + x = position.overlayX == 'left' ? originPoint.x : (originPoint.x - width); + } + + let y: number; + if (position.overlayY == 'center') { + y = originPoint.y - (height / 2); + } else { + y = position.overlayY == 'top' ? originPoint.y : (originPoint.y - height); + } + + return { x, y }; +} + + +/** + * Gets the (x, y) coordinate of a connection point on the origin based on a relative position. + */ +function getOriginPoint(originRect: ClientRect, position: ConnectionPosition): Point { + let x: number; + if (position.originX == 'center') { + x = originRect.left + (originRect.width / 2); + } else { + const startX = originRect.left; + const endX = originRect.right; + x = position.originX == 'left' ? startX : endX; + } + + let y: number; + if (position.originY == 'center') { + y = originRect.top + (originRect.height / 2); + } else { + y = position.originY == 'top' ? originRect.top : originRect.bottom; + } + + return { x, y }; +} + + +const flexibleLayoutChange = (visible: Ref, event: (e?: Event) => void) => { + watch(visible, (v, ov, onInvalidate) => { + if (visible) { + window.addEventListener('scroll', event, true); + window.addEventListener('resize', event); + window.addEventListener('orientationchange', event); + } else { + window.removeEventListener('scroll', event, true); + window.removeEventListener('resize', event); + window.removeEventListener('orientationchange', event); + } + onInvalidate(() => { + window.removeEventListener('scroll', event, true); + window.removeEventListener('resize', event); + window.removeEventListener('orientationchange', event); + }); + }); +} \ No newline at end of file diff --git a/devui/overlay/src/overlay-types.ts b/devui/overlay/src/overlay-types.ts new file mode 100644 index 00000000..9036841f --- /dev/null +++ b/devui/overlay/src/overlay-types.ts @@ -0,0 +1,21 @@ +export const overlayProps = { + backgroundBlock: { + type: Boolean, + default: false + }, + backgroundClass: { + type: String, + default: '' + }, + hasBackdrop: { + type: Boolean, + default: false + }, + backdropClick: { + type: Function, + }, + backdropClose: { + type: Boolean, + default: false + } +} as const; diff --git a/devui/overlay/src/overlay.scss b/devui/overlay/src/overlay.scss new file mode 100644 index 00000000..f0752579 --- /dev/null +++ b/devui/overlay/src/overlay.scss @@ -0,0 +1,58 @@ +.d-overlay-container { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; + + &__disabled { + pointer-events: none; + } + + &__background { + background: rgba(0, 0, 0, 0.4); + } + + .d-overlay-panel { + position: relative; + z-index: 1000; + } + + .d-overlay { + pointer-events: auto; + } +} + +.d-overlay-fade { + @mixin d-overlay-fade-animation { + animation-name: d-overlay-fade; + animation-duration: 0.3s; + } + @keyframes d-overlay-fade { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } + } + + &-enter { + opacity: 0; + } + + &-enter-active { + @include d-overlay-fade-animation; + } + + &-leave { + opacity: 1; + } + + &-leave-active { + @include d-overlay-fade-animation; + + animation-direction: reverse; + } +} diff --git a/devui/overlay/src/utils.ts b/devui/overlay/src/utils.ts new file mode 100644 index 00000000..24a34eef --- /dev/null +++ b/devui/overlay/src/utils.ts @@ -0,0 +1,18 @@ +import { onUnmounted, ref, watch, Ref } from 'vue'; + +export function overlayVisible(backgroundBlock: Ref): Ref { + const visible = ref(false); + const body = document.body; + const originOverflow = body.style.overflow; + watch(visible, (value) => { + if (backgroundBlock.value) { + body.style.overflow = value ? 'hidden' : originOverflow; + } + }); + + onUnmounted(() => { + body.style.overflow = originOverflow; + }); + + return visible; +} \ No newline at end of file -- Gitee From 37f556ab3d13a4be1e6afecf69a2841e8437e8ed Mon Sep 17 00:00:00 2001 From: zhuchenxi Date: Tue, 24 Aug 2021 18:07:39 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat(overlay):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/overlay/index.ts | 4 +- devui/overlay/src/common-overlay.tsx | 2 +- devui/overlay/src/fixed-overlay.tsx | 64 ++++++++------------ devui/overlay/src/flexible-overlay.tsx | 82 +++++++++++--------------- devui/overlay/src/overlay-types.ts | 15 ++++- devui/overlay/src/utils.ts | 44 +++++++++++--- sites/.vitepress/config/sidebar.ts | 1 + sites/components/overlay/index.md | 76 ++++++++++++++++++++++++ 8 files changed, 188 insertions(+), 100 deletions(-) create mode 100644 sites/components/overlay/index.md diff --git a/devui/overlay/index.ts b/devui/overlay/index.ts index c9b8717c..0e363ac8 100644 --- a/devui/overlay/index.ts +++ b/devui/overlay/index.ts @@ -3,7 +3,7 @@ import {FixedOverlay} from './src/fixed-overlay'; import {FlexibleOverlay } from './src/flexible-overlay'; FlexibleOverlay.install = function(app: App) { - app.component(FixedOverlay.name, FixedOverlay); + app.component(FlexibleOverlay.name, FlexibleOverlay); } FixedOverlay.install = function(app: App) { @@ -14,7 +14,7 @@ export { FlexibleOverlay, FixedOverlay } export default { title: 'Overlay 浮层', - category: '基础', + category: '通用', install(app: App): void { app.use(FixedOverlay as any); app.use(FlexibleOverlay as any); diff --git a/devui/overlay/src/common-overlay.tsx b/devui/overlay/src/common-overlay.tsx index 2928bd39..f99f6b54 100644 --- a/devui/overlay/src/common-overlay.tsx +++ b/devui/overlay/src/common-overlay.tsx @@ -6,7 +6,7 @@ export const CommonOverlay = defineComponent({ return () => ( - {renderSlot(ctx.slots, 'defalut')} + {renderSlot(ctx.slots, 'default')} ) diff --git a/devui/overlay/src/fixed-overlay.tsx b/devui/overlay/src/fixed-overlay.tsx index fe6c25a8..f5478029 100644 --- a/devui/overlay/src/fixed-overlay.tsx +++ b/devui/overlay/src/fixed-overlay.tsx @@ -1,62 +1,46 @@ +import { PropType } from 'vue'; +import { computed, reactive } from 'vue'; import { defineComponent, ref, renderSlot, CSSProperties, toRef } from 'vue'; import { CommonOverlay } from './common-overlay'; import { overlayProps } from './overlay-types'; import './overlay.scss'; -import { overlayVisible } from './utils'; +import { useOverlayLogic } from './utils'; export const FixedOverlay = defineComponent({ name: 'DFixedOverlay', props: { ...overlayProps, wrapperStyle: { - type: Object as () => CSSProperties + type: Object as PropType }, }, setup(props, ctx) { - const visible = overlayVisible(toRef(props, 'backgroundBlock')); + const { containerClass, panelClass, handleBackdropClick } = useOverlayLogic(props); + const overlayRef = ref(null); + const positionedStyle = reactive({ position: 'absolute' }); - const clickBackground = (event: Event) => { - event.preventDefault(); - - props.backdropClick?.(); - if (props.backdropClose) { - visible.value = false; - } - }; - - const panelRef = ref(null); - - - return () => { - return ( - + return () => ( + +
event.cancelBubble = true} > -
event.cancelBubble = true} - > - {renderSlot(ctx.slots, 'default')} -
+ {renderSlot(ctx.slots, 'default')}
- - ) - } +
+
+ ); } }); diff --git a/devui/overlay/src/flexible-overlay.tsx b/devui/overlay/src/flexible-overlay.tsx index 9c75bb93..e8dbd4cb 100644 --- a/devui/overlay/src/flexible-overlay.tsx +++ b/devui/overlay/src/flexible-overlay.tsx @@ -1,7 +1,7 @@ -import { ComponentPublicInstance, CSSProperties, defineComponent, isRef, nextTick, onBeforeUnmount, onMounted, reactive, ref, Ref, renderSlot, toRef, watch } from 'vue'; +import { ComponentPublicInstance, CSSProperties, defineComponent, getCurrentInstance, isRef, nextTick, onBeforeUnmount, onMounted, reactive, ref, Ref, renderSlot, toRef, watch } from 'vue'; import { CommonOverlay } from './common-overlay'; import { overlayProps } from './overlay-types'; -import { overlayVisible } from './utils'; +import { useOverlayLogic } from './utils'; /** @@ -12,7 +12,7 @@ export const FlexibleOverlay = defineComponent({ props: { origin: { type: Object as () => OriginOrDomRef, - default: () => ({ x: 0, y: 0 }) + require: true }, position: { type: Object as () => ConnectionPosition, @@ -20,13 +20,12 @@ export const FlexibleOverlay = defineComponent({ }, ...overlayProps }, + emits: ['onUpdate:visible'], setup(props, ctx) { + // lift cycle const overlayRef = ref(null); const positionedStyle = reactive({ position: 'absolute' }); - - const visible = overlayVisible(toRef(props, 'backgroundBlock')); - - // lift cycle + const instance = getCurrentInstance(); onMounted(async () => { await nextTick(); @@ -53,7 +52,16 @@ export const FlexibleOverlay = defineComponent({ }; const handleChange = () => handleRectChange(overlay.getBoundingClientRect()); - flexibleLayoutChange(visible, handleChange); + watch(toRef(props, 'visible'), (visible, ov, onInvalidate) => { + if (visible) { + subscribeLayoutEvent(handleChange); + } else { + unsbscribeLayoutEvent(handleChange); + } + onInvalidate(() => { + unsbscribeLayoutEvent(handleChange); + }); + }); const resizeObserver = new ResizeObserver((entries) => { handleRectChange(entries[0].contentRect); @@ -61,7 +69,7 @@ export const FlexibleOverlay = defineComponent({ resizeObserver.observe(overlay as unknown as Element); onBeforeUnmount(() => { resizeObserver.disconnect(); - }); + }, instance); if (origin instanceof Element) { // Only when the style changing, you can change @@ -72,35 +80,23 @@ export const FlexibleOverlay = defineComponent({ }); onBeforeUnmount(() => { observer.disconnect(); - }); + }, instance); } - }); + }, instance); - const clickBackground = (event: Event) => { - event.preventDefault(); + const { containerClass, panelClass, handleBackdropClick } = useOverlayLogic(props); - props.backdropClick?.(); - if (props.backdropClose) { - visible.value = false; - } - }; - return ( + return () => (
void) => { + window.addEventListener('scroll', event, true); + window.addEventListener('resize', event); + window.addEventListener('orientationchange', event); +}; -const flexibleLayoutChange = (visible: Ref, event: (e?: Event) => void) => { - watch(visible, (v, ov, onInvalidate) => { - if (visible) { - window.addEventListener('scroll', event, true); - window.addEventListener('resize', event); - window.addEventListener('orientationchange', event); - } else { - window.removeEventListener('scroll', event, true); - window.removeEventListener('resize', event); - window.removeEventListener('orientationchange', event); - } - onInvalidate(() => { - window.removeEventListener('scroll', event, true); - window.removeEventListener('resize', event); - window.removeEventListener('orientationchange', event); - }); - }); -} \ No newline at end of file +const unsbscribeLayoutEvent = (event: (e?: Event) => void) => { + window.removeEventListener('scroll', event, true); + window.removeEventListener('resize', event); + window.removeEventListener('orientationchange', event); +} diff --git a/devui/overlay/src/overlay-types.ts b/devui/overlay/src/overlay-types.ts index 9036841f..80b20826 100644 --- a/devui/overlay/src/overlay-types.ts +++ b/devui/overlay/src/overlay-types.ts @@ -1,4 +1,12 @@ +import { ExtractPropTypes, PropType } from 'vue'; + export const overlayProps = { + visible: { + type: Boolean, + }, + 'onUpdate:visible': { + type: Function as PropType<(v: boolean) => void> + }, backgroundBlock: { type: Boolean, default: false @@ -9,13 +17,16 @@ export const overlayProps = { }, hasBackdrop: { type: Boolean, - default: false + default: true }, backdropClick: { type: Function, }, backdropClose: { type: Boolean, - default: false + default: true } } as const; + + +export type OverlayProps = ExtractPropTypes; \ No newline at end of file diff --git a/devui/overlay/src/utils.ts b/devui/overlay/src/utils.ts index 24a34eef..0c1b09a4 100644 --- a/devui/overlay/src/utils.ts +++ b/devui/overlay/src/utils.ts @@ -1,12 +1,36 @@ -import { onUnmounted, ref, watch, Ref } from 'vue'; +import { onUnmounted, watch, computed } from 'vue'; +import { OverlayProps } from './overlay-types'; + +export function useOverlayLogic(props: OverlayProps) { + const containerClass = computed(() => { + if (props.hasBackdrop) { + return ['d-overlay-container', props.backgroundClass]; + } else { + return ['d-overlay-container', 'd-overlay-container__disabled']; + } + }); + const panelClass = computed(() => { + if (props.hasBackdrop) { + return ['d-overlay-panel']; + } else { + return ['d-overlay-panel', 'd-overlay-container__disabled']; + } + }); + + const handleBackdropClick = (event: Event) => { + event.preventDefault(); + + props.backdropClick?.(); + if (props.backdropClose) { + props['onUpdate:visible']?.(false); + } + }; -export function overlayVisible(backgroundBlock: Ref): Ref { - const visible = ref(false); const body = document.body; const originOverflow = body.style.overflow; - watch(visible, (value) => { - if (backgroundBlock.value) { - body.style.overflow = value ? 'hidden' : originOverflow; + watch([() => props.visible, () => props.backgroundBlock], ([visible, backgroundBlock]) => { + if (backgroundBlock) { + body.style.overflow = visible ? 'hidden' : originOverflow; } }); @@ -14,5 +38,9 @@ export function overlayVisible(backgroundBlock: Ref): Ref { body.style.overflow = originOverflow; }); - return visible; -} \ No newline at end of file + return { + containerClass, + panelClass, + handleBackdropClick + } +} diff --git a/sites/.vitepress/config/sidebar.ts b/sites/.vitepress/config/sidebar.ts index fbafed02..7c9f0f76 100644 --- a/sites/.vitepress/config/sidebar.ts +++ b/sites/.vitepress/config/sidebar.ts @@ -12,6 +12,7 @@ const sidebar = { { text: 'Search 搜索框', link: '/components/search/', status: '已完成' }, { text: 'Status 状态', link: '/components/status/', status: '已完成' }, { text: 'Sticky 便贴', link: '/components/sticky/' }, + { text: 'Overlay 浮层', link: '/components/overlay/'} ] }, { diff --git a/sites/components/overlay/index.md b/sites/components/overlay/index.md new file mode 100644 index 00000000..a9c8ae5d --- /dev/null +++ b/sites/components/overlay/index.md @@ -0,0 +1,76 @@ +## 浮层 + +### 固定浮层 +{{fixedVisible ? '隐藏' : '显示固定浮层' }} + +
hello world
+
+ + +### 弹性浮层 +
+
orgin
+ {{visible ? '隐藏' : '显示' }} +
+ + +
hello world
+
+ + + + \ No newline at end of file -- Gitee From a7b3db0ba130c7e7f34018709c5e5e9015fabd9a Mon Sep 17 00:00:00 2001 From: zhuchenxi Date: Wed, 25 Aug 2021 09:56:40 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat(overlay):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/overlay/src/fixed-overlay.tsx | 9 ++-- devui/overlay/src/flexible-overlay.tsx | 64 ++++++++++++++++++++------ devui/overlay/src/utils.ts | 10 +++- sites/components/overlay/index.md | 20 ++++---- 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/devui/overlay/src/fixed-overlay.tsx b/devui/overlay/src/fixed-overlay.tsx index f5478029..109960e8 100644 --- a/devui/overlay/src/fixed-overlay.tsx +++ b/devui/overlay/src/fixed-overlay.tsx @@ -10,14 +10,15 @@ export const FixedOverlay = defineComponent({ name: 'DFixedOverlay', props: { ...overlayProps, - wrapperStyle: { + overlayStyle: { type: Object as PropType }, }, setup(props, ctx) { const { containerClass, panelClass, handleBackdropClick } = useOverlayLogic(props); + const overlayRef = ref(null); - const positionedStyle = reactive({ position: 'absolute' }); + const handleBubbleCancel = (event: Event) => event.cancelBubble = true; return () => ( @@ -33,8 +34,8 @@ export const FixedOverlay = defineComponent({
event.cancelBubble = true} + style={props.overlayStyle} + onClick={handleBubbleCancel} > {renderSlot(ctx.slots, 'default')}
diff --git a/devui/overlay/src/flexible-overlay.tsx b/devui/overlay/src/flexible-overlay.tsx index e8dbd4cb..2dfc2bf5 100644 --- a/devui/overlay/src/flexible-overlay.tsx +++ b/devui/overlay/src/flexible-overlay.tsx @@ -1,21 +1,21 @@ -import { ComponentPublicInstance, CSSProperties, defineComponent, getCurrentInstance, isRef, nextTick, onBeforeUnmount, onMounted, reactive, ref, Ref, renderSlot, toRef, watch } from 'vue'; +import { ComponentPublicInstance, CSSProperties, defineComponent, getCurrentInstance, isRef, nextTick, onBeforeUnmount, onMounted, PropType, reactive, ref, Ref, renderSlot, toRef, watch } from 'vue'; import { CommonOverlay } from './common-overlay'; import { overlayProps } from './overlay-types'; import { useOverlayLogic } from './utils'; /** - * + * 弹性的 Overlay,用于连接固定的和相对点 */ export const FlexibleOverlay = defineComponent({ name: 'DFlexibleOverlay', props: { origin: { - type: Object as () => OriginOrDomRef, + type: Object as PropType, require: true }, position: { - type: Object as () => ConnectionPosition, + type: Object as PropType, default: () => ({ originX: 'left', originY: 'top', overlayX: 'left', overlayY: 'top' }) }, ...overlayProps @@ -86,7 +86,6 @@ export const FlexibleOverlay = defineComponent({ const { containerClass, panelClass, handleBackdropClick } = useOverlayLogic(props); - return () => (
void) => { +/** + * 订阅 layout 变化事件 + * @param event + */ +function subscribeLayoutEvent(event: (e?: Event) => void) { window.addEventListener('scroll', event, true); window.addEventListener('resize', event); window.addEventListener('orientationchange', event); -}; +} -const unsbscribeLayoutEvent = (event: (e?: Event) => void) => { +/** + * 取消 layout 变化事件 + * @param event + */ +function unsbscribeLayoutEvent(event: (e?: Event) => void) { window.removeEventListener('scroll', event, true); window.removeEventListener('resize', event); window.removeEventListener('orientationchange', event); diff --git a/devui/overlay/src/utils.ts b/devui/overlay/src/utils.ts index 0c1b09a4..40d7b947 100644 --- a/devui/overlay/src/utils.ts +++ b/devui/overlay/src/utils.ts @@ -1,7 +1,13 @@ -import { onUnmounted, watch, computed } from 'vue'; +import { onUnmounted, watch, computed, ComputedRef } from 'vue'; import { OverlayProps } from './overlay-types'; -export function useOverlayLogic(props: OverlayProps) { +interface CommonInfo { + containerClass: ComputedRef + panelClass: ComputedRef + handleBackdropClick: (e: Event) => void +} + +export function useOverlayLogic(props: OverlayProps): CommonInfo { const containerClass = computed(() => { if (props.hasBackdrop) { return ['d-overlay-container', props.backgroundClass]; diff --git a/sites/components/overlay/index.md b/sites/components/overlay/index.md index a9c8ae5d..5d7c9310 100644 --- a/sites/components/overlay/index.md +++ b/sites/components/overlay/index.md @@ -2,7 +2,7 @@ ### 固定浮层 {{fixedVisible ? '隐藏' : '显示固定浮层' }} - +
hello world
@@ -38,38 +38,38 @@ export default defineComponent({ })