当前位置: 首页 > news >正文

Tailwind CSS实战:构建仿ChatGPT聊天页面(失败了)

参考文章: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
    • Add the PostCSS plugin to your postcss.config.mjs file:
    • Import Tailwind in your global CSS file:
    • Import the CSS file in your root layout:
    • 打开`tailwind.config.js`并配置content字段,告诉Tailwind需要扫描哪些文件来生成CSS类:
    • 在`src/app/globals.css`中添加Tailwind指令:
  • 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. 代码解释
    • Tailwind CSS的实用类设计
    • Zustand状态管理
    • 交互逻辑
  • 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可以高效更新<Messagekey={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({// 使用当前时间戳作为消息IDid: Date.now().toString(),// 用户输入的消息文本text: input,// 标记为用户发送isUser: true,// 记录消息发送时间timestamp: Date.now(),});// 清空输入框setInput('');// 模拟AI响应,1秒后添加AI消息setTimeout(() => {addMessage({// 使用当前时间戳+1作为AI消息IDid: (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">{/* 输入框,绑定输入值和输入事件 */}<inputtype="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"/>{/* 发送按钮,绑定提交事件,禁用状态根据输入是否为空决定 */}<buttontype="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. 用户输入消息并提交
  2. 将用户消息添加到状态
  3. 模拟1秒后添加AI响应
  4. 消息列表自动滚动到最新消息

12. 扩展建议

  1. 添加加载状态:在AI响应时显示加载指示器
  2. 实现真正的API调用:替换假接口为实际的API
  3. 添加消息删除功能:允许用户删除消息
  4. 实现消息编辑:允许用户编辑已发送的消息
  5. 添加主题切换:实现深色/浅色模式

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
http://www.dtcms.com/a/524050.html

相关文章:

  • DeerFlow多智能体项目分析-依赖LangGraph实现条件路由和中断机制的源码解析
  • 【JUnit实战3_10】第六章:关于测试的质量(上)
  • 容器编排大王Kubernetes——helm包管理工具(8)
  • 南皮县网站建设php网站开发接口开发
  • 【AOA定位与UKF例程】到达角度(AOA)定位后,使用无迹卡尔曼滤波(UKF)对轨迹滤波,MATLAB例程可下载
  • 拒绝笨重,一款轻量、极致简洁的开源CI/CD工具 - Arbess
  • JavaWeb--Servlet
  • 【机器学习】15.深度聚类(Deep Clustering)原理讲解与实战
  • Atom编辑器下载安装图文教程(附安装包)
  • 【基础复习1】ROC 与 AUC:逻辑回归二分类例子
  • 【Angular 】Angular 中的依赖注入
  • 做门户网站需要什么条件文化传播公司网站模版
  • 马斯克公司推出视频模型 Imagine v0.9,实测解析
  • 扶风做企业网站网站建设平台安全问题有哪些方面
  • 【AI4S】Motif-Driven Contrastive Learning of Graph Representations
  • Flutter路由使用指南
  • husky vs lefthook:新一代 Git Hooks 工具全面对比
  • Go Web 编程快速入门 07 - 模板(1):语法与最佳实践
  • 聊城网站建设信息兴义网站建设网站建设
  • 今年前三季度浙江进出口总值首破四万亿元
  • 【一文了解】八大排序-插入排序、希尔排序
  • n8n数据存储在postgres
  • 数据结构——冒泡排序
  • 医疗连续体机器人模块化控制界面设计(2025年更新版Python库)
  • 做网站服务器需要系统wordpress折腾怕了
  • 022数据结构之树状数组——算法备赛
  • 从 TypeScript 到 Java(4):访问修饰符与作用域 —— Java 的封装哲学
  • 做网站要有什么团队上海网站营销推广
  • 残差网络的介绍及ResNet-18的搭建(pytorch版)
  • WPF绘制界面常用功能