代碼功能
這個是一個HTML網頁端,簡單來說就是可以雙擊之后運行進行點名。
當然,不局限于課堂點名
代碼功能
Excel 導入增強:
增加了列選擇器,可以指定從哪一列讀取學生姓名
增加了起始行選擇器,可以跳過標題行或其他非學生數據行
自動檢測功能:嘗試識別可能包含姓名的列并自動選擇
一鍵清空功能:
在學生列表上方添加了 “清空名單” 按鈕
點擊后會提示確認,防止誤操作
用戶體驗優化:
導入 Excel 后顯示導入選項,導入完成后自動隱藏
優化了通知提示效果
保持了原有隨機點名的核心功能不變
界面截圖
源碼
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>阿幸隨機點名抽問</title><script src="https://cdn.tailwindcss.com"></script><link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script><script>tailwind.config = {theme: {extend: {colors: {primary: '#4F46E5',secondary: '#EC4899',accent: '#8B5CF6',neutral: '#F3F4F6',"neutral-dark": '#1F2937',},fontFamily: {cute: ['"Comic Sans MS"', '"Marker Felt"', 'Arial', 'sans-serif'],},animation: {'bounce-slow': 'bounce 3s infinite',}},}}</script><style type="text/tailwindcss">@layer utilities {.content-auto {content-visibility: auto;}.text-shadow {text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);}.bg-cute {background-image: radial-gradient(circle at 25% 25%, rgba(255, 220, 220, 0.8) 0%, transparent 50%),radial-gradient(circle at 75% 75%, rgba(220, 220, 255, 0.8) 0%, transparent 50%);background-color: #FFF5F7;}.name-container {perspective: 1000px;}.name-card {transform-style: preserve-3d;transition: transform 0.5s;}.name-card:hover {transform: translateY(-5px) rotateX(5deg);}}</style>
</head>
<body class="min-h-screen bg-cute flex flex-col items-center justify-between p-4 md:p-8"><!-- 頂部標題區域 --><header class="w-full text-center mb-8"><h1 class="text-[clamp(2rem,5vw,3.5rem)] font-cute font-bold text-primary text-shadow animate-bounce-slow"><i class="fa fa-star text-yellow-400"></i>阿幸隨機點名抽問<i class="fa fa-star text-yellow-400"></i></h1><p class="text-gray-600 mt-2">公平、隨機、有趣的課堂互動工具</p></header><!-- 主要內容區域 --><main class="flex-1 w-full max-w-4xl flex flex-col items-center justify-center"><!-- 名字顯示區域 --><div class="name-container w-full bg-white rounded-2xl shadow-lg p-6 md:p-10 mb-8 transform transition-all duration-300 hover:shadow-xl"><div class="name-card bg-gradient-to-br from-pink-100 to-purple-100 rounded-xl p-8 text-center"><p id="displayedName" class="text-[clamp(2.5rem,8vw,5rem)] font-black text-neutral-dark transition-all duration-500">準備開始</p></div></div><!-- 控制面板 --><div class="w-full bg-white rounded-xl shadow-md p-6 md:p-8"><div class="flex flex-col md:flex-row items-center justify-between gap-6"><!-- 速度控制滑塊 --><div class="w-full md:w-1/3"><label for="speedControl" class="block text-gray-700 font-medium mb-2 flex items-center"><i class="fa fa-tachometer text-accent mr-2"></i>滾動速度</label><input type="range" id="speedControl" min="50" max="500" value="200" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary"><div class="flex justify-between text-xs text-gray-500 mt-1"><span>慢</span><span>快</span></div></div><!-- 開始/停止按鈕 --><div class="w-full md:w-auto flex justify-center md:justify-end"><button id="toggleButton" class="bg-primary hover:bg-primary/90 text-white font-bold py-3 px-8 rounded-full shadow-lg transform transition-all duration-300 hover:scale-105 active:scale-95 flex items-center"><i class="fa fa-play mr-2"></i><span>開始點名</span></button></div></div></div><!-- 學生名單管理 --><div class="w-full mt-8 bg-white rounded-xl shadow-md p-6 md:p-8"><h2 class="text-xl font-bold text-gray-800 mb-4 flex items-center"><i class="fa fa-users text-secondary mr-2"></i>學生名單管理</h2><div class="flex flex-col md:flex-row gap-4"><!-- 文本導入 --><div class="w-full md:w-1/2"><label for="nameList" class="block text-gray-700 font-medium mb-2">輸入學生姓名(用逗號、空格或換行分隔)</label><textarea id="nameList" rows="4" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all" placeholder="張三, 李四, 王五..."></textarea><button id="importNames" class="mt-2 bg-accent hover:bg-accent/90 text-white font-medium py-2 px-4 rounded-lg shadow transition-all duration-200 flex items-center"><i class="fa fa-upload mr-1"></i> 導入名單</button></div><!-- Excel導入 --><div class="w-full md:w-1/2"><label class="block text-gray-700 font-medium mb-2">或從Excel文件導入</label><div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-primary transition-colors cursor-pointer" id="excelDropArea"><input type="file" id="excelFile" accept=".xlsx,.xls" class="hidden"><i class="fa fa-file-excel-o text-3xl text-gray-400 mb-2"></i><p class="text-gray-500">拖放Excel文件到此處<br>或點擊選擇文件</p></div><div id="excelFileName" class="mt-2 text-sm text-gray-600 hidden"></div><!-- Excel導入選項 --><div id="excelOptions" class="mt-4 grid grid-cols-2 gap-4 hidden"><div><label for="excelColumn" class="block text-gray-700 text-sm font-medium mb-1">姓名列選擇</label><select id="excelColumn" class="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary focus:border-primary"><option value="A">A列</option><option value="B">B列</option><option value="C">C列</option><option value="D">D列</option><option value="E">E列</option><option value="F">F列</option></select></div><div><label for="excelStartRow" class="block text-gray-700 text-sm font-medium mb-1">起始行號</label><input type="number" id="excelStartRow" min="1" value="1" class="w-full p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-primary focus:border-primary"></div></div><button id="importExcel" class="mt-2 bg-blue-500 hover:bg-blue-600 text-white font-medium py-2 px-4 rounded-lg shadow transition-all duration-200 flex items-center hidden"><i class="fa fa-check mr-1"></i> 確認導入Excel</button></div></div><!-- 學生列表顯示 --><div class="mt-6"><div class="flex justify-between items-center mb-3"><h3 class="text-lg font-medium text-gray-700 flex items-center"><i class="fa fa-list-ul text-primary mr-2"></i>已導入學生 (<span id="studentCount">0</span>)</h3><button id="clearStudents" class="text-red-500 hover:text-red-600 text-sm font-medium flex items-center"><i class="fa fa-trash mr-1"></i> 清空名單</button></div><div id="studentList" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-2 max-h-40 overflow-y-auto p-2 bg-gray-50 rounded-lg"><div class="text-gray-400 col-span-full text-center py-4">暫無學生名單</div></div></div></div></main><!-- 頁腳 --><footer class="w-full text-center text-gray-500 text-sm mt-8"><p>雙擊此頁面即可離線使用 | 點擊右上角可保存為應用</p></footer><script>document.addEventListener('DOMContentLoaded', function() {// DOM元素const displayedName = document.getElementById('displayedName');const toggleButton = document.getElementById('toggleButton');const speedControl = document.getElementById('speedControl');const nameList = document.getElementById('nameList');const importNames = document.getElementById('importNames');const excelFile = document.getElementById('excelFile');const excelDropArea = document.getElementById('excelDropArea');const excelFileName = document.getElementById('excelFileName');const excelOptions = document.getElementById('excelOptions');const importExcel = document.getElementById('importExcel');const excelColumn = document.getElementById('excelColumn');const excelStartRow = document.getElementById('excelStartRow');const studentList = document.getElementById('studentList');const studentCount = document.getElementById('studentCount');const clearStudents = document.getElementById('clearStudents');// 狀態變量let students = [];let isRolling = false;let rollInterval;let rollSpeed = 200; // 默認速度,值越小越快let selectedName = null;let excelData = null;// 處理學生名單導入importNames.addEventListener('click', function() {const text = nameList.value.trim();if (!text) {alert('請輸入學生姓名');return;}// 支持逗號、空格、換行等多種分隔符students = text.split(/[,\s\n]+/).filter(name => name.trim() !== '');updateStudentList();resetRollState();showNotification(`成功導入 ${students.length} 名學生`);});// 處理Excel文件導入excelFile.addEventListener('change', handleExcelFile);excelDropArea.addEventListener('click', () => excelFile.click());// 拖放功能excelDropArea.addEventListener('dragover', function(e) {e.preventDefault();this.classList.add('border-primary', 'bg-primary/5');});excelDropArea.addEventListener('dragleave', function() {this.classList.remove('border-primary', 'bg-primary/5');});excelDropArea.addEventListener('drop', function(e) {e.preventDefault();this.classList.remove('border-primary', 'bg-primary/5');if (e.dataTransfer.files.length) {excelFile.files = e.dataTransfer.files;handleExcelFile();}});function handleExcelFile() {const file = excelFile.files[0];if (!file) return;if (!file.name.match(/\.(xlsx|xls)$/i)) {alert('請選擇Excel文件 (.xlsx 或 .xls)');return;}excelFileName.textContent = `已選擇: ${file.name}`;excelFileName.classList.remove('hidden');excelOptions.classList.remove('hidden');importExcel.classList.remove('hidden');const reader = new FileReader();reader.onload = function(e) {try {const data = new Uint8Array(e.target.result);const workbook = XLSX.read(data, { type: 'array' });const firstSheetName = workbook.SheetNames[0];const worksheet = workbook.Sheets[firstSheetName];// 保存Excel數據供后續處理excelData = worksheet;// 嘗試自動檢測姓名列autoDetectNameColumn(worksheet);} catch (error) {console.error('Excel處理錯誤:', error);alert('處理Excel文件時出錯,請確保文件格式正確');}};reader.readAsArrayBuffer(file);}// 自動檢測姓名列function autoDetectNameColumn(worksheet) {const nameKeywords = ['姓名', '名字', '學生姓名', 'name', 'student'];const headerRow = XLSX.utils.sheet_to_json(worksheet, { header: 1, range: 0, raw: false })[0] || [];for (let i = 0; i < headerRow.length; i++) {const cellValue = headerRow[i] || '';const cellValueLower = cellValue.toString().toLowerCase();if (nameKeywords.some(kw => cellValueLower.includes(kw))) {// 將列索引轉換為字母 (0->A, 1->B, ...)const columnLetter = String.fromCharCode(65 + i);excelColumn.value = columnLetter;return;}}// 默認選擇A列excelColumn.value = 'A';}// 確認導入ExcelimportExcel.addEventListener('click', function() {if (!excelData) {alert('請先選擇Excel文件');return;}const column = excelColumn.value;const startRow = parseInt(excelStartRow.value) || 1;try {// 提取指定列的數據const range = XLSX.utils.decode_range(excelData['!ref'] || 'A1:A1');const maxRow = range.e.r;students = [];for (let row = startRow; row <= maxRow; row++) {const cellAddress = `${column}${row}`;const cell = excelData[cellAddress];if (cell && cell.v && cell.v.toString().trim() !== '') {students.push(cell.v.toString().trim());}}if (students.length === 0) {alert('未能從Excel文件中提取到有效姓名,請檢查列選擇和起始行');return;}updateStudentList();resetRollState();showNotification(`成功從Excel導入 ${students.length} 名學生`);// 導入后隱藏選項excelOptions.classList.add('hidden');importExcel.classList.add('hidden');} catch (error) {console.error('Excel導入錯誤:', error);alert('導入Excel數據時出錯,請檢查設置');}});// 更新學生列表顯示function updateStudentList() {studentList.innerHTML = '';if (students.length === 0) {studentList.innerHTML = `<div class="text-gray-400 col-span-full text-center py-4">暫無學生名單</div>`;studentCount.textContent = '0';return;}students.forEach(name => {const nameEl = document.createElement('div');nameEl.className = 'bg-white border border-gray-200 rounded p-2 text-center text-sm hover:bg-primary/5 transition-colors';nameEl.textContent = name;nameEl.dataset.name = name;studentList.appendChild(nameEl);});studentCount.textContent = students.length;}// 開始/停止點名toggleButton.addEventListener('click', function() {if (students.length === 0) {alert('請先導入學生名單');return;}if (isRolling) {stopRolling();} else {startRolling();}});// 開始滾動function startRolling() {isRolling = true;toggleButton.innerHTML = '<i class="fa fa-stop mr-2"></i><span>停止點名</span>';toggleButton.classList.remove('bg-primary');toggleButton.classList.add('bg-red-500', 'hover:bg-red-600');// 重置之前的選中狀態displayedName.classList.remove('text-primary', 'font-black', 'scale-110');// 開始滾動rollInterval = setInterval(() => {const randomIndex = Math.floor(Math.random() * students.length);displayedName.textContent = students[randomIndex];// 添加動畫效果displayedName.classList.add('animate-pulse');setTimeout(() => {displayedName.classList.remove('animate-pulse');}, 50);}, 600 - rollSpeed); // 反轉速度值,使滑塊右側表示更快}// 停止滾動function stopRolling() {clearInterval(rollInterval);isRolling = false;toggleButton.innerHTML = '<i class="fa fa-play mr-2"></i><span>開始點名</span>';toggleButton.classList.remove('bg-red-500', 'hover:bg-red-600');toggleButton.classList.add('bg-primary', 'hover:bg-primary/90');// 突出顯示選中的名字selectedName = displayedName.textContent;displayedName.classList.add('text-primary', 'font-black', 'scale-110', 'transition-transform', 'duration-500');// 高亮學生列表中的選中項highlightSelectedStudent();}// 高亮選中的學生function highlightSelectedStudent() {const nameElements = studentList.querySelectorAll('[data-name]');nameElements.forEach(el => {if (el.dataset.name === selectedName) {el.classList.add('bg-primary/10', 'border-primary', 'font-bold');el.scrollIntoView({ behavior: 'smooth', block: 'center' });} else {el.classList.remove('bg-primary/10', 'border-primary', 'font-bold');}});}// 重置滾動狀態function resetRollState() {if (isRolling) {clearInterval(rollInterval);isRolling = false;}displayedName.textContent = '準備開始';displayedName.classList.remove('text-primary', 'font-black', 'scale-110');toggleButton.innerHTML = '<i class="fa fa-play mr-2"></i><span>開始點名</span>';toggleButton.classList.remove('bg-red-500', 'hover:bg-red-600');toggleButton.classList.add('bg-primary', 'hover:bg-primary/90');// 清除學生列表中的高亮const nameElements = studentList.querySelectorAll('[data-name]');nameElements.forEach(el => {el.classList.remove('bg-primary/10', 'border-primary', 'font-bold');});}// 速度控制speedControl.addEventListener('input', function() {rollSpeed = parseInt(this.value);// 如果正在滾動,更新速度if (isRolling) {clearInterval(rollInterval);startRolling();}});// 顯示通知function showNotification(message) {// 創建通知元素const notification = document.createElement('div');notification.className = 'fixed top-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg transform transition-all duration-300 translate-x-full opacity-0 z-50';notification.textContent = message;// 添加到頁面document.body.appendChild(notification);// 顯示通知setTimeout(() => {notification.classList.remove('translate-x-full', 'opacity-0');}, 10);// 自動隱藏setTimeout(() => {notification.classList.add('translate-x-full', 'opacity-0');setTimeout(() => {document.body.removeChild(notification);}, 300);}, 3000);}// 清空學生名單clearStudents.addEventListener('click', function() {if (students.length === 0) return;if (confirm('確定要清空當前學生名單嗎?')) {students = [];updateStudentList();resetRollState();showNotification('已清空學生名單');}});// 鍵盤快捷鍵document.addEventListener('keydown', function(e) {// 空格鍵控制開始/停止if (e.code === 'Space') {e.preventDefault();if (students.length > 0) {toggleButton.click();}}});// 示例數據nameList.value = "張三、李四、王五、趙六、錢七、孫八、周九、吳十、鄭十一、王十二";});</script>
</body>
</html>
源碼文件
迅雷下載