在日常教学、会议签到、活动抽奖等场景中,随机点名系统是一个非常实用的工具。今天,我们就来一个基于 HTML、CSS 和 JavaScript 实现的智能随机点名系统的代码,并了解其功能和应用场景。
一、系统功能概述
这个智能随机点名系统主要具备以下功能:
-
添加姓名:用户可以通过输入框手动输入姓名并添加到点名列表中。
-
导入 Excel:支持从 Excel 文件(.csv 或.xlsx 格式)中批量导入姓名,方便快捷地录入大量数据。
-
随机点名:从已录入的姓名列表中随机抽取一个名字作为结果显示,同时提供了一个动画效果,增加趣味性。
-
删除姓名:可以单个删除指定的姓名,也支持批量删除已选中的姓名。
-
全选和取消全选:提供了全选和取消全选的功能,方便用户进行批量操作。
-
状态显示:实时显示当前点名列表中的人数,并且根据列表的状态动态更新操作按钮的可用性。
-
本地存储:系统使用本地存储(localStorage)来保存点名列表,确保数据在页面刷新或关闭后仍然存在。
二、代码结构分析
-
HTML 结构:页面采用了简洁的布局,包含一个输入框、几个按钮、一个显示点名列表的无序列表、一个显示结果的区域以及一个状态显示条。通过不同的类名(如
.container
、.input-group
、.name-list
等)来组织和样式化各个元素。 -
CSS 样式:使用了 CSS 变量(
--primary-color
、--secondary-color
、--background
)来定义主要的颜色,方便统一管理和修改。通过对不同类名的样式设置,实现了页面的美观和交互效果,如按钮的悬停效果、列表项的高亮效果等。 -
JavaScript 逻辑:
-
初始化和数据存储:在页面加载时,从本地存储中读取已保存的姓名列表,并初始化页面显示。通过
saveToStorage
函数将更新后的列表保存到本地存储中。 -
添加和删除姓名:
addName
函数负责将新的姓名添加到列表中,deleteName
函数用于删除指定的姓名。在添加或删除操作后,会更新列表显示、保存数据到本地存储,并根据列表状态更新按钮的可用性。 -
批量操作:
toggleSelection
函数用于处理复选框的选中和取消选中状态,selectAll
函数实现全选和取消全选的功能,batchDelete
函数用于批量删除已选中的姓名。 -
Excel 导入:
handleFile
函数通过FileReader
和xlsx
库读取 Excel 文件内容,并将其中的姓名添加到点名列表中。在导入过程中,会显示一个加载提示,导入完成后更新列表和相关状态。 -
随机点名:
randomPick
函数实现了随机点名的功能,通过一个动画效果在列表中快速切换姓名,最后随机抽取一个作为结果显示,并高亮显示选中的姓名。
-
三、应用场景
-
教学场景:教师可以使用该系统随机抽取学生回答问题,增加课堂互动性和公平性。
-
会议签到:在会议开始前,参会人员的姓名可以录入系统,会议过程中可以随机抽取参会人员进行发言或提问。
-
活动抽奖:在各种活动中,将参与者的姓名录入系统,通过随机点名来确定中奖者,增加活动的趣味性和公正性。
四、安装这个代码
-
新建一个.txt文件:
-
然后复制下面全部代码到这个dm.txt中:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>智能随机点名系统</title> <style> :root { --primary-color: #2196F3; --secondary-color: #ff4081; --background: #f5f5f5; } body { font-family: 'Microsoft Yahei', Arial, sans-serif; background: var(--background); margin: 0; padding: 20px; } .container { max-width: 800px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 30px; } .header { text-align: center; margin-bottom: 30px; } .input-group { display: flex; gap: 10px; margin-bottom: 20px; } input[type="text"] { flex: 1; padding: 12px; border: 2px solid #ddd; border-radius: 6px; transition: border-color 0.3s; } input[type="text"]:focus { border-color: var(--primary-color); outline: none; } button { padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; transition: all 0.3s; background: var(--primary-color); color: white; } button:hover { opacity: 0.9; transform: translateY(-1px); } button:disabled { background: #ccc; cursor: not-allowed; } .file-input { position: relative; display: inline-block; } .file-input input[type="file"] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .name-list { list-style: none; padding: 0; margin: 20px 0; border: 2px solid #eee; border-radius: 8px; max-height: 300px; overflow-y: auto; } .name-list li { padding: 15px; margin: 0; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; transition: all 0.3s; } .name-list li:last-child { border-bottom: none; } .name-list li:hover { background: #f8f9fa; } .name-list .name-content { flex: 1; margin-left: 10px; } .highlight { background: #fff3e0 !important; font-weight: bold; } .result-box { text-align: center; padding: 30px; margin: 20px 0; background: #f8f9fa; border-radius: 8px; min-height: 100px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: var(--primary-color); transition: all 0.3s; } @keyframes spin { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.2); opacity: 0.8; } 100% { transform: scale(1); opacity: 1; } } .spinning { animation: spin 0.1s infinite; color: var(--secondary-color); } .status-bar { text-align: right; color: #666; font-size: 14px; margin-top: 20px; } .delete-btn { background: var(--secondary-color); padding: 6px 12px; font-size: 12px; } .loading { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255, 255, 255, 0.8); justify-content: center; align-items: center; z-index: 1000; } .loading.active { display: flex; } .batch-actions { display: flex; gap: 10px; margin-bottom: 10px; } .delete-all-btn { background: var(--secondary-color); } .name-checkbox { margin-right: 10px; } </style> </head> <body> <div class="container"> <div class="header"> <h1>🎉 智能随机点名系统</h1> </div> <div class="input-group"> <input type="text" id="nameInput" placeholder="请输入姓名..."> <button onclick="addName()">➕ 添加</button> <div class="file-input"> <button>📁 导入Excel</button> <input type="file" id="excelFile" accept=".csv,.xlsx" onchange="handleFile()"> </div> <button onclick="randomPick()" id="pickBtn" disabled>🎮 开始点名</button> </div> <div class="batch-actions"> <button onclick="selectAll()" id="selectAllBtn">全选</button> <button onclick="batchDelete()" class="delete-all-btn" id="batchDeleteBtn" disabled>批量删除</button> </div> <ul class="name-list" id="nameList"></ul> <div class="result-box" id="result"> 👇 点击上方按钮开始 </div> <div class="status-bar"> 当前人数: <span id="count">0</span> </div> </div> <div class="loading" id="loading"> <div style="font-size: 24px; color: var(--primary-color)">⏳ 正在导入数据...</div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.17.5/xlsx.full.min.js"></script> <script> // 初始化本地存储 let names = JSON.parse(localStorage.getItem('names')) || []; let isSpinning = false; let selectedNames = []; // 页面加载时初始化列表 window.onload = () => { renderList(); updateButtonState(); updateCount(); }; function saveToStorage() { localStorage.setItem('names', JSON.stringify(names)); updateCount(); } function updateCount() { document.getElementById('count').textContent = names.length; } function updateButtonState() { const pickBtn = document.getElementById('pickBtn'); pickBtn.disabled = names.length < 2; const batchDeleteBtn = document.getElementById('batchDeleteBtn'); batchDeleteBtn.disabled = selectedNames.length === 0; } function renderList() { const list = document.getElementById('nameList'); list.innerHTML = names.map(name => ` <li> <input type="checkbox" class="name-checkbox" onchange="toggleSelection('${name}', this.checked)"> <span class="name-content">${name}</span> <button class="delete-btn" onclick="deleteName('${name}')">删除</button> </li> `).join(''); selectedNames = []; updateButtonState(); } function addName(name) { const nameToAdd = name || document.getElementById('nameInput').value.trim(); if (nameToAdd && !names.includes(nameToAdd)) { names.push(nameToAdd); renderList(); document.getElementById('nameInput').value = ''; saveToStorage(); updateButtonState(); } } function deleteName(name) { names = names.filter(n => n !== name); selectedNames = selectedNames.filter(n => n !== name); renderList(); saveToStorage(); updateButtonState(); } function toggleSelection(name, isChecked) { if (isChecked) { if (!selectedNames.includes(name)) { selectedNames.push(name); } } else { selectedNames = selectedNames.filter(n => n !== name); } updateButtonState(); } function selectAll() { const checkboxes = document.querySelectorAll('.name-checkbox'); const selectAllBtn = document.getElementById('selectAllBtn'); // 检查是否所有都已选中 const allSelected = selectedNames.length === names.length; if (allSelected) { // 如果全部已选中,则取消全选 checkboxes.forEach(cb => cb.checked = false); selectedNames = []; selectAllBtn.textContent = '全选'; } else { // 否则全选 checkboxes.forEach(cb => cb.checked = true); selectedNames = [...names]; selectAllBtn.textContent = '取消全选'; } updateButtonState(); } function batchDelete() { if (selectedNames.length === 0) return; if (confirm(`确定要删除选中的 ${selectedNames.length} 个名字吗?`)) { names = names.filter(name => !selectedNames.includes(name)); selectedNames = []; renderList(); saveToStorage(); updateButtonState(); } } async function handleFile() { const file = document.getElementById('excelFile').files[0]; if (!file) return; document.getElementById('loading').classList.add('active'); const reader = new FileReader(); reader.onload = async function(e) { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, {type: 'array'}); const sheet = workbook.Sheets[workbook.SheetNames[0]]; const json = XLSX.utils.sheet_to_json(sheet); json.forEach(row => { const name = Object.values(row)[0]?.toString().trim(); if (name && !names.includes(name)) { names.push(name); } }); renderList(); saveToStorage(); updateButtonState(); document.getElementById('loading').classList.remove('active'); }; reader.readAsArrayBuffer(file); } function randomPick() { if (isSpinning || names.length < 2) return; isSpinning = true; const resultDiv = document.getElementById('result'); const btn = document.getElementById('pickBtn'); btn.disabled = true; let currentIndex = 0; let interval = 50; let rounds = 15; resultDiv.classList.add('spinning'); const animate = () => { resultDiv.textContent = names[currentIndex]; currentIndex = (currentIndex + 1) % names.length; if (rounds-- > 0) { interval += 10; setTimeout(animate, interval); } else { const winner = names[Math.floor(Math.random() * names.length)]; resultDiv.textContent = `🎉 中奖者: ${winner}`; resultDiv.classList.remove('spinning'); btn.disabled = false; isSpinning = false; document.querySelectorAll('#nameList li').forEach(li => { li.classList.toggle('highlight', li.querySelector('.name-content').textContent.includes(winner)); }); } }; setTimeout(animate, interval); } </script> </body> </html>
- 然后将dm.txt修改为dm.html:
4。然后双击运行这个html文件
5、就可以看到这个点名系统了
创作不易,从构思到成品,饱含我创作的热忱,希望大家尊重原创,拒绝抄袭、盗用!