/** @type {import('tailwindcss').Config} / module.exports = { content: ["./**/.{html,js}"], theme: { extend: { fontFamily: { outfit: "Outfit", }, colors: { danger: "#ff5f40", crayola_red: "#ff355e", darkblue: { 100: "#000066", 200: "#000033", }, }, borderRadius: { x20: "20px", }, width: { vw90: "90vw", }, }, }, plugins: [], };
@import url("fonts.googleapis.com/css2?family…");
@tailwind base; @tailwind components; @tailwind utilities;
/*! personal customization @apply */
/* main button */ .btn-main { @apply bg-darkblue-200 text-white font-bold px-6 py-2 m-4 rounded-x20; }
Tailwind Demo with Image Upload & CRUD<!-- ========== 头部导航栏 ========== -->
<header
class="bg-gradient-to-r from-blue-600 to-purple-600 p-4 shadow-lg text-white"
>
<nav class="container mx-auto flex items-center justify-between">
<div class="text-xl font-bold">My Tailwind Site</div>
<ul class="flex space-x-4">
<li>
<a href="#" class="hover:underline hover:text-yellow-200">主页</a>
</li>
<li>
<a href="#" class="hover:underline hover:text-yellow-200">关于</a>
</li>
<li>
<a href="#" class="hover:underline hover:text-yellow-200">联系</a>
</li>
</ul>
</nav>
</header>
<!-- ========== 主内容区域 ========== -->
<main class="container mx-auto mt-8 px-4">
<!-- ========= Hero / Banner 区域 ========= -->
<section
class="bg-white rounded-lg shadow-md p-8 mb-8 flex flex-col items-center text-center"
>
<h1 class="text-3xl font-extrabold mb-4 text-gray-800">
欢迎来到 Tailwind CSS 世界
</h1>
<p class="mb-4 text-gray-600 leading-relaxed">
这里演示了使用各种 Tailwind CSS
类名的页面布局示例,带有详细注释,方便你快速学习。
</p>
<button
class="bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-6 rounded-full shadow-md transform hover:-translate-y-1 hover:shadow-lg transition duration-300"
>
立即开始
</button>
</section>
<!-- ========= 卡片网格布局示例 ========= -->
<section class="grid gap-6 md:grid-cols-2 lg:grid-cols-3 mb-8">
<!-- 卡片1 -->
<article
class="bg-white p-4 rounded-lg shadow hover:shadow-lg transition-shadow duration-300"
>
<img
src="https://picasso-static.xiaohongshu.com/fe-platform/9e006ca119d9bc5779558284795d0d96b7096cf4.png"
alt="demo"
class="w-full h-40 object-cover rounded"
/>
<h3 class="mt-4 text-xl font-bold">卡片标题一</h3>
<p class="text-gray-700 mt-2">
这里是一段卡片简介,可自由扩展描述文字内容。
</p>
<div class="mt-4 flex justify-between items-center">
<span class="text-gray-500 text-sm">阅读更多</span>
<button
class="bg-blue-500 text-white px-3 py-1 rounded-md hover:bg-blue-600"
>
查看
</button>
</div>
</article>
<!-- 卡片2 -->
<article
class="bg-white p-4 rounded-lg shadow hover:shadow-lg transition-shadow duration-300"
>
<img
src="https://picasso-static.xiaohongshu.com/fe-platform/9e006ca119d9bc5779558284795d0d96b7096cf4.png"
alt="demo"
class="w-full h-40 object-cover rounded"
/>
<h3 class="mt-4 text-xl font-bold">卡片标题二</h3>
<p class="text-gray-700 mt-2">
使用 Tailwind CSS 可以非常快速地搭建页面原型。
</p>
<div class="mt-4 flex justify-between items-center">
<span class="text-gray-500 text-sm">阅读更多</span>
<button
class="bg-green-500 text-white px-3 py-1 rounded-md hover:bg-green-600"
>
查看
</button>
</div>
</article>
<!-- 卡片3 -->
<article
class="bg-white p-4 rounded-lg shadow hover:shadow-lg transition-shadow duration-300"
>
<img
src="https://picasso-static.xiaohongshu.com/fe-platform/9e006ca119d9bc5779558284795d0d96b7096cf4.png"
alt="demo"
class="w-full h-40 object-cover rounded"
/>
<h3 class="mt-4 text-xl font-bold">卡片标题三</h3>
<p class="text-gray-700 mt-2">
灵活的响应式设计,让你的页面适配多种设备尺寸。
</p>
<div class="mt-4 flex justify-between items-center">
<span class="text-gray-500 text-sm">阅读更多</span>
<button
class="bg-purple-500 text-white px-3 py-1 rounded-md hover:bg-purple-600"
>
查看
</button>
</div>
</article>
<!-- 卡片4 (大屏才可见) -->
<article
class="bg-white p-4 rounded-lg shadow hover:shadow-lg transition-shadow duration-300"
>
<img
src="https://picasso-static.xiaohongshu.com/fe-platform/9e006ca119d9bc5779558284795d0d96b7096cf4.png"
alt="demo"
class="w-full h-40 object-cover rounded"
/>
<h3 class="mt-4 text-xl font-bold">卡片标题四</h3>
<p class="text-gray-700 mt-2">
这张卡片仅在屏幕较大时(lg)才会自动进入第三列显示。
</p>
<div class="mt-4 flex justify-between items-center">
<span class="text-gray-500 text-sm">阅读更多</span>
<button
class="bg-red-500 text-white px-3 py-1 rounded-md hover:bg-red-600"
>
查看
</button>
</div>
</article>
</section>
<!-- ========= 表格示例 ========= -->
<section class="mb-8">
<div class="overflow-x-auto bg-white rounded-lg shadow">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
姓名
</th>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
年龄
</th>
<th
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
>
城市
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr class="hover:bg-gray-100 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">张三</td>
<td class="px-6 py-4 whitespace-nowrap">25</td>
<td class="px-6 py-4 whitespace-nowrap">北京</td>
</tr>
<tr class="hover:bg-gray-100 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">李四</td>
<td class="px-6 py-4 whitespace-nowrap">28</td>
<td class="px-6 py-4 whitespace-nowrap">上海</td>
</tr>
<tr class="hover:bg-gray-100 transition-colors">
<td class="px-6 py-4 whitespace-nowrap">王五</td>
<td class="px-6 py-4 whitespace-nowrap">30</td>
<td class="px-6 py-4 whitespace-nowrap">广州</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- ========= 表单示例 ========= -->
<section class="bg-white p-6 rounded-lg shadow-md">
<h2 class="text-2xl font-bold mb-4">联系表单</h2>
<form class="space-y-4">
<div>
<label for="name" class="block text-sm font-medium text-gray-700"
>姓名</label
>
<input
type="text"
id="name"
name="name"
placeholder="请输入姓名"
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label for="email" class="block text-sm font-medium text-gray-700"
>邮箱</label
>
<input
type="email"
id="email"
name="email"
placeholder="请输入邮箱"
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
<div>
<label for="message" class="block text-sm font-medium text-gray-700"
>留言</label
>
<textarea
id="message"
name="message"
rows="4"
placeholder="请输入留言内容"
class="mt-1 block w-full border border-gray-300 rounded-md shadow-sm px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
></textarea>
</div>
<div class="flex justify-end">
<button
type="submit"
class="bg-green-500 text-white px-6 py-2 rounded-md hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-300 transition"
>
提交
</button>
</div>
</form>
</section>
<!-- ========== 图片上传 & CRUD 表格 & 抽屉 (Drawer) ========== -->
<section class="bg-white p-6 rounded-lg shadow-md mt-8 mb-8">
<h2 class="text-2xl font-bold mb-4">图片上传和 CRUD 示例</h2>
<!-- “添加”按钮(打开右侧抽屉) -->
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">示例数据</h3>
<button onclick="openDrawer()">
<!-- 图标 + 文案 -->
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
></path>
</svg>
添加数据
</button>
</div>
<!-- CRUD 表格:名称、图片预览、编辑、删除 -->
<div class="overflow-x-auto">
<table class="min-w-full text-left border border-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 border-b border-gray-200">名称</th>
<th class="px-6 py-3 border-b border-gray-200">图片预览</th>
<th class="px-6 py-3 border-b border-gray-200">操作</th>
</tr>
</thead>
<tbody id="crud-tbody">
<!-- 示例静态数据 -->
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 border-b border-gray-200">示例名称</td>
<td class="px-6 py-4 border-b border-gray-200">
<img
src="https://via.placeholder.com/60"
alt="preview"
class="w-16 h-16 object-cover rounded"
/>
</td>
<td class="px-6 py-4 border-b border-gray-200">
<button
class="bg-yellow-400 text-white px-3 py-1 rounded hover:bg-yellow-500 mr-2"
>
编辑
</button>
<button
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600"
>
删除
</button>
</td>
</tr>
</tbody>
</table>
</div>
</section>
</main>
<!-- ========== 右侧抽屉(Drawer) ========== -->
<div
id="drawer"
class="fixed top-0 right-0 w-full sm:w-96 h-full bg-white shadow-xl transform translate-x-full transition-transform duration-300 z-50 flex flex-col"
>
<div class="flex justify-between items-center p-4 border-b">
<h3 class="text-lg font-semibold">添加/编辑数据</h3>
<!-- 关闭按钮 -->
<button
class="text-gray-500 hover:text-gray-700"
onclick="closeDrawer()"
>
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
></path>
</svg>
</button>
</div>
<!-- 抽屉主体内容:图片上传 & 名称输入 -->
<div class="p-4 flex-1 overflow-auto">
<!-- 图片上传区域 -->
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1"
>上传图片</label
>
<!-- 隐藏的 file input,用于真正选择图片 -->
<input
type="file"
accept="image/*"
id="uploadImage"
class="hidden"
onchange="handleImageUpload(event)"
/>
<!-- 自定义“选择图片”按钮 -->
<div class="flex items-center space-x-2">
<button
type="button"
class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600"
onclick="document.getElementById('uploadImage').click()"
>
选择图片
</button>
<span id="fileName" class="text-sm text-gray-600"></span>
</div>
<!-- 图片预览 -->
<div class="mt-2" id="imagePreviewWrapper">
<!-- 选中图片后,会在这里显示预览图 -->
</div>
</div>
<!-- 名称输入 -->
<div class="mb-4">
<label
for="itemName"
class="block text-sm font-medium text-gray-700 mb-1"
>名称</label
>
<input
type="text"
id="itemName"
class="block w-full border border-gray-300 rounded p-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="请输入名称"
/>
</div>
</div>
<!-- 抽屉底部按钮 -->
<div class="p-4 border-t flex justify-end space-x-2">
<button
class="px-4 py-2 rounded border border-gray-300 text-gray-700 hover:bg-gray-100"
onclick="closeDrawer()"
>
取消
</button>
<button
class="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600"
onclick="saveData()"
>
保存
</button>
</div>
</div>
<!-- 半透明遮罩层,在打开抽屉时可阻止底层点击 -->
<div
id="drawerOverlay"
class="fixed inset-0 bg-black bg-opacity-30 hidden z-40"
onclick="closeDrawer()"
></div>
<!-- ========== 页脚 ========== -->
<footer class="bg-gray-800 text-white mt-8 py-4">
<div class="container mx-auto text-center">
© 2025 My Tailwind Site. All rights reserved.
</div>
</footer>
<!-- ========== JavaScript:Drawer & CRUD 功能示例 ========== -->
<script>
const drawer = document.getElementById("drawer");
const drawerOverlay = document.getElementById("drawerOverlay");
const uploadImageInput = document.getElementById("uploadImage");
const imagePreviewWrapper = document.getElementById(
"imagePreviewWrapper"
);
const itemNameInput = document.getElementById("itemName");
const crudTbody = document.getElementById("crud-tbody");
const fileNameSpan = document.getElementById("fileName");
let selectedImageDataUrl = ""; // 用于存储上传的图片Base64或ObjectURL
// 打开抽屉
function openDrawer() {
drawerOverlay.classList.remove("hidden");
drawer.classList.remove("translate-x-full");
}
// 关闭抽屉
function closeDrawer() {
drawerOverlay.classList.add("hidden");
drawer.classList.add("translate-x-full");
// 重置表单
resetDrawerForm();
}
// 重置抽屉表单
function resetDrawerForm() {
uploadImageInput.value = null;
imagePreviewWrapper.innerHTML = "";
itemNameInput.value = "";
fileNameSpan.textContent = "";
selectedImageDataUrl = "";
}
// 处理图片上传(前端预览)
function handleImageUpload(event) {
const file = event.target.files[0];
if (!file) return;
fileNameSpan.textContent = file.name;
// 使用 FileReader 读取本地文件并预览
const reader = new FileReader();
reader.onload = function (e) {
selectedImageDataUrl = e.target.result; // base64数据
showImagePreview(selectedImageDataUrl);
};
reader.readAsDataURL(file);
}
// 显示图片预览
function showImagePreview(imgSrc) {
imagePreviewWrapper.innerHTML = `
<img
src="${imgSrc}"
alt="preview"
class="mt-2 w-24 h-24 object-cover rounded border"
/>
`;
}
// 保存数据到表格 (简单前端示例)
function saveData() {
const nameValue = itemNameInput.value.trim();
if (!nameValue) {
alert("请输入名称");
return;
}
// 创建一个新的表格行
const tr = document.createElement("tr");
tr.className = "hover:bg-gray-50";
tr.innerHTML = `
<td class="px-6 py-4 border-b border-gray-200">${nameValue}</td>
<td class="px-6 py-4 border-b border-gray-200">
${
selectedImageDataUrl
? `<img src="${selectedImageDataUrl}" alt="preview" class="w-16 h-16 object-cover rounded" />`
: "暂无图片"
}
</td>
<td class="px-6 py-4 border-b border-gray-200">
<button class="bg-yellow-400 text-white px-3 py-1 rounded hover:bg-yellow-500 mr-2">
编辑
</button>
<button
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600"
onclick="deleteRow(this)"
>
删除
</button>
</td>
`;
// 将新行添加到表格
crudTbody.appendChild(tr);
// 关闭抽屉
closeDrawer();
}
// 删除当前行
function deleteRow(btn) {
if (confirm("确定要删除该条目吗?")) {
const row = btn.parentNode.parentNode;
row.parentNode.removeChild(row);
}
}
</script>