From a1e811fe728bbf7ae10ff20ed56e1d65d2e7fbdf Mon Sep 17 00:00:00 2001 From: Y Date: Fri, 29 Mar 2024 13:40:14 +0800 Subject: [PATCH] feat(other): support ssr (#1280) --- src/action-sheet/index.ts | 4 +++- src/back-top/back-top.vue | 9 ++++++--- src/dialog/index.ts | 4 +++- src/drawer/plugin.ts | 3 ++- src/image-viewer/image-viewer.vue | 4 ++-- src/message/index.ts | 4 +++- src/picker/picker-item.vue | 3 +-- src/popup/popup.vue | 11 +++++++---- src/shared/dom.ts | 4 +++- src/shared/render-tnode.ts | 1 - src/shared/useClickAway/index.ts | 4 ++-- src/shared/useCountDown/index.ts | 2 ++ src/shared/useCountDown/utils.ts | 2 ++ src/shared/useScrollParent/index.ts | 4 ++-- src/shared/util.ts | 2 +- src/swipe-cell/useSwipe.ts | 5 +++-- src/toast/index.ts | 3 ++- 17 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/action-sheet/index.ts b/src/action-sheet/index.ts index e50dd9bb4..74d8b376c 100644 --- a/src/action-sheet/index.ts +++ b/src/action-sheet/index.ts @@ -1,6 +1,6 @@ import { createApp, DefineComponent, ref, h, VNode, App, nextTick } from 'vue'; import ActionSheetVue from './action-sheet.vue'; -import { WithInstallType } from '../shared'; +import { WithInstallType, isBrowser } from '../shared'; import './style'; import { TdActionSheetProps } from './type'; @@ -12,6 +12,8 @@ let instance: any = null; let app: App; function create(props: Partial): DefineComponent { + if (!isBrowser) return; + const root = document.createElement('div'); document.body.appendChild(root); diff --git a/src/back-top/back-top.vue b/src/back-top/back-top.vue index 5eb2e6449..9dccfe07e 100644 --- a/src/back-top/back-top.vue +++ b/src/back-top/back-top.vue @@ -10,7 +10,7 @@ import { computed, defineComponent, getCurrentInstance, h } from 'vue'; import { useElementBounding } from '@vueuse/core'; import { BacktopIcon as TIconBackTop } from 'tdesign-icons-vue-next'; -import { renderTNode, TNode } from '../shared'; +import { renderTNode, TNode, isBrowser } from '../shared'; import BackTopProps from './props'; import config from '../config'; @@ -22,6 +22,7 @@ export default defineComponent({ props: BackTopProps, setup(props, context) { const el = computed(() => { + if (!isBrowser) return undefined; return props.target ? props.target() : window.document.documentElement; }); const { top } = useElementBounding(el); @@ -43,8 +44,10 @@ export default defineComponent({ }); const clickBackBtn = () => { - window.document.documentElement.scrollTop += top.value; - props.onToTop?.(); + if (isBrowser) { + window.document.documentElement.scrollTop += top.value; + props.onToTop?.(); + } }; return { name, diff --git a/src/dialog/index.ts b/src/dialog/index.ts index 99320f354..3230a30ef 100644 --- a/src/dialog/index.ts +++ b/src/dialog/index.ts @@ -1,7 +1,7 @@ import { createApp, h, App, ref, nextTick, reactive } from 'vue'; import Dialog from './dialog.vue'; -import { WithInstallType } from '../shared'; +import { WithInstallType, isBrowser } from '../shared'; import { DialogCloseContext, TdDialogProps, DialogInstance } from './type'; import './style'; @@ -24,6 +24,8 @@ const propsFn = ['onConfirm', 'onCancel', 'onOverlayClick', 'onClose', 'onClosed type DialogPropsFnName = (typeof propsFn)[number]; function create(options: Partial | string): DialogInstance { + if (!isBrowser) return; + const root = document.createElement('div'); document.body.appendChild(root); diff --git a/src/drawer/plugin.ts b/src/drawer/plugin.ts index 2704959de..d1aec43b1 100644 --- a/src/drawer/plugin.ts +++ b/src/drawer/plugin.ts @@ -1,11 +1,12 @@ import { createApp, App, h, ref, nextTick } from 'vue'; import vueDrawer from './drawer.vue'; -import { WithInstallType } from '../shared'; +import { WithInstallType, isBrowser } from '../shared'; import { TdDrawerProps } from './type'; type DrawerOptions = Omit; const Drawer = (options: DrawerOptions) => { + if (!isBrowser) return; const root = document.createElement('div'); document.body.appendChild(root); const visible = ref(false); diff --git a/src/image-viewer/image-viewer.vue b/src/image-viewer/image-viewer.vue index bae2d70cf..7d449690d 100644 --- a/src/image-viewer/image-viewer.vue +++ b/src/image-viewer/image-viewer.vue @@ -64,7 +64,7 @@ import { CloseIcon, DeleteIcon } from 'tdesign-icons-vue-next'; import config from '../config'; import ImagediverProps from './props'; -import { renderTNode, TNode, useDefault, inBrowser, useGesture, DragState, PinchState } from '../shared'; +import { renderTNode, TNode, useDefault, isBrowser, useGesture, DragState, PinchState } from '../shared'; // inner components import { Swiper as TSwiper, SwiperItem as TSwiperItem } from '../swiper'; @@ -218,7 +218,7 @@ export default defineComponent({ const checkTap = (e: DragState) => { const { event } = e; const deltaTime = Date.now() - dragStartTime; - if (deltaTime < TAP_TIME && inBrowser) { + if (deltaTime < TAP_TIME && isBrowser) { if (dblTapTimer) { clearTimeout(dblTapTimer); dblTapTimer = window.setTimeout(() => { diff --git a/src/message/index.ts b/src/message/index.ts index 0eb7127c9..75b1ddafa 100644 --- a/src/message/index.ts +++ b/src/message/index.ts @@ -1,6 +1,6 @@ import { createApp, defineComponent, ref, h, VNode, App, nextTick } from 'vue'; import Message from './message.vue'; -import { WithInstallType } from '../shared'; +import { WithInstallType, isBrowser } from '../shared'; import { TdMessageProps, MessageThemeList } from './type'; import './style'; @@ -21,6 +21,8 @@ function destroy(context: Element, root: Element) { } function create(props: MessageActionOptionsType): void { + if (!isBrowser) return; + const { context, ...otherOptions } = props; if (!context) { diff --git a/src/picker/picker-item.vue b/src/picker/picker-item.vue index f081108fc..f83b898e0 100644 --- a/src/picker/picker-item.vue +++ b/src/picker/picker-item.vue @@ -36,8 +36,7 @@ export default defineComponent({ emits: ['pick'], setup(props, context) { let picker: Picker | null = null; - const el = document.createElement('ul'); - const root = ref(el); + const root = ref(); const getIndexByValue = (val: number | string | undefined) => { let defaultIndex = 0; if (val !== undefined) { diff --git a/src/popup/popup.vue b/src/popup/popup.vue index 07d6c3aa8..8433a3bcb 100644 --- a/src/popup/popup.vue +++ b/src/popup/popup.vue @@ -20,7 +20,7 @@ import popupProps from './props'; import TOverlay from '../overlay'; import config from '../config'; import { TdPopupProps } from './type'; -import { useDefault, TNode, renderTNode } from '../shared'; +import { useDefault, TNode, renderTNode, isBrowser } from '../shared'; import { getAttach } from '../shared/dom'; const { prefix } = config; @@ -109,7 +109,10 @@ export default defineComponent({ props.onClosed?.(); }; const afterEnter = () => props.onOpened?.(); - const to = computed(() => getAttach(props.attach ?? 'body')); + const to = computed(() => { + if (!isBrowser || !props.attach) return undefined; + return getAttach(props.attach ?? 'body'); + }); watch( () => currentVisible.value, @@ -122,7 +125,7 @@ export default defineComponent({ ); const lock = () => { - if (!lockTimes) { + if (!lockTimes && isBrowser) { document.body.classList.add(bodyLockClass); } @@ -133,7 +136,7 @@ export default defineComponent({ if (lockTimes) { lockTimes--; - if (!lockTimes) { + if (!lockTimes && isBrowser) { document.body.classList.remove(bodyLockClass); } } diff --git a/src/shared/dom.ts b/src/shared/dom.ts index e3480a422..2402b9d96 100644 --- a/src/shared/dom.ts +++ b/src/shared/dom.ts @@ -1,11 +1,13 @@ import isFunction from 'lodash/isFunction'; import isString from 'lodash/isString'; - import { AttachNode } from '../common'; +import { isBrowser } from './util'; const trim = (str: string): string => (str || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, ''); export function getAttach(node: AttachNode) { + if (!isBrowser) return; + const attachNode = isFunction(node) ? node() : node; if (isString(attachNode)) { diff --git a/src/shared/render-tnode.ts b/src/shared/render-tnode.ts index 56df86d8c..f2f109b71 100644 --- a/src/shared/render-tnode.ts +++ b/src/shared/render-tnode.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types const TNodeComponent = (props: { content: any }) => props.content; TNodeComponent.props = ['content']; export default TNodeComponent; diff --git a/src/shared/useClickAway/index.ts b/src/shared/useClickAway/index.ts index 161649afb..76e3028fd 100644 --- a/src/shared/useClickAway/index.ts +++ b/src/shared/useClickAway/index.ts @@ -1,6 +1,6 @@ import { MaybeElementRef, UnRefElementReturn, unrefElement, useEventListener } from '@vueuse/core'; import isArray from 'lodash/isArray'; -import { inBrowser } from '../util'; +import { isBrowser } from '../util'; export interface UseClickAwayOptions { /** @@ -39,7 +39,7 @@ export function useClickAway( fn: UseClickAwayHandler<{ detectIframe: T['detectIframe'] }>, options: T = {} as T, ) { - if (!inBrowser) return; + if (!isBrowser) return; const { eventName = 'touchstart', capture = true, ignore = [], detectIframe = false } = options; diff --git a/src/shared/useCountDown/index.ts b/src/shared/useCountDown/index.ts index a95d0eeef..7d28f71d9 100644 --- a/src/shared/useCountDown/index.ts +++ b/src/shared/useCountDown/index.ts @@ -2,6 +2,7 @@ import { ref, reactive } from 'vue'; import { useRafFn } from '@vueuse/core'; import { TdUseCountDownProps, TdUseCountDown } from './type'; import { getRemainTimes, getShowTimes, getScreenFps } from './utils'; +import { isBrowser } from '../util'; export function useCountDown(props: TdUseCountDownProps): TdUseCountDown { const { @@ -21,6 +22,7 @@ export function useCountDown(props: TdUseCountDownProps): TdUseCountDown { // raf const { pause, resume } = useRafFn( async () => { + if (!isBrowser) return; if (!fps.value) { const res = await getScreenFps?.(); fps.value = res || 60; diff --git a/src/shared/useCountDown/utils.ts b/src/shared/useCountDown/utils.ts index 3983988c8..54b649049 100644 --- a/src/shared/useCountDown/utils.ts +++ b/src/shared/useCountDown/utils.ts @@ -1,4 +1,5 @@ import { TimeData, TdUseCountDownShowTimes } from './type'; +import { isBrowser } from '../util'; export const TimeDataUnit = { DD: '天', @@ -111,6 +112,7 @@ export const getShowTimes = ( * @return {Promise} */ export const getScreenFps = (() => { + if (!isBrowser) return; const { requestAnimationFrame, mozRequestAnimationFrame, webkitRequestAnimationFrame } = window as any; // 先做一下兼容性处理 const nextFrame = [requestAnimationFrame, mozRequestAnimationFrame, webkitRequestAnimationFrame]?.find?.((fn) => fn); diff --git a/src/shared/useScrollParent/index.ts b/src/shared/useScrollParent/index.ts index a815eb189..79539627a 100644 --- a/src/shared/useScrollParent/index.ts +++ b/src/shared/useScrollParent/index.ts @@ -1,10 +1,10 @@ import { ref, Ref, onMounted } from 'vue'; -import { inBrowser } from '../util'; +import { isBrowser } from '../util'; type ScrollElement = HTMLElement | Window; const overflowScrollReg = /scroll|auto/i; -const defaultRoot = inBrowser ? window : undefined; +const defaultRoot = isBrowser ? window : undefined; function isElement(node: Element) { const ELEMENT_NODE_TYPE = 1; diff --git a/src/shared/util.ts b/src/shared/util.ts index ce6372ef5..1d2e2e4ac 100644 --- a/src/shared/util.ts +++ b/src/shared/util.ts @@ -7,7 +7,7 @@ export function toCamel(str: string): string { return str.replace(/^\S/, (m) => m.toUpperCase()); } -export const inBrowser = typeof window !== 'undefined'; +export const isBrowser = typeof window !== 'undefined'; /** * 计算字符串字符的长度并可以截取字符串。 diff --git a/src/swipe-cell/useSwipe.ts b/src/swipe-cell/useSwipe.ts index 020f3385f..7405c254b 100644 --- a/src/swipe-cell/useSwipe.ts +++ b/src/swipe-cell/useSwipe.ts @@ -3,6 +3,7 @@ import { computed, reactive, ref } from 'vue'; import { useEventListener } from '@vueuse/core'; import isObject from 'lodash/isObject'; import { preventDefault } from '../shared/dom'; +import { isBrowser } from '../shared'; const noop = () => {}; @@ -105,7 +106,7 @@ export function useSwipe( coordsEnd.y = y; }; - const isPassiveEventSupported = checkPassiveEventSupport(window?.document); + const isPassiveEventSupported = checkPassiveEventSupport(); const onTouchEnd = (e: TouchEvent) => { if (isSwiping.value) onSwipeEnd?.(e, direction.value); @@ -167,7 +168,7 @@ export function useSwipe( * This is a polyfill for passive event support detection * @see https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md */ -function checkPassiveEventSupport(document?: Document) { +function checkPassiveEventSupport(document = isBrowser ? window.document : undefined) { if (!document) return false; let supportsPassive = false; const optionsBlock: AddEventListenerOptions = { diff --git a/src/toast/index.ts b/src/toast/index.ts index 141f8c29d..d770546ef 100644 --- a/src/toast/index.ts +++ b/src/toast/index.ts @@ -1,7 +1,7 @@ import { createApp, App, DefineComponent } from 'vue'; import vueToast from './toast.vue'; import { TdToastProps } from './type'; -import { WithInstallType } from '../shared'; +import { WithInstallType, isBrowser } from '../shared'; import './style'; @@ -13,6 +13,7 @@ let app: App; /** 展示提示 */ function Toast(props: string | Partial): DefineComponent { + if (!isBrowser) return; const root = document.createElement('div'); document.body.appendChild(root);