|
|
@@ -0,0 +1,125 @@
|
|
|
+import { useEffect, useRef, useState } from 'react';
|
|
|
+
|
|
|
+import { calculateOptimalFontSize } from '@/utils/domUtils';
|
|
|
+
|
|
|
+interface TextSizes {
|
|
|
+ titleSize: number;
|
|
|
+ subTitleSize: number;
|
|
|
+ introduceSize: number;
|
|
|
+}
|
|
|
+
|
|
|
+interface UseActionsReturn {
|
|
|
+ containerRef: React.RefObject<HTMLDivElement>;
|
|
|
+ titleRef: React.RefObject<HTMLHeadingElement>;
|
|
|
+ subTitleRef: React.RefObject<HTMLSpanElement>;
|
|
|
+ introduceRef: React.RefObject<HTMLSpanElement>;
|
|
|
+ textSizes: TextSizes;
|
|
|
+}
|
|
|
+
|
|
|
+const DEFAULT_TITLE_SIZE = 28;
|
|
|
+const DEFAULT_SUBTITLE_SIZE = 36;
|
|
|
+const DEFAULT_INTRODUCE_SIZE = 22;
|
|
|
+const CONTAINER_PADDING = 33 * 2; // 左右 padding 总和
|
|
|
+
|
|
|
+/**
|
|
|
+ * PlanCard 响应逻辑 Hook
|
|
|
+ * 处理文本自适应大小调整
|
|
|
+ */
|
|
|
+export function useActions(
|
|
|
+ isMobile: boolean,
|
|
|
+ title: string,
|
|
|
+ subTitle: string,
|
|
|
+ introduce: string
|
|
|
+): UseActionsReturn {
|
|
|
+ const containerRef = useRef<HTMLDivElement>(null);
|
|
|
+ const titleRef = useRef<HTMLHeadingElement>(null);
|
|
|
+ const subTitleRef = useRef<HTMLSpanElement>(null);
|
|
|
+ const introduceRef = useRef<HTMLSpanElement>(null);
|
|
|
+
|
|
|
+ const [textSizes, setTextSizes] = useState<TextSizes>({
|
|
|
+ titleSize: DEFAULT_TITLE_SIZE,
|
|
|
+ subTitleSize: DEFAULT_SUBTITLE_SIZE,
|
|
|
+ introduceSize: DEFAULT_INTRODUCE_SIZE,
|
|
|
+ });
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (isMobile) {
|
|
|
+ setTextSizes({
|
|
|
+ titleSize: DEFAULT_TITLE_SIZE,
|
|
|
+ subTitleSize: DEFAULT_SUBTITLE_SIZE,
|
|
|
+ introduceSize: DEFAULT_INTRODUCE_SIZE,
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const container = containerRef.current;
|
|
|
+ const titleEl = titleRef.current;
|
|
|
+ const subTitleEl = subTitleRef.current;
|
|
|
+ const introduceEl = introduceRef.current;
|
|
|
+
|
|
|
+ if (!container || !titleEl || !subTitleEl || !introduceEl) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const calculateOptimalSizes = () => {
|
|
|
+ const containerWidth = container.offsetWidth;
|
|
|
+ const availableWidth = containerWidth - CONTAINER_PADDING;
|
|
|
+
|
|
|
+ if (availableWidth <= 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const newTitleSize = calculateOptimalFontSize({
|
|
|
+ element: titleEl,
|
|
|
+ text: title,
|
|
|
+ defaultSize: DEFAULT_TITLE_SIZE,
|
|
|
+ availableWidth,
|
|
|
+ });
|
|
|
+
|
|
|
+ const newSubTitleSize = calculateOptimalFontSize({
|
|
|
+ element: subTitleEl,
|
|
|
+ text: subTitle,
|
|
|
+ defaultSize: DEFAULT_SUBTITLE_SIZE,
|
|
|
+ availableWidth,
|
|
|
+ });
|
|
|
+
|
|
|
+ const newIntroduceSize = calculateOptimalFontSize({
|
|
|
+ element: introduceEl,
|
|
|
+ text: introduce,
|
|
|
+ defaultSize: DEFAULT_INTRODUCE_SIZE,
|
|
|
+ availableWidth,
|
|
|
+ });
|
|
|
+
|
|
|
+ setTextSizes({
|
|
|
+ titleSize: newTitleSize,
|
|
|
+ subTitleSize: newSubTitleSize,
|
|
|
+ introduceSize: newIntroduceSize,
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const resizeObserver = new ResizeObserver(() => {
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ calculateOptimalSizes();
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ resizeObserver.observe(container);
|
|
|
+ resizeObserver.observe(titleEl);
|
|
|
+ resizeObserver.observe(subTitleEl);
|
|
|
+ resizeObserver.observe(introduceEl);
|
|
|
+
|
|
|
+ calculateOptimalSizes();
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ resizeObserver.disconnect();
|
|
|
+ };
|
|
|
+ }, [isMobile, title, subTitle, introduce]);
|
|
|
+
|
|
|
+ return {
|
|
|
+ containerRef,
|
|
|
+ titleRef,
|
|
|
+ subTitleRef,
|
|
|
+ introduceRef,
|
|
|
+ textSizes,
|
|
|
+ };
|
|
|
+}
|