Tailwind CSS实战:构建仿ChatGPT聊天页面(失败了)
通过这个简单的示例,我们使用Tailwind CSS实现了仿ChatGPT的聊天界面。Tailwind CSS的实用类使我们能够快速构建响应式UI,而Zustand则提供了简洁的状态管理。使用Tailwind的实用类快速构建UI通过Zustand管理应用状态使用假接口模拟后端交互确保界面在不同设备上的响应式体验这个项目是学习Tailwind CSS和现代前端开发模式的绝佳起点。随着你对Tailwi
参考文章:https://nextjs.org/docs/app/getting-started/css#tailwind-css
参考文章:How to install Tailwind CSS v3 in your Next.js application
注意:
- globals.css只能放在app/globals.css 或 src/styles/globals.css 这类约定俗成的位置,保持路径清晰;移动后别忘了更新 layout.tsx 里的 import。
- layout.tsx也只能放在以下位置之一(取决于项目配置):app/layout.tsx、src/app/layout.tsx
文章目录
- 1. 环境准备
- 2. 项目结构
- 3. 设置Tailwind CSS
- 4. 创建状态管理(Zustand)(尴尬,语法看不太懂,回头再研究,先把代码跑通😳)(src/store/chatStore.ts)
- 5. 实现聊天消息组件(src/components/Chat/Message.tsx)
- 6. 实现消息列表组件(src/components/Chat/MessageList.tsx)
- 7. 实现输入框组件(看不太懂代码,先跑通)(src/components/InputBox.tsx)
- 8. 创建主页面(src/app/page.tsx)
- 9. 添加全局样式(src/app/globals.css)
- 10. 运行项目
- 11. 代码解释
- 12. 扩展建议
- 13. 总结
- 14. 最终效果
- 15. 下一步学习
在现代前端开发中,Tailwind CSS凭借其实用类(utility classes)和高度可定制性,成为了构建响应式UI的热门选择。今天,我将带你一步步使用Tailwind CSS、React、TypeScript、Next.js和Zustand,实现一个仿ChatGPT的聊天界面。我们将使用假接口模拟后端交互,专注于前端实现。
1. 环境准备
首先,创建一个新的Next.js项目:
npx create-next-app@latest chatgpt-clone --typescript --tailwind --eslint --src-dir --app --import-alias "@/*"
命令解释:npx create-next-app@latest 是Next.js官方提供的脚手架命令,用于快速创建Next.js项目。--typescript 表示使用TypeScript,--tailwind 表示集成Tailwind CSS,--eslint 表示集成ESLint,--src-dir 表示将源代码放在src目录下,--app 表示使用App Router,--import-alias "@/*" 表示设置路径别名。

cd chatgpt-clone
命令解释:cd 是切换当前工作目录的命令,进入刚刚创建的项目目录。
npm install zustand
命令解释:npm install 是安装Node.js包的命令。这里安装了Zustand状态管理库。
注意:
@types/zustand已被弃用:
zustand 库从 v4.0.0 开始(2022 年)将类型定义直接打包到主包中(zustand 包内包含 index.d.ts)。 因此,无需单独安装@types/zustand,npm 官方仓库已移除该包。
2. 项目结构
我们的项目结构将如下:
src/
├── app/
│ ├── layout.tsx
│ ├── page.tsx
├── components/
│ ├── Chat/
│ │ ├── Message.tsx
│ │ └── MessageList.tsx
│ └── InputBox.tsx
├── store/
│ └── chatStore.ts
└── styles/
└── globals.css
3. 设置Tailwind CSS
Add the PostCSS plugin to your postcss.config.mjs file:
export default {
plugins: {
'@tailwindcss/postcss': {},
},
}
参考文章:PostCSS介绍(一个用JavaScript工具和插件生态系统来转换CSS代码的工具)CSS后处理器,用于支持Tailwind CSS

我打开文件看,似乎已经配置好了?(虽然语法不太一样)
Import Tailwind in your global CSS file:
在src/app/globals.css中增加:
@import 'tailwindcss';

好像已经加了,懵,跟官方给的有点不一样,我是通过create-next-app工具装的,可能有所不同。
Import the CSS file in your root layout:
将以下内容添加到app/layout.tsx:
import './globals.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
似乎也已经添加了,可能版本不一样,代码不同:

打开tailwind.config.js并配置content字段,告诉Tailwind需要扫描哪些文件来生成CSS类:
// tailwind.config.js
module.exports = {
// 指定Tailwind需要扫描的文件路径,以生成对应的CSS类
// 这里包括了app目录下的所有JS/TS/JSX/TSX文件
content: [
"./src/app/**/*.{js,ts,jsx,tsx}",
// 也包括components目录下的所有JS/TS/JSX/TSX文件
"./src/components/**/*.{js,ts,jsx,tsx}",
],
theme: {
// 扩展Tailwind的默认主题,添加自定义颜色
extend: {
colors: {
// 定义一个名为primary的颜色,用于主要按钮和强调元素
primary: '#4F46E5',
// 定义一个名为secondary的颜色,用于次要按钮和强调元素
secondary: '#10B981',
}
},
},
// 插件扩展,目前没有使用任何插件
plugins: [],
}
我没看到有tailwind.config.js文件,只能创建一个了。

在src/app/globals.css中添加Tailwind指令:
/* 从Tailwind的base样式开始,这是Tailwind的基础重置 */
@tailwind base;
/* 从Tailwind的组件样式开始,这是Tailwind的组件样式 */
@tailwind components;
/* 从Tailwind的实用类样式开始,这是Tailwind的核心实用类 */
@tailwind utilities;

4. 创建状态管理(Zustand)(尴尬,语法看不太懂,回头再研究,先把代码跑通😳)(src/store/chatStore.ts)
我们使用Zustand管理聊天状态:
// src/store/chatStore.ts
// 从zustand库导入create函数,用于创建状态管理
import { create } from 'zustand';
// 定义聊天消息的类型,包含id、文本、是否是用户发送、时间戳
type ChatMessage = {
// 消息的唯一标识符,使用时间戳生成
id: string;
// 消息的文本内容
text: string;
// 标记消息是否是用户发送的(true表示用户,false表示AI)
isUser: boolean;
// 消息发送的时间戳
timestamp: number;
};
// 定义ChatState的状态类型,包含消息数组、添加消息函数、清除消息函数
type ChatState = {
// 存储所有聊天消息的数组
messages: ChatMessage[];
// 添加新消息到状态的函数
addMessage: (message: ChatMessage) => void;
// 清空所有聊天消息的函数
clearMessages: () => void;
};
// 使用zustand的create函数创建状态管理
// 传入一个函数,该函数接收set函数,用于更新状态
export const useChatStore = create<ChatState>((set) => ({
// 初始状态:消息数组为空
messages: [],
// 添加消息函数:将新消息添加到消息数组的末尾
addMessage: (message) => set((state) => ({
// 通过set函数更新状态,将新消息添加到现有消息数组的末尾
messages: [...state.messages, message]
})),
// 清除消息函数:将消息数组重置为空数组
clearMessages: () => set({ messages: [] }),
}));

5. 实现聊天消息组件(src/components/Chat/Message.tsx)
首先,创建消息组件:
// src/components/Chat/Message.tsx
// 从React导入React组件
import React from 'react';
// 定义Message组件的Props类型,包含text和isUser
interface MessageProps {
// 消息的文本内容
text: string;
// 标记消息是否是用户发送的
isUser: boolean;
}
// 创建Message组件,接收text和isUser作为props
const Message: React.FC<MessageProps> = ({ text, isUser }) => {
// 返回一个div,根据isUser的值决定消息的对齐方式
// 如果是用户发送的消息,右对齐;如果是AI发送的消息,左对齐
return (
<div className={`flex ${isUser ? 'justify-end' : 'justify-start'} mb-4`}>
{/* 消息容器,根据isUser的值设置背景色和文字颜色 */}
<div className={`max-w-[70%] rounded-lg p-3 ${isUser ? 'bg-primary text-white' : 'bg-gray-200'}`}>
{/* 消息文本,设置字体大小 */}
<p className="text-sm">{text}</p>
</div>
</div>
);
};
// 导出Message组件,使其可以在其他地方使用
export default Message;

6. 实现消息列表组件(src/components/Chat/MessageList.tsx)
// src/components/Chat/MessageList.tsx
// 从React导入React组件
import React from 'react';
// 从store/chatStore导入useChatStore,用于访问聊天状态
import Message from './Message';
import { useChatStore } from '@/store/chatStore';
// 定义MessageList组件,没有接收任何props
const MessageList: React.FC = () => {
// 使用useChatStore获取消息状态
const { messages } = useChatStore();
// 返回消息列表,使用div包裹,设置高度、溢出滚动和间距
return (
<div className="h-[calc(100vh-120px)] overflow-y-auto p-4 space-y-4">
{/* 使用map遍历messages数组,为每条消息渲染Message组件 */}
{messages.map((message) => (
// 为每条消息提供唯一的key,确保React可以高效更新
<Message
key={message.id}
text={message.text}
isUser={message.isUser}
/>
))}
</div>
);
};
// 导出MessageList组件
export default MessageList;

7. 实现输入框组件(看不太懂代码,先跑通)(src/components/InputBox.tsx)
// src/components/InputBox.tsx
// 从React导入useState
import React, { useState } from 'react';
// 从store/chatStore导入useChatStore,用于访问聊天状态
import { useChatStore } from '@/store/chatStore';
// 定义InputBox组件,没有接收任何props
const InputBox: React.FC = () => {
// 使用useState管理输入框的值
const [input, setInput] = useState('');
// 从useChatStore获取addMessage函数,用于添加新消息
const { addMessage } = useChatStore();
// 处理表单提交事件
const handleSubmit = (e: React.FormEvent) => {
// 阻止表单默认提交行为
e.preventDefault();
// 如果输入为空,直接返回,不处理
if (!input.trim()) return;
// 添加用户消息到状态
addMessage({
// 使用当前时间戳作为消息ID
id: Date.now().toString(),
// 用户输入的消息文本
text: input,
// 标记为用户发送
isUser: true,
// 记录消息发送时间
timestamp: Date.now(),
});
// 清空输入框
setInput('');
// 模拟AI响应,1秒后添加AI消息
setTimeout(() => {
addMessage({
// 使用当前时间戳+1作为AI消息ID
id: (Date.now() + 1).toString(),
// AI的模拟响应文本
text: "这是一个模拟的AI响应。在实际应用中,这里会调用API获取真实响应。",
// 标记为AI发送
isUser: false,
// 记录AI消息发送时间
timestamp: Date.now() + 1000,
});
}, 1000);
};
// 返回表单,包含输入框和发送按钮
return (
<form onSubmit={handleSubmit} className="p-4 border-t border-gray-200">
<div className="flex">
{/* 输入框,绑定输入值和输入事件 */}
<input
type="text"
value={input}
// 当输入框内容变化时,更新input状态
onChange={(e) => setInput(e.target.value)}
// 输入框的占位符文本
placeholder="请输入消息..."
// 设置输入框的样式,包括边框、内边距、圆角和焦点样式
className="flex-1 p-3 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-primary"
/>
{/* 发送按钮,绑定提交事件,禁用状态根据输入是否为空决定 */}
<button
type="submit"
// 设置按钮的背景色、文字颜色、内边距、圆角和悬停效果
className="bg-primary text-white px-6 rounded-r-lg hover:bg-indigo-600 transition-colors"
// 如果输入为空,禁用按钮
disabled={!input.trim()}
>
发送
</button>
</div>
</form>
);
};
// 导出InputBox组件
export default InputBox;

8. 创建主页面(src/app/page.tsx)
// src/app/page.tsx
// 从React导入React组件
import React from 'react';
// 从components导入MessageList和InputBox组件
import MessageList from '@/components/Chat/MessageList';
import InputBox from '@/components/InputBox';
// 定义Home组件,作为应用程序的主页面
export default function Home() {
// 返回页面结构,包含头部、主内容区域
return (
<div className="min-h-screen bg-gray-50 flex flex-col">
{/* 头部,包含标题 */}
<header className="bg-white shadow-md p-4 text-center">
{/* 标题,设置字体大小、粗细和颜色 */}
<h1 className="text-xl font-bold text-primary">AI Chat</h1>
</header>
{/* 主内容区域,包含消息列表和输入框 */}
<main className="flex-1 flex flex-col">
{/* 消息列表组件 */}
<MessageList />
{/* 输入框组件 */}
<InputBox />
</main>
</div>
);
}
将以上内容替换page.tsx中的初始内容:

9. 添加全局样式(src/app/globals.css)
/* src/app/globals.css */
/* 从Google Fonts导入Inter字体,指定字体重量 */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');
/* 设置页面的字体为Inter,如果没有则使用sans-serif */
body {
font-family: 'Inter', sans-serif;
}

10. 运行项目
npm run dev
命令解释:npm run dev 是Next.js项目默认的开发服务器命令,它会启动一个开发服务器,自动检测代码变化并热重载。
11. 代码解释
Tailwind CSS的实用类设计
- 布局:
flex,justify-end,justify-start,flex-1用于实现响应式布局 - 间距:
p-4,mb-4,space-y-4用于控制元素间距 - 颜色:
bg-primary,text-white,bg-gray-200,border-gray-300用于设置颜色 - 圆角:
rounded-lg用于设置圆角 - 响应式:
max-w-[70%]用于限制消息宽度,确保在不同屏幕下显示良好
Zustand状态管理
create:Zustand的创建函数addMessage:添加新消息到状态clearMessages:清空聊天记录useChatStore:在组件中使用状态
交互逻辑
- 用户输入消息并提交
- 将用户消息添加到状态
- 模拟1秒后添加AI响应
- 消息列表自动滚动到最新消息
12. 扩展建议
- 添加加载状态:在AI响应时显示加载指示器
- 实现真正的API调用:替换假接口为实际的API
- 添加消息删除功能:允许用户删除消息
- 实现消息编辑:允许用户编辑已发送的消息
- 添加主题切换:实现深色/浅色模式
13. 总结
通过这个简单的示例,我们使用Tailwind CSS实现了仿ChatGPT的聊天界面。Tailwind CSS的实用类使我们能够快速构建响应式UI,而Zustand则提供了简洁的状态管理。
关键点:
- 使用Tailwind的实用类快速构建UI
- 通过Zustand管理应用状态
- 使用假接口模拟后端交互
- 确保界面在不同设备上的响应式体验
这个项目是学习Tailwind CSS和现代前端开发模式的绝佳起点。随着你对Tailwind的熟悉,可以尝试添加更多功能,如消息表情、图片上传等。
14. 最终效果

也太丑了吧。。。
(注:实际效果请运行代码查看)
15. 下一步学习
- 学习Tailwind的响应式设计:Tailwind官方响应式文档
- 探索Zustand的高级功能:Zustand官方文档
- 了解Next.js的API路由:Next.js API Routes
更多推荐


所有评论(0)