| Cỡ chữ:   
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css"> </head> <body> <div id="app-container"> <h1>Chọn đại diện nhóm ngẫu nhiên ????</h1> <p>Nhập tên các thành viên, mỗi tên một dòng:</p> <textarea id="team-members"></textarea> <button id="select-button">Chọn Ngẫu nhiên</button> <div id="roll-display"> <div id="rolling-list"></div> </div> <div id="result"> <p id="result-text">Người được chọn sẽ hiện ở đây!</p> <div id="winner-name"></div> </div> </div> <script src="script.js"></script> </body> </html>
#app-container { background-color: #ffffff; padding: 30px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); width: 90%; max-width: 500px; } textarea { width: 100%; height: 150px; padding: 10px; margin-bottom: 20px; border: 2px solid #ccc; border-radius: 8px; resize: vertical; font-size: 16px; box-sizing: border-box; /* Quan trọng để padding không làm tăng chiều rộng */ } button { background-color: #007bff; color: white; padding: 12px 25px; border: none; border-radius: 8px; cursor: pointer; font-size: 18px; font-weight: bold; transition: background-color 0.3s ease, transform 0.1s; width: 100%; } button:hover { background-color: #0056b3; } button:active { transform: scale(0.98); } #result { margin-top: 25px; text-align: center; min-height: 50px; /* Đảm bảo chiều cao không bị nhảy */ } #result p { font-size: 20px; color: #555; font-weight: 500; } #winner-name { font-size: 36px; color: #28a745; font-weight: bold; margin-top: 10px; /* Hiệu ứng ban đầu */ opacity: 0; transform: scale(0.5); transition: opacity 0.5s ease, transform 0.5s ease; } /* Hiệu ứng khi tên người chiến thắng hiện ra */ .show-winner { opacity: 1 !important; transform: scale(1) !important; animation: pulse 1s infinite alternate; /* Hiệu ứng nhấp nháy nhẹ */ } /* Khung hiển thị hiệu ứng "cuộn" */ #roll-display { display: none; /* Ban đầu ẩn */ flex-direction: column; align-items: center; justify-content: center; margin-top: 20px; height: 100px; /* Chiều cao cố định */ overflow: hidden; border: 2px solid #007bff; border-radius: 8px; background-color: #e9f5ff; font-size: 24px; font-weight: bold; color: #333; width: 100%; position: relative; } /* Hiệu ứng cuộn sử dụng TranslateY */ #rolling-list { position: absolute; top: 0; left: 0; width: 100%; text-align: center; } .rolling { animation: roll-animation 3s forwards cubic-bezier(0.25, 0.1, 0.25, 1); } @keyframes roll-animation { 0% { transform: translateY(0); opacity: 1; } 50% { opacity: 1; } 90% { opacity: 0.5; } 100% { transform: translateY(var(--final-y)); opacity: 0; } } /* Hiệu ứng nhấp nháy nhẹ cho tên người chiến thắng */ @keyframes pulse { from { box-shadow: 0 0 5px #28a745, 0 0 10px #28a745; } to { box-shadow: none; } }
const textarea = document.getElementById('team-members'); const selectButton = document.getElementById('select-button'); const resultText = document.getElementById('result-text'); const winnerNameDiv = document.getElementById('winner-name'); const rollDisplay = document.getElementById('roll-display'); const rollingListDiv = document.getElementById('rolling-list'); let isSelecting = false; // Trạng thái để ngăn chặn nhấn liên tục selectButton.addEventListener('click', selectRandomMember); function selectRandomMember() { if (isSelecting) return; // 1. Lấy danh sách tên const names = textarea.value .split('\n') .map(name => name.trim()) .filter(name => name.length > 0); if (names.length === 0) { alert('Vui lòng nhập tên các thành viên!'); return; } isSelecting = true; selectButton.disabled = true; resultText.textContent = 'Đang chọn...'; winnerNameDiv.textContent = ''; winnerNameDiv.classList.remove('show-winner'); rollDisplay.style.display = 'flex'; // Hiện khung cuộn // 2. Tạo danh sách cuộn tạm thời rollingListDiv.innerHTML = ''; // Lặp lại danh sách vài lần để tạo hiệu ứng cuộn dài const rollCount = 15; for (let i = 0; i < rollCount; i++) { names.forEach(name => { const item = document.createElement('div'); item.textContent = name; item.style.padding = '5px 0'; rollingListDiv.appendChild(item); }); } // 3. Chọn ngẫu nhiên người chiến thắng const randomIndex = Math.floor(Math.random() * names.length); const winner = names[randomIndex]; // 4. Tính toán vị trí dừng của hiệu ứng cuộn (ở đầu danh sách lặp thứ 4) // Ta muốn dừng ở tên người chiến thắng // Vị trí của người chiến thắng trong *một lần* lặp danh sách const winnerIndexInList = names.indexOf(winner); // Giả sử mỗi item cao khoảng 34px (padding 5px + font-size 24px) - Cần điều chỉnh nếu CSS thay đổi const itemHeight = 34; const fullListHeight = names.length * itemHeight; // Vị trí cuộn để tên chiến thắng nằm ngay dưới điểm cuộn ban đầu. // Ta chọn một vòng lặp bất kỳ (ví dụ: vòng lặp thứ 4) để kết thúc const stopLoop = Math.floor(rollCount / 2); // Dừng ở giữa danh sách lặp // Vị trí Y cuối cùng (âm vì cuộn lên) const finalY = -(fullListHeight * stopLoop + winnerIndexInList * itemHeight); // 5. Bắt đầu hiệu ứng cuộn rollingListDiv.style.setProperty('--final-y', `${finalY}px`); rollingListDiv.classList.add('rolling'); // 6. Kết thúc hiệu ứng và hiển thị kết quả sau 3.5 giây (lớn hơn thời gian animation) setTimeout(() => { rollingListDiv.classList.remove('rolling'); rollDisplay.style.display = 'none'; // Ẩn khung cuộn resultText.textContent = 'Người đại diện nhóm là:'; winnerNameDiv.textContent = winner; winnerNameDiv.classList.add('show-winner'); // Hiện tên người chiến thắng isSelecting = false; selectButton.disabled = false; }, 3500); // 3.5 giây cho hiệu ứng hồi hộp } // Tải code mẫu khi ứng dụng được mở window.onload = function() { // Đã có dữ liệu mẫu trong textarea };