Ver código fonte

feat: 购买页面

BaiLuoYan 3 meses atrás
pai
commit
955a4b88d3

+ 10 - 5
src/pages/pricing/index.tsx

@@ -1,4 +1,4 @@
-import { memo } from 'react';
+import { memo, useRef } from 'react';
 
 import { useTranslation } from 'react-i18next';
 
@@ -9,11 +9,13 @@ import PayMethodCard from './components/PayMethodCard';
 import PlanCard from './components/PlanCard';
 import UserInfo from './components/UserInfo';
 import { useAction } from './useAction';
+import { usePlanCardsHeightSync } from './usePlanCardsHeightSync';
 import { useService } from './useService';
 
 const Pricing = memo(() => {
     const { t } = useTranslation();
     const { isMobile } = useResponsive();
+    const planCardsContainerRef = useRef<HTMLDivElement>(null);
     const { selectedPlanId, handlePlanClick, selectedPayMethod, handlePayMethodClick } =
         useAction();
 
@@ -21,6 +23,8 @@ const Pricing = memo(() => {
 
     const selectedPlan = plans.find((plan) => plan.id === selectedPlanId) || null;
 
+    usePlanCardsHeightSync(planCardsContainerRef, isMobile, plans.length);
+
     return (
         <div className="flex items-start justify-center">
             <div className={`max-w-[1440px] w-full ${isMobile ? 'px-0' : 'px-[30px]'}`}>
@@ -40,10 +44,11 @@ const Pricing = memo(() => {
                             {t('pages.pricing.selecPlan')}
                         </span>
                         <div
+                            ref={planCardsContainerRef}
                             className={
                                 isMobile
                                     ? 'flex-col-c gap-5'
-                                    : 'flex flex-wrap justify-start gap-x-8 gap-y-4 [&>*]:flex-[1_1_calc(25%-1.5rem)]'
+                                    : 'flex flex-wrap justify-start gap-x-8 gap-y-4 [&>*]:flex-[1_1_calc(25%-1.5rem)] [&>*]:max-w-[calc(25%-1.5rem)]'
                             }
                         >
                             {plans.map((plan) => (
@@ -61,7 +66,7 @@ const Pricing = memo(() => {
                             ))}
                         </div>
                     </div>
-                    <div className="flex flex-col gap-5">
+                    <div className="flex flex-col gap-4 mt-1">
                         <span
                             className={`text-white font-semibold leading-[1.43] ${isMobile ? 'text-[16px]' : 'text-[22px]'}`}
                         >
@@ -70,8 +75,8 @@ const Pricing = memo(() => {
                         <div
                             className={
                                 isMobile
-                                    ? 'flex-col-c gap-5'
-                                    : 'flex flex-wrap justify-start gap-x-8 gap-y-4 [&>*]:flex-[1_1_calc(50%-1rem)]'
+                                    ? 'flex-col-c gap-4'
+                                    : 'flex flex-wrap justify-start gap-x-8 gap-y-4 [&>*]:flex-[1_1_calc(50%-1rem)] [&>*]:max-w-[calc(50%-1rem)]'
                             }
                         >
                             {payMethods.map((payMethod) => (

+ 45 - 0
src/pages/pricing/usePlanCardsHeightSync.ts

@@ -0,0 +1,45 @@
+import { useEffect, RefObject } from 'react';
+
+function syncPlanCardsHeight(container: HTMLDivElement | null) {
+    if (!container) return;
+    const children = Array.from(container.children) as HTMLElement[];
+    if (children.length === 0) return;
+    const maxHeight = Math.max(...children.map((el) => el.offsetHeight));
+    children.forEach((el) => {
+        el.style.minHeight = `${maxHeight}px`;
+    });
+}
+
+export function usePlanCardsHeightSync(
+    containerRef: RefObject<HTMLDivElement | null>,
+    isMobile: boolean,
+    plansLength: number
+) {
+    useEffect(() => {
+        const container = containerRef.current;
+        const cancelled = { current: false };
+        const clearMinHeight = () => {
+            Array.from(container?.children ?? []).forEach((el) => {
+                (el as HTMLElement).style.minHeight = '';
+            });
+        };
+        if (isMobile) {
+            clearMinHeight();
+            return () => clearMinHeight();
+        }
+        const run = () => {
+            requestAnimationFrame(() => {
+                if (cancelled.current) return;
+                syncPlanCardsHeight(container);
+            });
+        };
+        run();
+        const observer = new ResizeObserver(run);
+        if (container) observer.observe(container);
+        return () => {
+            cancelled.current = true;
+            clearMinHeight();
+            observer.disconnect();
+        };
+    }, [isMobile, plansLength]);
+}

+ 8 - 0
src/pages/pricing/useService.ts

@@ -55,6 +55,14 @@ export function useService(): UseServiceReturn {
                 tag: '无优惠',
                 tagType: PlanTagType.NONE,
                 price: 1.99,
+            },            {
+                id: 5,
+                title: '7天',
+                subTitle: 'USD 1.99',
+                introduce: '折合 USD 0.28/天',
+                tag: '无优惠',
+                tagType: PlanTagType.NONE,
+                price: 1.99,
             },
         ],
         []