diff --git a/devui/anchor/index.ts b/devui/anchor/index.ts index 3df6a901d6e4e5fff5864f8a5273893ebdcc231c..99bd1f054549fab3b4cc4c834a1fb589087de8ac 100644 --- a/devui/anchor/index.ts +++ b/devui/anchor/index.ts @@ -5,20 +5,10 @@ import dAnchorLink from './src/d-anchor-link' import dAnchor from './src/d-anchor' import './src/anchor.scss'; -const directives = { - 'd-anchor': dAnchor, - 'd-anchor-link': dAnchorLink, - 'd-anchor-box': dAnchorBox, - -}; - Anchor.install = function(Vue: App) { - for (const key in directives) { - if (directives.hasOwnProperty(key)) { - - Vue.directive(key, directives[key]); - } - } + Vue.directive(dAnchor.name, dAnchor); + Vue.directive(dAnchorLink.name, dAnchorLink); + Vue.directive(dAnchorBox.name, dAnchorBox); Vue.component(Anchor.name, Anchor) }; diff --git a/devui/anchor/src/d-anchor-box.ts b/devui/anchor/src/d-anchor-box.ts index a9396cd29ea679e467e9d868d77f3ad8344950ae..0ad8a390bc72f553fdc35577e14d0ebd1966eccf 100644 --- a/devui/anchor/src/d-anchor-box.ts +++ b/devui/anchor/src/d-anchor-box.ts @@ -1,5 +1,7 @@ import { setActiveLink, onScroll, randomId } from './util'; +import { inBrowser } from '../../shared/util/common-var'; export default { + name: 'd-anchor-box', // 滚动区域 // 1.监听window滚动或滚动容器滚动,切换link+active,改变# mounted(el: HTMLElement): void { @@ -84,7 +86,7 @@ const cssChange = ( mysidebar.style.left = left + 'px'; }; const addEvent = (function () { - if (window.addEventListener) { + if (inBrowser && window.addEventListener) { return function (elm, type, handle) { elm.addEventListener(type, handle, false); }; diff --git a/devui/anchor/src/d-anchor-link.ts b/devui/anchor/src/d-anchor-link.ts index b4ad15c477885a211ce6f2663ce37e47dd0c6bfb..743106942d1fc6829b6b9dca1cdf1750ac71d493 100644 --- a/devui/anchor/src/d-anchor-link.ts +++ b/devui/anchor/src/d-anchor-link.ts @@ -4,27 +4,28 @@ interface Bind { } export default { - // 当被绑定的元素挂载到 DOM 中时…… - // 1.点击滚动到对应位置,并且高亮 - // 2.到对应位置后,改变url后hash + name: 'd-anchor-link', + // 当被绑定的元素挂载到 DOM 中时…… + // 1.点击滚动到对应位置,并且高亮 + // 2.到对应位置后,改变url后hash - mounted(el: HTMLElement,binding: Bind):void { - const parent: Element = el.parentNode as Element; - if (!parent.className) { - parent.className = 'mysidebar step-nav'; - } - el.className = 'bar-link-item'; - el.innerHTML += ''; - el.setAttribute('id', binding.value); - - el.onclick = () => { - let scrollContainer: any; - const scollToDomY = document.getElementsByName(binding.value)[0]; - document.getElementsByClassName('scrollTarget').length - ? scrollContainer = document.getElementsByClassName('scrollTarget')[0] - : scrollContainer = window - scrollToControl(scollToDomY, scrollContainer); - - } + mounted(el: HTMLElement,binding: Bind):void { + const parent: Element = el.parentNode as Element; + if (!parent.className) { + parent.className = 'mysidebar step-nav'; } - }; + el.className = 'bar-link-item'; + el.innerHTML += ''; + el.setAttribute('id', binding.value); + + el.onclick = () => { + let scrollContainer: any; + const scollToDomY = document.getElementsByName(binding.value)[0]; + document.getElementsByClassName('scrollTarget').length + ? scrollContainer = document.getElementsByClassName('scrollTarget')[0] + : scrollContainer = window + scrollToControl(scollToDomY, scrollContainer); + + } + } +}; diff --git a/devui/anchor/src/d-anchor.ts b/devui/anchor/src/d-anchor.ts index 8f6d01c3aafb32103e393062686cf10a13fd1ca4..5f76e8ced1012c4f3f02096e5be54e79eb27b6de 100644 --- a/devui/anchor/src/d-anchor.ts +++ b/devui/anchor/src/d-anchor.ts @@ -4,27 +4,28 @@ interface Bind { } export default { - // 挂载事件到dom - // 1.点击对应link高亮 - // 2.href+#+bing.value + name: 'd-anchor', + // 挂载事件到dom + // 1.点击对应link高亮 + // 2.href+#+bing.value - mounted(el: HTMLElement, binding: Bind):void { - const parent: Element = el.parentNode as Element; - if (!parent.className) { - parent.className = 'mycontent' - } - el.innerHTML = '' + el.innerHTML - el.className = 'section-block'; - // anchor-active-by-scroll - el.setAttribute('name',binding.value); - el.onclick = e => { - hightLightFn(binding.value); - - const classList = document.getElementById((e.target as HTMLElement).getAttribute('name')).classList; - console.log(classList) - - } + mounted(el: HTMLElement, binding: Bind):void { + const parent: Element = el.parentNode as Element; + if (!parent.className) { + parent.className = 'mycontent' } - }; + el.innerHTML = '' + el.innerHTML + el.className = 'section-block'; + // anchor-active-by-scroll + el.setAttribute('name',binding.value); + el.onclick = e => { + hightLightFn(binding.value); + + const classList = document.getElementById((e.target as HTMLElement).getAttribute('name')).classList; + console.log(classList) + + } + } +}; \ No newline at end of file diff --git a/devui/anchor/src/util.ts b/devui/anchor/src/util.ts index ec4c8ee73c04d55d374e22540dad67d8663045f9..868446b36c41b81e945e1166745a1ac8579876e9 100644 --- a/devui/anchor/src/util.ts +++ b/devui/anchor/src/util.ts @@ -4,7 +4,7 @@ const timeoutIntervalSpeed = 10; let hashName:string; // 滚动是由于点击产生 let scollFlag = false; -function elementPosition(obj: HTMLElement ) { +function elementPosition(obj: HTMLElement) { let curleft = 0, curtop = 0; curleft = obj.offsetLeft; curtop = obj.offsetTop; @@ -12,46 +12,44 @@ function elementPosition(obj: HTMLElement ) { } export function scrollToControl(elem: HTMLElement, container: HTMLElement):void { - hashName = elem.getAttribute('name'); - scollFlag = true; - const tops = container.scrollTop>=0 ? container.scrollTop : -(document.getElementsByClassName('mycontainer')[0] as HTMLElement).offsetTop; - let scrollPos: number = elementPosition(elem).y - tops ; - - scrollPos = scrollPos - document.documentElement.scrollTop; - const remainder: number = scrollPos % timeoutIntervalSpeed; - const repeatTimes = Math.abs((scrollPos - remainder) / timeoutIntervalSpeed); - if (scrollPos < 0 && container || elem.getBoundingClientRect().top < container.offsetTop) { - window.scrollBy(0, elem.getBoundingClientRect().top-container.offsetTop-16) - } - // 多个计时器达到平滑滚动效果 - scrollSmoothly(scrollPos, repeatTimes, container) + hashName = elem.getAttribute('name'); + scollFlag = true; + const tops = container.scrollTop>=0 ? container.scrollTop : -(document.getElementsByClassName('mycontainer')[0] as HTMLElement).offsetTop; + let scrollPos: number = elementPosition(elem).y - tops ; + + scrollPos = scrollPos - document.documentElement.scrollTop; + const remainder: number = scrollPos % timeoutIntervalSpeed; + const repeatTimes = Math.abs((scrollPos - remainder) / timeoutIntervalSpeed); + if (scrollPos < 0 && container || elem.getBoundingClientRect().top < container.offsetTop) { + window.scrollBy(0, elem.getBoundingClientRect().top-container.offsetTop-16) + } + // 多个计时器达到平滑滚动效果 + scrollSmoothly(scrollPos, repeatTimes, container) } function scrollSmoothly(scrollPos: number, repeatTimes: number, container: HTMLElement):void { - - if (repeatCount <= repeatTimes) { - scrollPos > 0 - ? container.scrollBy(0, timeoutIntervalSpeed) - : container.scrollBy(0, -timeoutIntervalSpeed) - } - else { - repeatCount = 0; - clearTimeout(cTimeout); - history.replaceState(null, null, document.location.pathname + '#' + hashName); - - hightLightFn(hashName) - setTimeout(() => { - scollFlag = false; - }, 310) - return ; - - } - repeatCount++; - cTimeout = setTimeout(() => { - scrollSmoothly(scrollPos, repeatTimes, container) - }, 10) + if (repeatCount <= repeatTimes) { + scrollPos > 0 + ? container.scrollBy(0, timeoutIntervalSpeed) + : container.scrollBy(0, -timeoutIntervalSpeed) + } + else { + repeatCount = 0; + clearTimeout(cTimeout); + history.replaceState(null, null, document.location.pathname + '#' + hashName); + hightLightFn(hashName) + setTimeout(() => { + scollFlag = false; + }, 310) + return ; + + } + repeatCount++; + cTimeout = setTimeout(() => { + scrollSmoothly(scrollPos, repeatTimes, container) + }, 10) } // 高亮切换 diff --git a/devui/modal/index.ts b/devui/modal/index.ts index f324c5d93ca4aa857ce61de342fb8505b3597315..4c28caa116072f2125a034f9682f9f39d9976e4e 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 e5a97c08ab92f1925f228ee0fd33079862f07f5e..978cc5e3b26eb4a8475958f2b9e920aefb14f289 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 7e8c34d7d9f22a6a9b801945935c8c2ace1677ca..262253e8f273a532e2f8ce789eb87d3f22a9e70a 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 b6b6ad81d252cbe8b0361a4ff2525d6f0b757801..18be40209900771d9e34b0db2d397f6654b2a1ca 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 0000000000000000000000000000000000000000..a8ba4f7e34c274e4f0ebaf7b61b9ff990f7ee093 --- /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 bdd0fd45d14fe01fab498353cd78aea0520ccf7a..95d733e7cdaa01f041b2d3ab456c02efd502e628 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 2b37e404e64d34f6280ffdd976ef47b198dba96e..a21bfd182c219617ceb9883b6d325fc8223a9c57 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 e08715772a8115a4d9dc7e31f0763e9f97f176ce..85edd242046f47d09751b8362e65db0cc7370d82 100644 --- a/docs/.vitepress/devui-theme/components/NavBar.vue +++ b/docs/.vitepress/devui-theme/components/NavBar.vue @@ -1,14 +1,15 @@