2025-11-05 15:59:53 +08:00

150 lines
3.5 KiB
TypeScript

import { headerModel } from "@/model/header.model";
import {
View,
Text,
ScrollView,
CommonEventFunction,
} from "@tarojs/components";
import Taro from "@tarojs/taro";
import { clsx } from "clsx";
import { FC, memo, PropsWithChildren } from "react";
import { useRecoilValue } from "recoil";
import type { loadMoreConfig, refresherConfig } from "./hooks";
const PageLoader = memo(() => {
return (
<View className="h-screen w-screen flex items-center justify-center bg-red-500 text-white">
<Text>Loading...</Text>
</View>
);
});
interface LayoutHeaderProps {
className?: string;
hideBack?: boolean;
}
// 自定义导航栏
const LayoutHeader = memo(
({
className,
hideBack = true,
children,
}: PropsWithChildren<LayoutHeaderProps>) => {
const header = useRecoilValue(headerModel);
const capsStyles = {
width: `${header.capsuleWidth}px`,
height: `${header.capsuleHeight}px`,
};
const handlerBack = () => {
Taro.navigateBack();
};
return (
<View className={className}>
<View style={{ height: `${header.statusBar}px` }}></View>
<View
className="flex flex-row items-center"
style={{ height: `${header.customBar}px` }}
>
<View
className="flex items-center"
style={{
...capsStyles,
marginLeft: `${header.capsulePadding}px`,
}}
>
{hideBack ? (
<View
className="h-full aspect-square pl-[5px] flex justify-center items-center"
onClick={handlerBack}
>
<Text></Text>
</View>
) : null}
</View>
<View className="flex-1 flex justify-center items-center truncate w-full">
{children}
</View>
<View
style={{ ...capsStyles, marginRight: `${header.capsulePadding}px` }}
></View>
</View>
</View>
);
},
);
interface LayoutContainerProps {
className?: string;
refresherConfig?: refresherConfig;
refresherEnabled?: boolean;
loadMore?: loadMoreConfig;
onScroll?: CommonEventFunction;
}
// 页面容器
const LayoutContainer = memo(
({
className,
refresherConfig,
loadMore,
onScroll,
children,
}: PropsWithChildren<LayoutContainerProps>) => {
return (
<ScrollView
className={clsx("flex-1 overflow-hidden", className)}
scrollY
{...(refresherConfig ?? {})}
{...(loadMore ?? {})}
scrollWithAnimation
enableFlex
onScroll={onScroll}
>
{children}
</ScrollView>
);
},
);
// 自定义页脚
const LayoutFooter = memo(({ children }: PropsWithChildren) => {
return (
<View className="h-[150px] bg-green-500 text-white flex items-center justify-center">
{children}
</View>
);
});
interface LayoutProps {
loadding: boolean;
}
interface LayoutComponent extends FC<PropsWithChildren<LayoutProps>> {
Header: FC<PropsWithChildren<LayoutHeaderProps>>;
Footer: FC<PropsWithChildren>;
Container: FC<PropsWithChildren<LayoutContainerProps>>;
}
const LayoutBase = ({
children,
loadding = true,
}: PropsWithChildren<LayoutProps>) => {
if (loadding) {
return <PageLoader></PageLoader>;
}
return <View className="h-screen w-screen flex flex-col">{children}</View>;
};
const Layout = LayoutBase as unknown as LayoutComponent;
Layout.Header = LayoutHeader;
Layout.Container = LayoutContainer;
Layout.Footer = LayoutFooter;
export default Layout;