From 9de660ca47a188df5c4d9c3dbe042c8b9947dd4f Mon Sep 17 00:00:00 2001 From: zhuchenxi Date: Fri, 8 Oct 2021 14:55:10 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(build):=20=E5=AE=8C=E5=96=84=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=20ssr=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- devui/modal/index.ts | 5 + devui/overlay/index.ts | 4 +- devui/overlay/src/utils.ts | 44 ++++----- devui/shared/devui-directive/clickoutside.ts | 26 ++++-- devui/shared/util/common-var.ts | 1 + devui/sticky/src/sticky.tsx | 92 +++++++++---------- devui/theme/core/theme.ts | 6 ++ .../devui-theme/components/NavBar.vue | 7 +- package.json | 4 +- 9 files changed, 104 insertions(+), 85 deletions(-) create mode 100644 devui/shared/util/common-var.ts diff --git a/devui/modal/index.ts b/devui/modal/index.ts index f324c5d9..4c28caa1 100644 --- a/devui/modal/index.ts +++ b/devui/modal/index.ts @@ -2,6 +2,7 @@ import type { App } from 'vue' import Modal from './src/modal' import { ModalService } from './src/services/modal-service' import { DialogService } from './src/services/dialog-service' +import { inBrowser } from '../shared/util/common-var' Modal.install = function(app: App): void { app.component(Modal.name, Modal) @@ -16,6 +17,10 @@ export default { install(app: App): void { app.use(Modal as any) + if (!inBrowser) { + return; + } + let anchorsContainer = document.getElementById('d-modal-anchors-container'); if (!anchorsContainer) { anchorsContainer = document.createElement('div'); diff --git a/devui/overlay/index.ts b/devui/overlay/index.ts index e5a97c08..978cc5e3 100644 --- a/devui/overlay/index.ts +++ b/devui/overlay/index.ts @@ -1,6 +1,7 @@ import type { App } from 'vue' import {FixedOverlay} from './src/fixed-overlay'; import {FlexibleOverlay } from './src/flexible-overlay'; +import {inBrowser} from '../shared/util/common-var'; FlexibleOverlay.install = function(app: App) { app.component(FlexibleOverlay.name, FlexibleOverlay); @@ -18,7 +19,8 @@ export default { install(app: App): void { app.use(FixedOverlay as any); app.use(FlexibleOverlay as any); - if (!document.getElementById('d-overlay-anchor')) { + + if (inBrowser && !document.getElementById('d-overlay-anchor')) { const overlayAnchor = document.createElement('div'); overlayAnchor.setAttribute('id', 'd-overlay-anchor'); overlayAnchor.style.position = 'fixed'; diff --git a/devui/overlay/src/utils.ts b/devui/overlay/src/utils.ts index 7e8c34d7..262253e8 100644 --- a/devui/overlay/src/utils.ts +++ b/devui/overlay/src/utils.ts @@ -1,4 +1,4 @@ -import { onUnmounted, watch, computed, ComputedRef } from 'vue'; +import { onUnmounted, watch, computed, ComputedRef, onMounted } from 'vue'; import { OverlayProps } from './overlay-types'; interface CommonInfo { @@ -27,28 +27,28 @@ export function useOverlayLogic(props: OverlayProps): CommonInfo { const handleOverlayBubbleCancel = (event: Event) => (event.cancelBubble = true); - - const body = document.body; - const originOverflow = body.style.overflow; - const originPosition = body.style.position; - watch([() => props.visible, () => props.backgroundBlock], ([visible, backgroundBlock]) => { - if (backgroundBlock) { - const top = body.getBoundingClientRect().y; - if (visible) { - body.style.overflowY = 'scroll'; - body.style.position = visible ? 'fixed' : ''; - body.style.top = `${top}px`; - } else { - body.style.overflowY = originOverflow; - body.style.position = originPosition; - body.style.top = ''; - window.scrollTo(0, -top); + onMounted(() => { + const body = document.body; + const originOverflow = body.style.overflow; + const originPosition = body.style.position; + watch([() => props.visible, () => props.backgroundBlock], ([visible, backgroundBlock]) => { + if (backgroundBlock) { + const top = body.getBoundingClientRect().y; + if (visible) { + body.style.overflowY = 'scroll'; + body.style.position = visible ? 'fixed' : ''; + body.style.top = `${top}px`; + } else { + body.style.overflowY = originOverflow; + body.style.position = originPosition; + body.style.top = ''; + window.scrollTo(0, -top); + } } - } - }); - - onUnmounted(() => { - body.style.overflow = originOverflow; + }); + onUnmounted(() => { + document.body.style.overflow = originOverflow; + }); }); return { diff --git a/devui/shared/devui-directive/clickoutside.ts b/devui/shared/devui-directive/clickoutside.ts index b6b6ad81..18be4020 100644 --- a/devui/shared/devui-directive/clickoutside.ts +++ b/devui/shared/devui-directive/clickoutside.ts @@ -5,6 +5,7 @@ *
*/ +import { inBrowser } from '../util/common-var' import { on } from './utils' const ctx = Symbol('@@clickoutside') @@ -12,17 +13,21 @@ const nodeList = new Map() let startClick let nid = 0 +let isFirst = true; -on(document, 'mousedown', (e: Event) => { - startClick = e -}) -on(document, 'mouseup', (e: Event) => { - for (const [id, node] of nodeList) { - node[ctx].documentHandler(e, startClick) +function createDocumentHandler(el: HTMLElement, binding: Record, vnode: any) { + if (inBrowser && isFirst) { + isFirst = false; + on(document, 'mousedown', (e: Event) => { + startClick = e + }) + on(document, 'mouseup', (e: Event) => { + for (const [id, node] of nodeList) { + node[ctx].documentHandler(e, startClick) + } + }) } -}) -function createDocumentHandler(el: HTMLElement, binding: Record, vnode: any) { return function(mouseup: Event, mousedown: Event) { if ( !vnode || @@ -32,8 +37,9 @@ function createDocumentHandler(el: HTMLElement, binding: Record, vn el.contains(mouseup.target as HTMLElement) || el.contains(mousedown.target as HTMLElement) || el === mouseup.target - ) - return + ) { + return; + } el[ctx].bindingFn && el[ctx].bindingFn() } } diff --git a/devui/shared/util/common-var.ts b/devui/shared/util/common-var.ts new file mode 100644 index 00000000..a8ba4f7e --- /dev/null +++ b/devui/shared/util/common-var.ts @@ -0,0 +1 @@ +export const inBrowser = typeof window !== 'undefined'; \ No newline at end of file diff --git a/devui/sticky/src/sticky.tsx b/devui/sticky/src/sticky.tsx index bdd0fd45..95d733e7 100644 --- a/devui/sticky/src/sticky.tsx +++ b/devui/sticky/src/sticky.tsx @@ -1,5 +1,5 @@ +import { defineComponent, onMounted, reactive, ref, watch, PropType } from 'vue' -import { defineComponent, onMounted, reactive, ref, watch } from 'vue' export default defineComponent({ name: 'DSticky', @@ -8,27 +8,25 @@ export default defineComponent({ type: Number, }, container: { - type: Element, - default: '', + type: Object as PropType }, view: { type: Object, - default: ()=>{return {top:0,bottom:0}}, + default: () => { return { top: 0, bottom: 0 } }, }, scrollTarget: { - type: Element, - default: '', + type: Object as PropType }, }, emits: ['statusChange'], - setup(props, ctx) { - const { slots } = ctx + setup(props, ctx) { + const { slots } = ctx let container: Element let scrollTarget: Element | Window let scrollTimer: any let scrollPreStart: number | null - + const THROTTLE_DELAY = 16; const THROTTLE_TRIGGER = 100; @@ -38,7 +36,7 @@ export default defineComponent({ const state = reactive({ status: 'normal' }) - + watch( () => props.zIndex, () => { @@ -61,30 +59,30 @@ export default defineComponent({ () => state.status, () => { ctx.emit('statusChange', state.status) - }, + }, { immediate: true } ); const init = () => { - parentNode = stickyRef.value.parentElement - if (!props.container) { - container = parentNode; - } else { - container = props.container - } - - stickyRef.value.style.zIndex = props.zIndex - - scrollTarget = props.scrollTarget || window; - scrollTarget.addEventListener('scroll',throttle); - - initScrollStatus(scrollTarget); + parentNode = stickyRef.value.parentElement + if (!props.container) { + container = parentNode; + } else { + container = props.container + } + + stickyRef.value.style.zIndex = props.zIndex + + scrollTarget = props.scrollTarget || window; + scrollTarget.addEventListener('scroll', throttle); + + initScrollStatus(scrollTarget); } // 初始化,判断位置,如果有滚用动则用handler处理 - const initScrollStatus = ( target: any)=>{ + const initScrollStatus = (target: any) => { const scrollTargets = target === window ? - [document.documentElement, document.body] : [target]; + [document.documentElement, document.body] : [target]; let flag = false; scrollTargets.forEach((scrollTarget) => { if (scrollTarget.scrollTop && scrollTarget.scrollTop > 0) { @@ -98,7 +96,7 @@ export default defineComponent({ const statusProcess = (status: any) => { - const wrapper = stickyRef.value|| document.createElement('div') + const wrapper = stickyRef.value || document.createElement('div') switch (status) { case 'normal': wrapper.style.top = 'auto'; @@ -106,9 +104,9 @@ export default defineComponent({ wrapper.style.position = 'static'; break; case 'follow': - const scrollTargetElement:any = scrollTarget - const viewOffset = scrollTarget && scrollTarget !== window ? - scrollTargetElement.getBoundingClientRect().top : 0; + const scrollTargetElement: any = scrollTarget + const viewOffset = scrollTarget && scrollTarget !== window ? + scrollTargetElement.getBoundingClientRect().top : 0; wrapper.style.top = +viewOffset + ((props.view && props.view.top) || 0) + 'px'; wrapper.style.left = wrapper.getBoundingClientRect().left + 'px'; wrapper.style.position = 'fixed'; @@ -122,7 +120,7 @@ export default defineComponent({ if (wrapper.style.position !== 'fixed' && wrapper.style.position !== 'absolute') { wrapper.style.top = calculateRelativePosition(wrapper, parentNode, 'top') + 'px'; wrapper.style.left = 'auto'; - wrapper.style.position = 'absolute'; + wrapper.style.position = 'absolute'; } wrapper.style.top = calculateRemainPosition(wrapper, parentNode, container) + 'px'; @@ -157,7 +155,7 @@ export default defineComponent({ } const scrollAndResizeHock = () => { - if (container.getBoundingClientRect().left - (containerLeft || 0) !== 0) { + if (container.getBoundingClientRect().left - (containerLeft || 0) !== 0) { state.status = 'stay'; containerLeft = container.getBoundingClientRect().left; } else { @@ -166,31 +164,31 @@ export default defineComponent({ } const scrollHandler = () => { - const scrollTargetElement:any = scrollTarget + const scrollTargetElement: any = scrollTarget const wrapper = stickyRef.value || document.createElement('div') - const viewOffsetTop = scrollTarget && scrollTarget !== window ? - scrollTargetElement.getBoundingClientRect().top : 0; + const viewOffsetTop = scrollTarget && scrollTarget !== window ? + scrollTargetElement.getBoundingClientRect().top : 0; const computedStyle = window.getComputedStyle(container); if (parentNode.getBoundingClientRect().top - viewOffsetTop > ((props.view && props.view.top) || 0)) { state.status = 'normal'; statusProcess(state.status); } else if ( container.getBoundingClientRect().top + - parseInt(computedStyle.paddingTop, 10) + - parseInt(computedStyle.borderTopWidth, 10) - - viewOffsetTop >= + parseInt(computedStyle.paddingTop, 10) + + parseInt(computedStyle.borderTopWidth, 10) - + viewOffsetTop >= ((props.view && props.view.top) || 0) ) { state.status = 'normal'; statusProcess(state.status); } else if ( container.getBoundingClientRect().bottom - - parseInt(computedStyle.paddingBottom, 10) - - parseInt(computedStyle.borderBottomWidth, 10) < + parseInt(computedStyle.paddingBottom, 10) - + parseInt(computedStyle.borderBottomWidth, 10) < viewOffsetTop + - ((props.view && props.view.top) || 0) + - wrapper.getBoundingClientRect().height + - ((props.view && props.view.bottom) || 0) + ((props.view && props.view.top) || 0) + + wrapper.getBoundingClientRect().height + + ((props.view && props.view.bottom) || 0) ) { state.status = 'remain'; statusProcess(state.status); @@ -204,7 +202,7 @@ export default defineComponent({ } - const calculateRelativePosition =(element:any, relativeElement:any, direction:'left' | 'top') => { + const calculateRelativePosition = (element: any, relativeElement: any, direction: 'left' | 'top') => { const key = { left: ['left', 'Left'], top: ['top', 'Top'], @@ -214,8 +212,8 @@ export default defineComponent({ return ( element.getBoundingClientRect()[key[direction][0]] - relativeElement.getBoundingClientRect()[key[direction][0]] - - parseInt(computedStyle[ direction === 'left' ? 'paddingLeft' : 'paddingTop' ], 10) - - parseInt(computedStyle[ direction === 'left' ? 'borderLeftWidth' : 'borderTopWidth' ], 10) + parseInt(computedStyle[direction === 'left' ? 'paddingLeft' : 'paddingTop'], 10) - + parseInt(computedStyle[direction === 'left' ? 'borderLeftWidth' : 'borderTopWidth'], 10) ); } } @@ -246,7 +244,7 @@ export default defineComponent({ return () => { return (
- { slots.default ? slots.default() : '' } + {slots.default ? slots.default() : ''}
) } diff --git a/devui/theme/core/theme.ts b/devui/theme/core/theme.ts index 2b37e404..a21bfd18 100644 --- a/devui/theme/core/theme.ts +++ b/devui/theme/core/theme.ts @@ -1,3 +1,5 @@ +import { inBrowser } from '../../shared/util/common-var' + class Theme { static imports: any = {} @@ -15,6 +17,10 @@ class Theme { applyTheme(name: string): void { const theme = Theme.imports[name] + if (!inBrowser) { + return; + } + if (!theme) { console.error(`主题 ${theme} 未注册!`) return diff --git a/docs/.vitepress/devui-theme/components/NavBar.vue b/docs/.vitepress/devui-theme/components/NavBar.vue index e0871577..85edd242 100644 --- a/docs/.vitepress/devui-theme/components/NavBar.vue +++ b/docs/.vitepress/devui-theme/components/NavBar.vue @@ -1,14 +1,15 @@