React + Tailwind css V4:从零实现流动态主题配置与切换
1.项目初始化
首先,我们用vite搭建一个 React 项目,并安装 Tailwind CSS
npm create vite@latest my-theme-app --template react
cd my-theme-app
npm install
npm install tailwindcss @tailwindcss/vite
然后,在 vite.config.js 中添加tailwind配置
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
由于版本4不需要config配置文件,但是导致编辑器会没有代码提示,所以复制一个版本3里面的tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
tailwind4
样式引入
//index.css
@import "tailwindcss";
//主题样式 配置。。。
2.主题切换逻辑
删除多余代码 留个React svg
表当作 切换的 Btn
创建一个ThemeProvider
组件来管理深浅色模式,包裹App组件
import { ThemeProvider } from './ThemeProvider.js'
createRoot(document.getElementById('root')).render(
<StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</StrictMode>,
)
补充 App
组件,样式如下
import reactLogo from './assets/react.svg'
import { useTheme } from "./ThemeProvider";
function App() {
const { theme, setTheme } = useTheme();
return (
<main className='w-screen h-screen flex flex-col items-center justify-center '>
<h1 className={`text-2xl`}>Vite + React</h1>
<a href="#" onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</main>
)
}
export default App
此时 在浏览器中点击react图标 F12查看 html标签的css类 会切换dark/light
坚持一下 马上就要成功了!!!
3. 主题适配样式
@import 'tailwindcss';
* {
padding: 0;
margin: 0;
}
@theme {
--color-theme-bg: var(--color-bg);
--color-theme-text: var(--color-text);
}
@custom-variant dark (&:where(.dark, .dark *));
@custom-variant light (&:where(.light, .light *));
@layer base {
.light {
--color-bg: #edf2ee;
--color-text: #171717;
}
.dark {
--color-bg: #171717;
--color-text: #edf2ee;
}
}
颜色配置完 ,记得补充App组件
// ... 表示忽略部分
<main className='... bg-theme-bg'>
<h1 className={`... text-theme-text`}>Vite + React</h1>
成功了 , 黑白主题风!
发布第二天!! 发现忘记给 provider 代码 !!自己封装一个最简单的ThemeProvider
ThemeProvider
import React, { createContext, useContext, useEffect, useState } from "react";
interface ThemeContextType {
theme: string;
setTheme: (theme: string) => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
const storedTheme =
typeof window !== "undefined" ? localStorage.getItem("theme") : null;
const systemPrefersDark =
typeof window !== "undefined" &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
const [theme, setThemeState] = useState<string>(
storedTheme || (systemPrefersDark ? "dark" : "light")
);
useEffect(() => {
document.documentElement.classList.remove("light", "dark");
document.documentElement.classList.add(theme);
localStorage.setItem("theme", theme);
}, [theme]);
const setTheme = (newTheme: string) => {
setThemeState(newTheme);
};
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};