Skip to content

Commit c198076

Browse files
committed
fixed querySelector first not attached issue
1 parent 3373348 commit c198076

File tree

8 files changed

+63
-9
lines changed

8 files changed

+63
-9
lines changed

src/features/jimaku/components/ButtonArea.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { toast } from "sonner/dist";
1212
import { sendMessager } from "~utils/messaging";
1313
import { sendForward } from "~background/forwards";
1414
import { sleep } from "~utils/misc";
15+
import { useQuerySelector } from "~hooks/dom";
1516

1617
export type ButtonAreaProps = {
1718
clearJimaku: VoidFunction
@@ -50,6 +51,11 @@ function ButtonArea({ clearJimaku, jimakus }: ButtonAreaProps): JSX.Element {
5051
sendForward('pages', 'jimaku-summarize', { roomId: info.room, jimakus: jimakus.map(j => j.text) })
5152
}
5253

54+
const upperHeaderAreaElement = useQuerySelector(upperHeaderArea)
55+
if (info.isTheme && upperHeaderAreaElement === null) {
56+
console.warn(`找不到上方标题界面元素 ${upperHeaderArea},可能无法插入切換按鈕列表的按钮`)
57+
}
58+
5359
return (
5460
<Fragment>
5561
{show && (
@@ -80,11 +86,11 @@ function ButtonArea({ clearJimaku, jimakus }: ButtonAreaProps): JSX.Element {
8086
)}
8187
</div>
8288
)}
83-
{info.isTheme && document.querySelector(upperHeaderArea) !== null && createPortal(
89+
{info.isTheme && upperHeaderAreaElement !== null && createPortal(
8490
<TailwindScope>
8591
<ButtonSwitchList switched={show} onClick={() => setShow(!show)} />
8692
</TailwindScope>,
87-
document.querySelector(upperHeaderArea)
93+
upperHeaderAreaElement
8894
)}
8995
</Fragment>
9096
)

src/features/jimaku/components/JimakuList.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type React from "react";
22
import { Item, Menu, useContextMenu, type ItemParams } from 'react-contexify';
33
import { toast } from 'sonner/dist';
4-
import { useKeepBottom } from '~hooks/keep-bottom';
4+
import { useKeepBottom } from '~hooks/dom';
55
import { useScrollOptimizer } from '~hooks/optimizer';
66
import { getSettingStorage, setSettingStorage } from '~utils/storage';
77

src/features/jimaku/components/JimakuVisibleButton.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createPortal } from 'react-dom'
22
import styled from '@emotion/styled'
33
import type { SettingSchema } from "~options/fragments/developer"
4+
import { useQuerySelector } from "~hooks/dom"
45

56
export type JimakuVisibleButtonProps = {
67
toggle: VoidFunction
@@ -21,7 +22,7 @@ const Div = styled.div`
2122

2223
function JimakuVisibleButton({ toggle, visible, dev }: JimakuVisibleButtonProps): JSX.Element {
2324

24-
const element = document.querySelector(dev.elements.upperInputArea)
25+
const element = useQuerySelector(dev.elements.upperInputArea)
2526
if (!element) {
2627
console.warn(`找不到元素 ${dev.elements.upperInputArea},部分功能可能无法正常工作`)
2728
return null

src/features/jimaku/index.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { FeatureHookRender } from "..";
1414
import JimakuCaptureLayer from './components/JimakuCaptureLayer';
1515
import JimakuAreaSkeleton from './components/JimakuAreaSkeleton';
1616
import JimakuAreaSkeletonError from './components/JimakuAreaSkeletonError';
17+
import { useQuerySelector } from "~hooks/dom";
1718

1819

1920

@@ -35,7 +36,7 @@ export function App(): JSX.Element {
3536

3637
const dev = settings['settings.developer']
3738

38-
const danmakuArea = document.querySelector(dev.elements.danmakuArea)
39+
const danmakuArea = useQuerySelector(dev.elements.danmakuArea)
3940
if (!danmakuArea) {
4041
toast.warning(`找不到弹幕区域 ${dev.elements.danmakuArea},部分功能可能无法正常工作`)
4142
}

src/features/recorder/components/RecorderButton.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useContext, useState, type MutableRefObject } from "react"
44
import TailwindScope from "~components/TailwindScope"
55
import ContentContext from "~contexts/ContentContexts"
66
import RecorderFeatureContext from "~contexts/RecorderFeatureContext"
7+
import { useQuerySelector } from "~hooks/dom"
78
import { useForceRender } from "~hooks/force-update"
89
import { useComputedStyle, useContrast } from "~hooks/styles"
910
import type { Recorder } from "~types/media"
@@ -25,7 +26,7 @@ function RecorderButton(props: RecorderButtonProps): JSX.Element {
2526
const [recording, setRecording] = useState(false)
2627
const update = useForceRender()
2728
const { headInfoArea } = settings['settings.developer'].elements
28-
const { backgroundImage } = useComputedStyle(document.querySelector(headInfoArea))
29+
const { backgroundImage } = useComputedStyle(useQuerySelector(headInfoArea))
2930

3031
useInterval(() => {
3132
if (!recorder.current) return

src/features/recorder/components/RecorderLayer.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { randomString } from '~utils/misc'
1616
import createRecorder from "../recorders"
1717
import ProgressText from "./ProgressText"
1818
import RecorderButton from "./RecorderButton"
19+
import { useQuerySelector } from "~hooks/dom"
1920

2021
export type RecorderLayerProps = {
2122
urls: StreamUrls
@@ -202,7 +203,11 @@ function RecorderLayer(props: RecorderLayerProps): JSX.Element {
202203
screenshot()
203204
})
204205

205-
if (hiddenUI || document.querySelector(upperHeaderArea) === null) {
206+
const upperHeaderAreaElement = useQuerySelector(upperHeaderArea)
207+
if (hiddenUI || upperHeaderAreaElement === null) {
208+
if (!hiddenUI) {
209+
console.warn(upperHeaderArea, 'is not attached yet')
210+
}
206211
return null
207212
}
208213

@@ -212,7 +217,7 @@ function RecorderLayer(props: RecorderLayerProps): JSX.Element {
212217
record={clipRecord}
213218
screenshot={screenshot}
214219
/>,
215-
document.querySelector(upperHeaderArea)
220+
upperHeaderAreaElement
216221
)
217222

218223
}

src/hooks/keep-bottom.ts src/hooks/dom.ts

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useInterval } from "@react-hooks-library/core"
12
import { useCallback, useEffect, useRef, useState } from 'react'
23

34
/**
@@ -57,4 +58,43 @@ export function useKeepBottom<E extends HTMLElement>(enabled: boolean, calculate
5758
}, [])
5859

5960
return { ref: refCallback, element: ref, keepBottom }
61+
}
62+
63+
64+
65+
66+
/**
67+
* Custom hook that queries the DOM for an element matching the given selector.
68+
* Optionally, it can remount and re-query the DOM at a specified interval.
69+
*
70+
* @param {string} selector - The CSS selector to query the DOM.
71+
* @param {boolean} [remount=false] - If true, the hook will re-query the DOM at the specified interval.
72+
* @returns {Element | null} - The DOM element matching the selector, or null if no element is found.
73+
*
74+
* @example
75+
* // Usage in a React component
76+
* const MyComponent = () => {
77+
* const element = useQuerySelector('#my-element', true);
78+
*
79+
* useEffect(() => {
80+
* if (element) {
81+
* console.log('Element found:', element);
82+
* }
83+
* }, [element]);
84+
*
85+
* return <div>Check the console for the element.</div>;
86+
* };
87+
*/
88+
export function useQuerySelector<E extends Element>(selector: string, remount: boolean = false): E | null {
89+
90+
const [element, setElement] = useState<Element | null>(document.querySelector(selector))
91+
92+
useInterval(() => {
93+
const el = document.querySelector(selector)
94+
if (el) {
95+
setElement(el)
96+
}
97+
}, 500, { paused: !remount && !!element, immediate: true })
98+
99+
return element as E
60100
}

src/hooks/styles.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useMemo } from "react";
22

33

44
export function useComputedStyle(element: Element): CSSStyleDeclaration {
5-
return useMemo(() => window.getComputedStyle(element), [element]);
5+
return useMemo(() => element ? window.getComputedStyle(element) : {} as CSSStyleDeclaration, [element]);
66
}
77

88
export function useContrast(background: Element) {

0 commit comments

Comments
 (0)