html+css+vue實現增刪改查

代碼如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>優化版 Vue.js CRUD 示例</title><script src="https://unpkg.com/vue@3/dist/vue.global.js"></script><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);color: #333;padding: 20px;min-height: 100vh;}.container {max-width: 1000px;margin: 0 auto;background: white;border-radius: 15px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);padding: 30px;position: relative;overflow: hidden;}.container::before {content: '';position: absolute;top: 0;left: 0;right: 0;height: 5px;background: linear-gradient(90deg, #3498db, #2ecc71, #f39c12, #e74c3c);}h1 {text-align: center;margin: 15px 0 30px;color: #2c3e50;font-weight: 600;position: relative;padding-bottom: 15px;}h1::after {content: '';position: absolute;bottom: 0;left: 50%;transform: translateX(-50%);width: 80px;height: 4px;background: linear-gradient(90deg, #3498db, #2ecc71);border-radius: 2px;}.header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 25px;flex-wrap: wrap;gap: 15px;padding: 20px;background: #f8fafc;border-radius: 10px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);}.search-container {position: relative;flex-grow: 1;}.search-box {padding: 12px 45px 12px 15px;border: 2px solid #e2e8f0;border-radius: 8px;width: 100%;font-size: 16px;transition: all 0.3s;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);}.search-box:focus {border-color: #3498db;box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);outline: none;}.search-icon {position: absolute;right: 15px;top: 50%;transform: translateY(-50%);color: #64748b;}.search-clear {position: absolute;right: 40px;top: 50%;transform: translateY(-50%);background: none;border: none;color: #94a3b8;cursor: pointer;font-size: 16px;transition: color 0.3s;}.search-clear:hover {color: #e74c3c;}.btn {padding: 12px 24px;border: none;border-radius: 8px;cursor: pointer;font-weight: 500;transition: all 0.3s;display: flex;align-items: center;gap: 8px;}.btn-primary {background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);color: white;box-shadow: 0 4px 6px rgba(52, 152, 219, 0.3);}.btn-primary:hover {transform: translateY(-2px);box-shadow: 0 6px 8px rgba(52, 152, 219, 0.4);}.btn-edit {background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);color: white;box-shadow: 0 4px 6px rgba(243, 156, 18, 0.3);}.btn-edit:hover {transform: translateY(-2px);box-shadow: 0 6px 8px rgba(243, 156, 18, 0.4);}.btn-delete {background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);color: white;box-shadow: 0 4px 6px rgba(231, 76, 60, 0.3);}.btn-delete:hover {transform: translateY(-2px);box-shadow: 0 6px 8px rgba(231, 76, 60, 0.4);}table {width: 100%;border-collapse: separate;border-spacing: 0;margin-top: 20px;border-radius: 10px;overflow: hidden;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);}th, td {padding: 16px;text-align: left;border-bottom: 1px solid #e2e8f0;}th {background: linear-gradient(to bottom, #f8fafc, #f1f5f9);font-weight: 600;color: #334155;}tr:last-child td {border-bottom: none;}tr:hover {background-color: #f8fafc;}.actions {display: flex;gap: 10px;}.modal {position: fixed;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(0, 0, 0, 0.5);display: flex;justify-content: center;align-items: center;z-index: 1000;opacity: 0;animation: fadeIn 0.3s forwards;}@keyframes fadeIn {to { opacity: 1; }}.modal-content {background-color: white;padding: 30px;border-radius: 15px;width: 500px;max-width: 90%;box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);transform: translateY(20px);animation: slideUp 0.3s forwards;}@keyframes slideUp {to { transform: translateY(0); }}.modal-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 25px;padding-bottom: 15px;border-bottom: 1px solid #e2e8f0;}.modal-title {font-size: 22px;font-weight: 600;color: #2c3e50;}.modal-close {background: none;border: none;font-size: 24px;cursor: pointer;color: #94a3b8;transition: color 0.3s;}.modal-close:hover {color: #e74c3c;}.form-group {margin-bottom: 20px;position: relative;}label {display: block;margin-bottom: 8px;font-weight: 500;color: #334155;}input, select {width: 100%;padding: 14px;border: 2px solid #e2e8f0;border-radius: 8px;font-size: 16px;transition: all 0.3s;}input:focus, select:focus {border-color: #3498db;box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);outline: none;}.error-message {color: #e74c3c;font-size: 14px;margin-top: 5px;display: none;}input.invalid, select.invalid {border-color: #e74c3c;}input.invalid + .error-message, select.invalid + .error-message {display: block;}.form-actions {display: flex;justify-content: flex-end;gap: 12px;margin-top: 30px;}.empty-state {text-align: center;padding: 60px 20px;color: #64748b;}.empty-state i {font-size: 60px;margin-bottom: 15px;color: #cbd5e1;}.empty-state p {margin-top: 15px;font-size: 18px;}.search-hint {text-align: center;padding: 15px;color: #64748b;font-style: italic;background: #f8fafc;border-radius: 8px;margin-top: 10px;display: none;}.search-hint.visible {display: block;animation: fadeIn 0.5s;}@media (max-width: 768px) {.header {flex-direction: column;align-items: stretch;}.search-box {width: 100%;}.actions {flex-direction: column;}th, td {padding: 12px;}.btn {width: 100%;justify-content: center;}}.user-avatar {width: 40px;height: 40px;border-radius: 50%;background: linear-gradient(135deg, #3498db 0%, #2ecc71 100%);display: flex;align-items: center;justify-content: center;color: white;font-weight: 600;margin-right: 10px;}.user-info {display: flex;align-items: center;}.role-badge {padding: 4px 12px;border-radius: 20px;font-size: 12px;font-weight: 600;}.role-admin {background: #ffeaa7;color: #d35400;}.role-user {background: #d6eaf8;color: #2980b9;}.role-editor {background: #e8f8f5;color: #16a085;}</style>
</head>
<body><div id="app"><div class="container"><h1><i class="fas fa-users-cog"></i> 用戶管理系統</h1><div class="header"><div class="search-container"><input v-model="searchQuery" class="search-box" placeholder="搜索用戶..." @input="handleSearch"/><button v-if="searchQuery" class="search-clear" @click="clearSearch"><i class="fas fa-times"></i></button><div class="search-icon"><i class="fas fa-search"></i></div></div><button class="btn btn-primary" @click="openModal(null)"><i class="fas fa-plus"></i> 添加用戶</button></div><div class="search-hint" :class="{visible: searchQuery && filteredUsers.length > 0}">找到 {{ filteredUsers.length }} 個匹配"{{ searchQuery }}"的用戶</div><div v-if="filteredUsers.length > 0"><table><thead><tr><th>用戶</th><th>郵箱</th><th>角色</th><th>操作</th></tr></thead><tbody><tr v-for="user in filteredUsers" :key="user.id"><td><div class="user-info"><div class="user-avatar">{{ user.name.charAt(0) }}</div><div><div>{{ user.name }}</div><div style="font-size: 12px; color: #64748b;">ID: {{ user.id }}</div></div></div></td><td>{{ user.email }}</td><td><span class="role-badge" :class="'role-' + user.role">{{ user.role }}</span></td><td class="actions"><button class="btn btn-edit" @click="openModal(user)"><i class="fas fa-edit"></i> 編輯</button><button class="btn btn-delete" @click="deleteUser(user.id)"><i class="fas fa-trash"></i> 刪除</button></td></tr></tbody></table></div><div v-else class="empty-state"><i class="fas fa-user-slash"></i><p>{{ searchQuery ? '沒有找到匹配的用戶' : '暫無用戶數據' }}</p><button v-if="!searchQuery" class="btn btn-primary" @click="openModal(null)" style="margin-top: 20px;"><i class="fas fa-plus"></i> 添加第一個用戶</button><button v-else class="btn btn-primary" @click="clearSearch" style="margin-top: 20px;"><i class="fas fa-times"></i> 清除搜索</button></div><!-- 添加/編輯用戶的模態框 --><div class="modal" v-if="showModal" @click.self="closeModal"><div class="modal-content"><div class="modal-header"><h2 class="modal-title"><i :class="editingUser ? 'fas fa-user-edit' : 'fas fa-user-plus'"></i>{{ editingUser ? '編輯用戶' : '添加用戶' }}</h2><button class="modal-close" @click="closeModal"><i class="fas fa-times"></i></button></div><div class="form-group"><label for="name">姓名</label><input type="text" id="name" v-model="currentUser.name" placeholder="請輸入姓名":class="{invalid: !currentUser.name && formSubmitted}"><div class="error-message">請輸入姓名</div></div><div class="form-group"><label for="email">郵箱</label><input type="email" id="email" v-model="currentUser.email" placeholder="請輸入郵箱":class="{invalid: (!currentUser.email || !isValidEmail) && formSubmitted}"><div class="error-message">{{ !currentUser.email ? '請輸入郵箱' : '請輸入有效的郵箱地址' }}</div></div><div class="form-group"><label for="role">角色</label><select id="role" v-model="currentUser.role"><option value="用戶">用戶</option><option value="管理員">管理員</option><option value="編輯">編輯</option></select></div><div class="form-actions"><button class="btn" @click="closeModal"><i class="fas fa-times"></i> 取消</button><button class="btn btn-primary" @click="saveUser"><i class="fas fa-save"></i> 保存</button></div></div></div></div></div><script>const { createApp, ref, computed, onMounted, watch } = Vue;createApp({setup() {// 用戶數據const users = ref([]);// 搜索查詢const searchQuery = ref('');// 控制模態框顯示const showModal = ref(false);// 當前正在編輯的用戶const currentUser = ref({ id: null, name: '', email: '', role: '用戶' });// 判斷是否為編輯模式const editingUser = ref(false);// 表單提交狀態const formSubmitted = ref(false);// 郵箱驗證狀態const isValidEmail = ref(true);// 初始化一些示例數據onMounted(() => {users.value = [{ id: 1, name: '張三', email: 'zhangsan@example.com', role: '管理員' },{ id: 2, name: '李四', email: 'lisi@example.com', role: '用戶' },{ id: 3, name: '王五', email: 'wangwu@example.com', role: '編輯' },{ id: 4, name: '趙六', email: 'zhaoliu@example.com', role: '用戶' },{ id: 5, name: '錢七', email: 'qianqi@example.com', role: '編輯' }];});// 郵箱驗證const validateEmail = () => {const email = currentUser.value.email;if (!email) {isValidEmail.value = false;return false;}const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;isValidEmail.value = re.test(email);return isValidEmail.value;};// 過濾用戶列表const filteredUsers = computed(() => {if (!searchQuery.value) {return users.value;}const query = searchQuery.value.toLowerCase();return users.value.filter(user => user.name.toLowerCase().includes(query) || user.email.toLowerCase().includes(query) ||user.role.toLowerCase().includes(query));});// 處理搜索const handleSearch = () => {// 可以添加搜索延遲處理};// 清除搜索const clearSearch = () => {searchQuery.value = '';};// 打開模態框const openModal = (user) => {formSubmitted.value = false;if (user) {// 編輯模式currentUser.value = { ...user };editingUser.value = true;} else {// 添加模式currentUser.value = { id: null, name: '', email: '', role: '用戶' };editingUser.value = false;}showModal.value = true;};// 關閉模態框const closeModal = () => {showModal.value = false;};// 保存用戶const saveUser = () => {formSubmitted.value = true;// 驗證表單if (!currentUser.value.name || !currentUser.value.email || !validateEmail()) {return;}if (editingUser.value) {// 更新現有用戶const index = users.value.findIndex(u => u.id === currentUser.value.id);if (index !== -1) {users.value[index] = { ...currentUser.value };}} else {// 添加新用戶const newId = users.value.length > 0 ? Math.max(...users.value.map(u => u.id)) + 1 : 1;users.value.push({id: newId,name: currentUser.value.name,email: currentUser.value.email,role: currentUser.value.role});}showModal.value = false;};// 刪除用戶const deleteUser = (id) => {if (confirm('確定要刪除這個用戶嗎?此操作不可撤銷。')) {users.value = users.value.filter(user => user.id !== id);}};// 監聽郵箱變化watch(() => currentUser.value.email, () => {if (formSubmitted.value) {validateEmail();}});return {users,searchQuery,showModal,currentUser,editingUser,formSubmitted,isValidEmail,filteredUsers,handleSearch,clearSearch,openModal,closeModal,saveUser,deleteUser,validateEmail};}}).mount('#app');</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95919.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95919.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95919.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(計算機網絡)DNS解析流程及兩種途徑

在計算機網絡中&#xff0c;DNS&#xff08;Domain Name System&#xff09;用于 將域名解析為 IP 地址。一個完整的解析過程涉及 遞歸查詢、迭代查詢&#xff0c;以及多個關鍵角色&#xff08;LDNS、本地域名服務器&#xff1b;根服務器&#xff1b;頂級域名服務器&#xff1b…

數據結構——隊列(Java)

一.基本概念 隊列用來存儲邏輯關系為“一對一”的數據&#xff0c;是一種“特殊”的線性存儲結構。 特點&#xff1a; ?先進先出&#xff1a;隊列中元素的添加&#xff08;入隊enqueue&#xff09;和移除&#xff08;出隊dequeue&#xff09;遵循先進先出的原 則。 ?端點&…

【Go】:mac 環境下GoFrame安裝開發工具 gf-cli——gf_darwin_arm64

當前主要是關于gf_darwin_arm64的安裝步驟 如何快速給mac電腦安裝gfgf是什么安裝步驟方法1&#xff1a;去github下載gf-cli去git上下載對應電腦版本的gf-cli驗證下載文件是否二進制文件授予該文件權限方法2&#xff1a;去goframe官網教你下載步驟驗證gf是否安裝成功可能遇到的問…

【新】ApiHug官方文檔-ApiHug Spring Security 擴展-補充說明

概述 在上次說明中我們寫了ApiHug 如何做授權的&#xff0c; 這里有個概念的混淆&#xff0c; 其實 apihug 不是在spring security 上做的安全擴展&#xff0c; 應該是 apihug spring, 安全設計框架&#xff0c; 和本身 spring security 沒有半毛錢關系&#xff0c; 而如果你…

【Flask】測試平臺開發,新增說明書編寫和展示功能 第二十三篇

概述&#xff1a;本篇是接著上一篇&#xff0c;細分出說明書的編寫部分&#xff0c;實現這個功能的需求&#xff0c;是內部很多同事反饋&#xff0c;需要有個地方存工具&#xff0c;并且可以寫說明書&#xff0c;如果需要的人&#xff0c;那么可以在界面上直接下載工具和查看工…

Mac設置中的安全性缺少“任何來源”

問題&#xff1a;用Mac安裝軟件&#xff0c;隱私性與安全性&#xff0c;想切換“任何來源”用來下載網站的app&#xff0c;但是菜單欄找不到“任何來源”選項&#xff0c;無法安裝dmg的文件終端中一行代碼設置出來&#xff1a;sudo spctl --global-disable &#xff08;禁用Mac…

uniapp開發小程序,列表 點擊后加載更多數據

一、需求 1.初始顯示限制:將每頁條數limit改為5,確保初始只顯示5條數據 2.查看更多功能:添加了loadMore方法,點擊"查看更多"時加載下一頁數據 3.實現查看更多功能,點擊后加載更多數據 4.添加loading狀態防止重復請求 添加hasMore狀態判斷是否還有更多數據 …

Windows 部署 Gerrit 與 Apache24 配置

Windows 部署 Gerrit 與 Apache24 并配置反向代理 準備工作 下載并安裝 Java JDK 確保配置 JAVA_HOME 環境變量博主這里安裝openjdk21 https://jdk.java.net/archive/下載所需軟件 Apache24&#xff1a;https://httpd.apache.org/download.cgi Gerrit&#xff1a;https://www.g…

從 Excel 趨勢線到機器學習:拆解 AI 背后的核心框架?

引言&#xff1a;你其實早就 “玩轉” 過機器學習&#xff1f;提到 “機器學習”&#xff0c;你是不是第一時間聯想到復雜的代碼、密密麻麻的公式&#xff0c;還有那些讓人頭暈的 “算法”“模型”“訓練” 術語&#xff1f;仿佛它是高高在上的技術&#xff0c;離我們的日常無比…

Lenovo聯想YOGA Pro 16 IAH10 2025款筆記本電腦(83L0)開箱狀態預裝OEM原廠Win11系統

適用機型(MTM)&#xff1a;【83L0】 鏈接&#xff1a;https://pan.baidu.com/s/1tDpeBb93t1u0XIgqAZ3edg?pwdqy2r 提取碼&#xff1a;qy2r 聯想原裝系統自帶所有驅動、出廠主題壁紙、系統屬性聯機支持標志、系統屬性專屬LOGO標志、Office辦公軟件、聯想瀏覽器、電腦管家、…

Android 開發 - 一些畫板第三方庫(DrawBoard、FingerPaintView、PaletteLib)

一、DrawBoard 1、Dependencies 模塊級 build.gradle implementation com.github.jenly1314:drawboard:1.1.02、Test &#xff08;1&#xff09;Activity Layout activity_draw_board.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout …

捷多邦揭秘超厚銅板:從制造工藝到設計關鍵環節?

一、超厚銅板制造工藝要點超厚銅板&#xff08;3oz 及以上&#xff09;的制造工藝對精度和穩定性要求嚴苛&#xff0c;核心環節需突破多重技術壁壘。蝕刻工藝中&#xff0c;因銅箔厚度達 105μm 以上&#xff0c;需采用高濃度酸性蝕刻液&#xff08;氯化銅濃度控制在 180-220g/…

【MYSQL | 高級篇 MyCat實現分庫分表】

摘要&#xff1a;本文圍繞分庫分表展開&#xff0c;先分析單庫性能瓶頸&#xff0c;介紹垂直與水平拆分策略及實現技術&#xff0c;再詳述 MyCat 中間件的概述、環境準備、目錄結構&#xff0c;講解其入門配置與測試&#xff0c;深入說明核心配置文件&#xff0c;最后演示垂直和…

Docker部署Drawnix開源白板工具

Drawnix簡介 Drawnix 是一款開源的在線白板工具&#xff08;SaaS&#xff09;&#xff0c;集思維導圖、流程圖繪制、自由畫圖等多種功能于一體&#xff0c;支持協作與插件擴展&#xff0c;適用于個人創作、團隊協作和遠程辦公場景。它完全免費且開源&#xff0c;提供豐富的編輯…

Griffin|增強現實數據集|無人機數據集

Griffin|增強現實數據集|無人機數據集 數據來源&#xff1a;huggingface 百度網盤 構建方式 Griffin數據集的構建采用了模塊化架構&#xff0c;結合了CARLA和AirSim平臺&#xff0c;通過模擬真實世界中的無人駕駛環境和無人機動態&#xff0c;收集了超過30,000幀圖像數據&am…

力扣.1054距離相等的條形碼力扣767.重構字符串力扣47.全排列II力扣980.不同路徑III力扣509.斐波那契數列(記憶化搜索)

目錄 力扣.1054距離相等的條形碼 力扣767.重構字符串 力扣47.全排列II 力扣980.不同路徑III 力扣509.斐波那契數列&#xff08;記憶化搜索) 力扣.1054距離相等的條形碼 是否策略正確 但是假如 1 2 2 此時 1_2 此時中間只能填寫2&#xff0c;但是就不對了&#xff0c;所…

「docker」二、3分鐘快速理解docker核心要素

上一節中我們知道docker的作用&#xff0c;這節我們介紹一下docker的要素。 鏡像 docker的核心要素里面有個叫鏡像&#xff08;images&#xff09;的概念&#xff0c;鏡像的作用就類似我們安裝虛擬機用到的iso鏡像文件。鏡像里包含了我們要運行的應用&#xff0c;如&#xff…

搭建基于 Solon AI 的 Streamable MCP 服務并部署至阿里云百煉

一、快速搭建 Solon 項目&#xff0c;引入 Solon AI 1. 開發環境準備 JDK 8 或以上版本。Maven 3.8.6 或以上版本。通義千問 API Key&#xff08;用于模型調用&#xff09;。 2. 創建名為 mcp-server-demo 的項目 創建時選擇 Archetype 為 Solon AI&#xff08;可以減少些活&am…

免費的SSL和付費SSL 證書差異

免費的 SSL 和付費的 SSL&#xff08;TLS 證書&#xff09;本質上提供的加密能力是一樣的&#xff0c;因為 SSL/TLS 協議本身是開放標準&#xff0c;核心加密算法不會因為是否收費而不同。主要區別在于以下幾個方面&#xff1a;&#x1f511; 1. 加密強度免費 SSL&#xff1a;一…

代碼隨想錄算法訓練營第六天 -- 字符串1 || 344.反轉字符串I / 541.反轉字符串II / kamacoder54.替換數字--第八期模擬筆試

代碼隨想錄算法訓練營第六天 -- 字符串1 || 344.反轉字符串I / 541.反轉字符串II / kamacoder54.替換數字--第八期模擬筆試344.反轉字符串I思路541.反轉字符串II題目理解解題思路邊界細節reverse()函數的實現[kamacoder54.替換數字 -- 第八期模擬筆試](https://kamacoder.com/p…