taro 小程序主题切换生成_Text


使用

import { FC, ReactElement } from "react";
import { Container } from "../../components/BUI";

interface IProps {}

const UserProfile: FC<IProps> = (): ReactElement => {
return <Container fill>UserProfile</Container>;
};

export default UserProfile;

​ThemeTriggerSwitch​

import { styled } from "linaria/react";
import { setTabBarStyle, setNavigationBarColor } from "@tarojs/taro";
import { Switch, View } from "@tarojs/components";
import { FC, ReactElement, useCallback, useMemo } from "react";
import { ThemeMode, useTheme, LightTheme, DarkTheme } from "./BUI/theme";
import { Text } from "../components/BUI";

interface IProps {}

const ThemeTriggerSwitch: FC<IProps> = (): ReactElement => {
const [{ mode, theme }, setTheme] = useTheme();
const isLight = useMemo(() => mode === ThemeMode.LIGHT, [mode]);

const handleChangeThemeMode = useCallback(() => {
const themeState = isLight ? DarkTheme : LightTheme;
setTheme(themeState);
const { background: backgroundColor, color } = themeState.theme;
//底部导航栏一同变化
setTabBarStyle({
backgroundColor,
color,
});
//顶部导航栏也一同变化 只是当前页面 其他页还需设置
setNavigationBarColor({
backgroundColor,
frontColor: color,
});
}, [isLight, setTheme]);

return (
<Container>
<Text>{isLight ? "夜间" : "日间"}模式</Text>
<Switch color={theme.primary} checked={isLight} onChange={handleChangeThemeMode} />
</Container>
);
};

export default ThemeTriggerSwitch;

const Container = styled(View)`
display: flex;
justify-content: flex-end;
align-items: center;
`;

​app.tsx​

class App extends Component {
render() {
return (
<Provider store={store}>
<HUIProvide>{this.props.children}</HUIProvide>
</Provider>
);
}
}

​BUI/theme.tsx​

import { createContext, useContext, useState } from "react";

const darkPrimary = "#666666";
const lightPrimary = "#5511ff";
const dark = "#000000";
const light = "#ffffff";

interface ITheme {
primary: string;
button: {
color: string;
backgroundColor: string;
};
color: string;
background: string;
}

export enum ThemeMode {
DARK = "dark",
LIGHT = "light",
}

const darkTheme: ITheme = {
primary: darkPrimary,
button: {
color: light,
backgroundColor: darkPrimary,
},
color: light,
background: dark,
};

const lightTheme: ITheme = {
primary: lightPrimary,
button: {
color: light,
backgroundColor: lightPrimary,
},
color: dark,
background: light,
};

interface ThemeProps {
theme: ITheme;
mode: ThemeMode;
}

export const LightTheme: ThemeProps = {
theme: lightTheme,
mode: ThemeMode.LIGHT,
};

export const DarkTheme: ThemeProps = {
theme: darkTheme,
mode: ThemeMode.DARK,
};

const Theme = createContext(LightTheme);

const HUIProvide = ({ children }) => {
const theme = useState<ThemeProps>(LightTheme);
//@ts-ignore
return <Theme.Provider value={theme}>{children}</Theme.Provider>;
};

export const useSetTheme = () => useContext(Theme)[1];
export const useThemeState = (): ThemeProps => useContext(Theme)[0];
export const useTheme = (): [ThemeProps, React.Dispatch<React.SetStateAction<ThemeProps>>] => useContext(Theme);

export default HUIProvide;

BUI/index.tsx

import { Button } from "./Button";
import View from "./View";
import Container from "./View/Container";
import Text from "./Text";

export { Button, View, Text, Container };

组件 BUI/View/index.tsx

import { ComponentType, ReactElement } from "react";
import { ViewProps } from "@tarojs/components/types/View";
import { View as TView } from "@tarojs/components";
import { useThemeState } from "../theme";

export type IProps = ComponentType<ViewProps & { fill?: boolean }>;

const View: IProps = ({ children, fill, style, ...props }): ReactElement => {
const { theme } = useThemeState();
return (
<TView
style={{
backgroundColor: theme.background,
width: fill ? "100vw" : undefined,
height: fill ? "100vh" : undefined,
color: theme.color,
...style,
}}
{...props}
>
{children}
</TView>
);
};

export default View;

组件 BUI/View/COntainer.tsx

import { setNavigationBarColor, useDidShow } from "@tarojs/taro";
import { useThemeState } from "../theme";
import View, { IProps } from "./index";

const Container: IProps = (props) => {
const { theme } = useThemeState();

useDidShow(() => {
// 导航栏不会随主题变化只会在当前的页面生效
// 因此每个也都要统一导航栏主题
setNavigationBarColor({
backgroundColor: theme.background,
frontColor: theme.color,
});
console.log("set navigate style");
});

return <View {...props} />;
};

export default Container;

组件 BUI/Text/index.tsx

import { ComponentType, ReactElement } from "react";
import { Text as TText } from "@tarojs/components";
import { TextProps } from "@tarojs/components/types/Text";
import { useThemeState } from "../theme";

type Props = ComponentType<TextProps & { children: any; bold?: boolean }>;

const Text: Props = ({ children, style, bold, ...props }): ReactElement => {
const { theme } = useThemeState();
return (
<TText
style={{
color: theme.color,
fontWeight: bold ? "bold" : undefined,
...style,
}}
{...props}
>
{children}
</TText>
);
};

export default Text;

组件 BUI/Button/index.tsx

import { ComponentType } from "react";
import { Button as TButton, ButtonProps } from "@tarojs/components";
import { useThemeState } from "../theme";

type TButtonProps = ComponentType<ButtonProps & { width?: string; bold?: boolean }>;

export const Button: TButtonProps = ({ children, style, bold, width, ...props }) => {
const { theme } = useThemeState();

return (
<TButton
style={{
width,
color: theme.button.color,
backgroundColor: theme.button.backgroundColor,
fontWeight: bold ? "bold" : undefined,
...style,
}}
{...props}
>
{children}
</TButton>
);
};