|
|
| (未显示同一用户的12个中间版本) |
| 第1行: |
第1行: |
| <includeonly> | | <includeonly> |
| <style> | | <style> |
| .tier-row { | | .tierlist-controls { |
| position: relative;
| | display: flex; |
| background-color: #fafafa;
| | gap: 8px; |
| border: 2px dashed transparent;
| | margin: 8px 0 12px 0; |
| transition: all 0.2s ease;
| |
| display: flex;
| |
| flex-wrap: wrap;
| |
| gap: 5px;
| |
| align-content: flex-start;
| |
| padding: 10px;
| |
| min-height: 80px;
| |
| | |
| .tier-row.drag-over {
| |
| background-color: #e3f2fd;
| |
| border-color: #2196F3;
| |
| }
| |
| | |
| #character-pool {
| |
| position: relative;
| |
| display: flex;
| |
| flex-wrap: wrap;
| |
| gap: 5px;
| |
| align-content: flex-start;
| |
| padding: 10px;
| |
| min-height: 100px;
| |
| } | | } |
| | | .btn { |
| #character-pool.drag-over {
| | display: inline-block; |
| background-color: #fff3e0;
| | padding: 6px 12px; |
| | background: #f0f0f0; |
| | border: 1px solid #ccc; |
| | color: #333; |
| | border-radius: 4px; |
| | cursor: pointer; |
| | user-select: none; |
| } | | } |
| | | .btn:hover { background: #e6e6e6; } |
| | .btn.primary { background: #4a8cf6; color: #fff; border-color: #3b78de; } |
| | .btn.primary:hover { background: #3b78de; } |
| .tierlist-table { | | .tierlist-table { |
| width: 100%;
| | width: 100%; |
| table-layout: fixed;
| | table-layout: fixed; |
| border-collapse: collapse;
| |
| } | | } |
| | | .tier-row .tier-head { |
| .tierlist-table th { | | position: relative; |
| width: 100px;
| | width: 120px; |
| position: relative;
| | color: #fff; |
| vertical-align: top;
| | text-align: center; |
| | font-size: 18px; |
| | font-weight: bold; |
| | padding: 8px; |
| | white-space: nowrap; |
| | border: 1px solid #ccc; |
| | background: #555; |
| } | | } |
| | | .tier-row .tier-cell { |
| .tierlist-table td { | | border: 1px solid #ccc; |
| padding: 0 !important;
| | padding: 0px; |
| vertical-align: top;
| |
| | |
| .tierlist-controls { | |
| margin-bottom: 20px;
| |
| display: flex;
| |
| gap: 10px;
| |
| } | | } |
| | | .tier-tools { |
| .tierlist-btn { | | position: absolute; |
| padding: 10px 20px;
| | right: 6px; |
| font-size: 16px;
| | top: 6px; |
| color: white;
| | display: flex; |
| border: none;
| | gap: 6px; |
| border-radius: 5px;
| |
| cursor: pointer;
| |
| transition: all 0.2s ease;
| |
| display: inline-block;
| |
| text-align: center;
| |
| user-select: none;
| |
| } | | } |
| | | /* 导出时隐藏工具按钮 */ |
| .tierlist-btn-save { | | .exporting .tier-tools { |
| background-color: #4CAF50;
| | display: none !important; |
| } | | } |
| | | .color-toggle { |
| .tierlist-btn-save:hover { | | width: 18px; |
| background-color: #45a049;
| | height: 18px; |
| | border-radius: 3px; |
| | border: 1px solid rgba(0,0,0,0.2); |
| | cursor: pointer; |
| | background: rgba(255,255,255,0.6); |
| } | | } |
| | | .delete-row { |
| .tierlist-btn-reset {
| | font-size: 12px; |
| background-color: #f44336;
| | padding: 2px 6px; |
| | border-radius: 3px; |
| | background: rgba(0,0,0,0.1); |
| | cursor: pointer; |
| } | | } |
| | | .delete-row:hover { background: rgba(0,0,0,0.2); } |
| .tierlist-btn-reset:hover { | | .tier-dropzone { |
| background-color: #da190b;
| | min-height: 112px; |
| | display: flex; |
| | flex-wrap: wrap; |
| | gap: 6px; |
| | align-items: flex-start; |
| | padding: 4px; |
| } | | } |
| | | .tier-dropzone.pool { |
| .tierlist-btn-add { | | border: 2px dashed #ccc; |
| background-color: #2196F3;
| | padding: 8px; |
| | border-radius: 6px; |
| | background: #fafafa; |
| } | | } |
| | | /* 导出时隐藏角色池 */ |
| .tierlist-btn-add:hover { | | .exporting .pool-wrapper { |
| background-color: #0b7dda;
| | display: none !important; |
| } | | } |
| | | .pool-wrapper { margin-top: 12px; } |
| .tierlist-btn-edit { | | .pool-header { |
| background-color: #ff9800;
| | font-weight: bold; |
| | margin-bottom: 6px; |
| } | | } |
| | | .avatar-frame { |
| .tierlist-btn-edit:hover {
| | position: relative; |
| background-color: #e68900;
| | display: inline-block; |
| | vertical-align: top; |
| | border: 3px solid #ccc; |
| | border-radius: 5px; |
| | overflow: hidden; |
| | box-shadow: 0 2px 5px rgba(0,0,0,0.1); |
| | background: #f5f5f5; |
| | transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; |
| | cursor: move; |
| } | | } |
| | | .avatar-frame.dragging { |
| .tierlist-btn-edit.active { | | opacity: 0.7; |
| background-color: #ff5722;
| | transform: scale(1.03); |
| | border-color: #4a8cf6; |
| | z-index: 10; |
| } | | } |
| | | .avatar-frame img { |
| .tierlist-btn:active {
| | display: block; |
| transform: scale(0.98);
| | width: 100px; |
| | height: 100px; |
| | object-fit: cover; |
| | pointer-events: none; |
| | -webkit-user-drag: none; |
| } | | } |
| | | .avatar-name { |
| .character-pool-container { | | position: absolute; |
| background-color: #f9f9f9;
| | left: 0; |
| padding: 15px;
| | bottom: 0; |
| border: 2px dashed #ccc;
| | padding: 2px 8px; |
| border-radius: 5px;
| | color: white; |
| margin-top: 20px;
| | font-size: 12px; |
| | font-weight: bold; |
| | text-shadow: 0 0 2px black, 0 0 2px black; |
| | white-space: nowrap; |
| | max-width: 100%; |
| | overflow: hidden; |
| | text-overflow: ellipsis; |
| | border-top-right-radius: 3px; |
| } | | } |
| | | .color-palette { |
| .character-pool-container h3 { | | position: absolute; |
| margin-top: 0;
| | display: none; |
| color: #333;
| | gap: 6px; |
| | flex-wrap: wrap; |
| | width: 210px; |
| | padding: 8px; |
| | background: #fff; |
| | border: 1px solid #ccc; |
| | box-shadow: 0 2px 8px rgba(0,0,0,0.15); |
| | border-radius: 6px; |
| | z-index: 9999; |
| } | | } |
| | | .color-swatch { |
| /* 编辑模式下的样式 */
| | width: 24px; height: 24px; |
| .tier-header.editable {
| | border-radius: 4px; |
| cursor: pointer;
| | border: 1px solid rgba(0,0,0,0.2); |
| position: relative;
| | cursor: pointer; |
| } | | } |
| | | .color-swatch:hover { outline: 2px solid rgba(0,0,0,0.2); } |
| .tier-header.editable:hover::after { | | .tier-label { |
| content: '✎';
| | display: inline-block; |
| position: absolute;
| | padding: 2px 6px; |
| right: 5px;
| | border-radius: 3px; |
| top: 50%;
| | background: rgba(255,255,255,0.15); |
| transform: translateY(-50%);
| |
| font-size: 16px;
| |
| } | | } |
| | | .tier-label[contenteditable="true"] { |
| .delete-row-btn { | | outline: none; |
| position: absolute;
| | cursor: text; |
| right: 5px;
| |
| top: 50%;
| |
| transform: translateY(-50%);
| |
| background-color: #f44336;
| |
| color: white;
| |
| border: none;
| |
| border-radius: 3px;
| |
| padding: 3px 8px;
| |
| cursor: pointer;
| |
| font-size: 12px;
| |
| display: none;
| |
| z-index: 100;
| |
| } | | } |
| | </style> |
|
| |
|
| .edit-mode .delete-row-btn { | | <script> |
| display: block; | | (function() { |
| } | | function ready(fn) { |
| | if (document.readyState !== 'loading') fn(); |
| | else document.addEventListener('DOMContentLoaded', fn); |
| | } |
| | function contrastColor(hex) { |
| | hex = (hex || '').replace('#',''); |
| | if (hex.length === 3) hex = hex.split('').map(c => c + c).join(''); |
| | if (!/^[0-9a-fA-F]{6}$/.test(hex)) return '#fff'; |
| | var r = parseInt(hex.substr(0,2), 16); |
| | var g = parseInt(hex.substr(2,2), 16); |
| | var b = parseInt(hex.substr(4,2), 16); |
| | var yiq = ((r*299)+(g*587)+(b*114))/1000; |
| | return yiq >= 128 ? '#000' : '#fff'; |
| | } |
| | function getDragAfterElement(container, y) { |
| | const elements = [...container.querySelectorAll('.avatar-frame:not(.dragging)')]; |
| | return elements.reduce((closest, child) => { |
| | const box = child.getBoundingClientRect(); |
| | const offset = y - box.top - box.height/2; |
| | if (offset < 0 && offset > closest.offset) { |
| | return { offset: offset, element: child }; |
| | } else { |
| | return closest; |
| | } |
| | }, { offset: Number.NEGATIVE_INFINITY, element: null }).element; |
| | } |
| | function ensureCrossOrigin(img) { |
| | try { |
| | if (!img) return; |
| | if (!img.crossOrigin) img.crossOrigin = 'anonymous'; |
| | if (!img.referrerPolicy) img.referrerPolicy = 'no-referrer'; |
| | } catch(e) {} |
| | } |
| | function makeDraggable(avatar) { |
| | if (!avatar || avatar._draggableInit) return; |
| | avatar._draggableInit = true; |
| | avatar.setAttribute('draggable', 'true'); |
| | avatar.classList.add('draggable-avatar'); |
| | avatar.querySelectorAll('img').forEach(ensureCrossOrigin); |
|
| |
|
| .delete-row-btn:hover { | | avatar.addEventListener('dragstart', function(e) { |
| background-color: #da190b; | | avatar.classList.add('dragging'); |
| } | | avatar._prevParent = avatar.parentNode; |
| | e.dataTransfer.setData('text/plain', avatar.dataset.id || avatar.querySelector('.avatar-name')?.textContent || ''); |
| | e.dataTransfer.effectAllowed = 'move'; |
| | }); |
| | avatar.addEventListener('dragend', function() { |
| | avatar.classList.remove('dragging'); |
| | cleanupEmptyWrapper(avatar._prevParent); |
| | avatar._prevParent = null; |
| | }); |
| | } |
| | function initAvatars(root) { |
| | if (!root) return; |
| | const avatars = root.querySelectorAll('.avatar-frame'); |
| | avatars.forEach(function(av) { |
| | if (!av.dataset.id) { |
| | const nameEl = av.querySelector('.avatar-name'); |
| | av.dataset.name = nameEl ? nameEl.textContent.trim() : ''; |
| | } |
| | makeDraggable(av); |
| | }); |
| | } |
| | function cleanupEmptyWrapper(node) { |
| | if (!node || node.nodeType !== 1) return; |
| | if (node.classList && node.classList.contains('tier-dropzone')) return; |
| | const hasElementChild = node.querySelector('.avatar-frame'); |
| | const onlyWhitespace = !node.textContent || node.textContent.trim().length === 0; |
| | if (!hasElementChild && node.childElementCount === 0 && onlyWhitespace) { |
| | node.parentNode && node.parentNode.removeChild(node); |
| | } |
| | } |
| | function cleanupEmptyPlaceholdersIn(container) { |
| | if (!container) return; |
| | Array.from(container.children).forEach(function(child) { |
| | if (child.nodeType !== 1) return; |
| | if (child.classList.contains('avatar-frame')) return; |
| | const hasAvatarInside = !!child.querySelector('.avatar-frame'); |
| | const onlyWhitespace = !child.textContent || child.textContent.trim().length === 0; |
| | if (!hasAvatarInside && child.childElementCount === 0 && onlyWhitespace) { |
| | child.remove(); |
| | } |
| | }); |
| | } |
| | function initDropzone(zone) { |
| | if (!zone || zone._dropzoneInit) return; |
| | zone._dropzoneInit = true; |
|
| |
|
| /* 颜色选择器容器 */
| | zone.addEventListener('dragover', function(e) { |
| .color-picker-popup { | | e.preventDefault(); |
| position: fixed;
| | e.dataTransfer.dropEffect = 'move'; |
| top: 50%;
| | const afterElement = getDragAfterElement(zone, e.clientY); |
| left: 50%;
| | const dragging = document.querySelector('.avatar-frame.dragging'); |
| transform: translate(-50%, -50%);
| | if (!dragging) return; |
| background: white;
| | if (afterElement == null) { |
| padding: 20px;
| | if (dragging.parentNode !== zone) zone.appendChild(dragging); |
| border-radius: 8px;
| | } else { |
| box-shadow: 0 4px 20px rgba(0,0,0,0.3);
| | if (afterElement !== dragging) zone.insertBefore(dragging, afterElement); |
| z-index: 1000;
| | } |
| min-width: 300px; | | }); |
| }
| |
|
| |
|
| .color-picker-popup h4 { | | zone.addEventListener('drop', function(e) { |
| margin-top: 0; | | e.preventDefault(); |
| } | | e.stopPropagation(); |
| | const dragging = document.querySelector('.avatar-frame.dragging'); |
| | if (dragging) { |
| | if (dragging.parentNode !== zone) zone.appendChild(dragging); |
| | cleanupEmptyWrapper(dragging._prevParent); |
| | dragging._prevParent = null; |
| | } |
| | if (zone.classList.contains('pool')) { |
| | cleanupEmptyPlaceholdersIn(zone); |
| | } |
| | }); |
| | } |
| | function buildEditableHead(th) { |
| | const currentText = (th.childNodes[0] && th.childNodes[0].nodeType === 3) |
| | ? th.childNodes[0].nodeValue.trim() |
| | : th.textContent.trim(); |
| | const tools = th.querySelector('.tier-tools'); |
| | th.innerHTML = ''; |
| | const label = document.createElement('div'); |
| | label.className = 'tier-label'; |
| | label.setAttribute('contenteditable', 'true'); |
| | label.textContent = currentText || '未命名'; |
| | const toolsWrap = tools || (function() { |
| | const t = document.createElement('div'); |
| | t.className = 'tier-tools'; |
| | const color = document.createElement('div'); |
| | color.className = 'color-toggle'; |
| | color.title = '更改颜色'; |
| | const del = document.createElement('div'); |
| | del.className = 'delete-row'; |
| | del.textContent = '删除'; |
| | del.title = '删除该行'; |
| | t.appendChild(color); t.appendChild(del); |
| | return t; |
| | })(); |
| | th.appendChild(label); |
| | th.appendChild(toolsWrap); |
| | const initialBg = th.getAttribute('data-initial-bg') || '#555'; |
| | th.style.background = initialBg; |
| | th.style.color = contrastColor(initialBg); |
| | attachColorPalette(toolsWrap.querySelector('.color-toggle'), th); |
| | const delBtn = toolsWrap.querySelector('.delete-row'); |
| | delBtn.addEventListener('click', function() { |
| | const tr = th.closest('tr'); |
| | const dropzone = tr.querySelector('.tier-dropzone'); |
| | const pool = document.getElementById('character-pool'); |
| | Array.from(dropzone.querySelectorAll('.avatar-frame')).forEach(function(av) { |
| | pool.appendChild(av); |
| | }); |
| | tr.parentNode.removeChild(tr); |
| | }); |
| | } |
| | function attachColorPalette(toggle, th) { |
| | if (!toggle) return; |
| | const palette = document.createElement('div'); |
| | palette.className = 'color-palette'; |
| | const colors = [ |
| | '#e53935','#d81b60','#8e24aa','#5e35b1','#3949ab','#1e88e5','#039be5','#00acc1', |
| | '#00897b','#43a047','#7cb342','#c0ca33','#fdd835','#fb8c00','#f4511e','#6d4c41', |
| | '#546e7a','#9e9e9e','#000000','#ffffff' |
| | ]; |
| | colors.forEach(function(c) { |
| | const sw = document.createElement('div'); |
| | sw.className = 'color-swatch'; |
| | sw.style.background = c; |
| | sw.addEventListener('click', function() { |
| | th.style.background = c; |
| | th.style.color = contrastColor(c); |
| | palette.style.display = 'none'; |
| | }); |
| | palette.appendChild(sw); |
| | }); |
| | document.body.appendChild(palette); |
| | function placePalette() { |
| | const rect = toggle.getBoundingClientRect(); |
| | palette.style.left = (window.scrollX + rect.left) + 'px'; |
| | palette.style.top = (window.scrollY + rect.bottom + 6) + 'px'; |
| | } |
| | toggle.addEventListener('click', function(e) { |
| | e.stopPropagation(); |
| | if (palette.style.display === 'block') { |
| | palette.style.display = 'none'; |
| | } else { |
| | placePalette(); |
| | palette.style.display = 'block'; |
| | } |
| | }); |
| | document.addEventListener('click', function(e) { |
| | if (e.target === toggle || palette.contains(e.target)) return; |
| | palette.style.display = 'none'; |
| | }); |
| | window.addEventListener('scroll', function() { |
| | if (palette.style.display === 'block') placePalette(); |
| | }); |
| | window.addEventListener('resize', function() { |
| | if (palette.style.display === 'block') placePalette(); |
| | }); |
| | } |
| | function addNewRow() { |
| | const tbody = document.querySelector('#tierlist-table tbody') || document.querySelector('#tierlist-table'); |
| | const tr = document.createElement('tr'); |
| | tr.className = 'tier-row'; |
| | const th = document.createElement('th'); |
| | th.className = 'tier-head'; |
| | th.setAttribute('data-initial-bg', '#8888ff'); |
| | th.textContent = '新行'; |
| | const td = document.createElement('td'); |
| | td.className = 'tier-cell'; |
| | const dz = document.createElement('div'); |
| | dz.className = 'tier-dropzone'; |
| | dz.setAttribute('data-tier', 'CUSTOM'); |
| | td.appendChild(dz); |
| | tr.appendChild(th); |
| | tr.appendChild(td); |
| | tbody.appendChild(tr); |
| | initDropzone(dz); |
| | buildEditableHead(th); |
| | } |
| | function ensureHtml2Canvas(cb) { |
| | if (window.html2canvas) { cb(); return; } |
| | var s = document.createElement('script'); |
| | s.src = 'https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js'; |
| | s.onload = cb; |
| | s.onerror = function() { |
| | alert('加载截图库失败,请检查网络或跨域策略。'); |
| | }; |
| | document.body.appendChild(s); |
| | } |
| | function downloadCanvas(canvas) { |
| | function done(blobOrUrl) { |
| | try { |
| | const link = document.createElement('a'); |
| | const isBlob = blobOrUrl instanceof Blob; |
| | const url = isBlob ? (URL.createObjectURL(blobOrUrl)) : blobOrUrl; |
| | link.href = url; |
| | link.download = 'tierlist.png'; |
| | document.body.appendChild(link); |
| | link.click(); |
| | document.body.removeChild(link); |
| | if (isBlob) setTimeout(() => URL.revokeObjectURL(url), 0); |
| | } catch (e) { |
| | const dataUrl = canvas.toDataURL('image/png'); |
| | window.open(dataUrl, '_blank'); |
| | } |
| | } |
| | if (canvas.toBlob) { |
| | canvas.toBlob(function(blob) { |
| | if (blob) done(blob); |
| | else done(canvas.toDataURL('image/png')); |
| | }, 'image/png'); |
| | } else { |
| | done(canvas.toDataURL('image/png')); |
| | } |
| | } |
| | function prepareImagesForExport(container) { |
| | if (!container) return; |
| | container.querySelectorAll('img').forEach(ensureCrossOrigin); |
| | } |
| | function savePNG() { |
| | const maker = document.getElementById('tierlist-maker'); |
| | const table = document.getElementById('tierlist-table'); |
| | if (!table) { |
| | alert('未找到要导出的表格。'); |
| | return; |
| | } |
| | |
| | // 添加导出样式类 |
| | maker.classList.add('exporting'); |
| | prepareImagesForExport(table); |
| | |
| | ensureHtml2Canvas(function() { |
| | // 稍微延迟以确保CSS生效 |
| | setTimeout(function() { |
| | html2canvas(table, { |
| | backgroundColor: '#ffffff', |
| | scale: 2, |
| | useCORS: true, |
| | allowTaint: false, |
| | imageTimeout: 15000 |
| | }).then(function(canvas) { |
| | downloadCanvas(canvas); |
| | }).catch(function(err) { |
| | console.error('html2canvas 失败', err); |
| | alert('保存PNG失败:' + (err && err.message ? err.message : '未知错误')); |
| | }).finally(function() { |
| | maker.classList.remove('exporting'); |
| | }); |
| | }, 100); |
| | }); |
| | } |
| | function resetAll() { |
| | const pool = document.getElementById('character-pool'); |
| | if (!pool) return; |
| | const rows = document.querySelectorAll('#tierlist-table .tier-dropzone'); |
| | rows.forEach(function(zone) { |
| | if (zone.classList.contains('pool')) return; |
| | Array.from(zone.querySelectorAll('.avatar-frame')).forEach(function(av) { |
| | pool.appendChild(av); |
| | }); |
| | cleanupEmptyPlaceholdersIn(zone); |
| | }); |
| | cleanupEmptyPlaceholdersIn(pool); |
| | } |
|
| |
|
| .color-picker-popup label { | | ready(function() { |
| display: block; | | document.querySelectorAll('#tierlist-table .tier-head').forEach(buildEditableHead); |
| margin: 10px 0 5px 0; | | document.querySelectorAll('.tier-dropzone').forEach(initDropzone); |
| }
| | initAvatars(document.getElementById('character-pool')); |
|
| |
|
| .color-picker-popup input[type="text"],
| | var addBtn = document.getElementById('add-row'); |
| .color-picker-popup input[type="color"] { | | if (addBtn) addBtn.addEventListener('click', addNewRow); |
| width: 100%;
| | var saveBtn = document.getElementById('save-png'); |
| padding: 5px; | | if (saveBtn) saveBtn.addEventListener('click', savePNG); |
| margin-bottom: 10px; | |
| box-sizing: border-box; | |
| }
| |
|
| |
|
| .color-picker-popup .button-group { | | (function insertResetButton() { |
| display: flex;
| | const controls = document.querySelector('#tierlist-maker .tierlist-controls'); |
| gap: 10px;
| | if (!controls || document.getElementById('reset-roles')) return; |
| margin-top: 15px;
| | const resetBtn = document.createElement('div'); |
| } | | resetBtn.id = 'reset-roles'; |
| | resetBtn.className = 'btn'; |
| | resetBtn.textContent = '重置'; |
| | controls.insertBefore(resetBtn, controls.querySelector('#save-png') || null); |
| | resetBtn.addEventListener('click', resetAll); |
| | })(); |
|
| |
|
| .color-picker-popup button {
| | const pool = document.getElementById('character-pool'); |
| flex: 1; | | if (pool) { |
| padding: 8px;
| | const obs = new MutationObserver(function(muts) { |
| border: none;
| | muts.forEach(function(m) { |
| border-radius: 4px;
| | if (m.addedNodes && m.addedNodes.length) { |
| cursor: pointer;
| | m.addedNodes.forEach(function(n) { |
| font-size: 14px;
| | if (n.nodeType === 1) { |
| }
| | if (n.classList.contains('avatar-frame')) { |
| | | makeDraggable(n); |
| .color-picker-popup .btn-confirm { | |
| background-color: #4CAF50;
| |
| color: white;
| |
| }
| |
| | |
| .color-picker-popup .btn-cancel {
| |
| background-color: #f44336;
| |
| color: white;
| |
| }
| |
| | |
| .overlay {
| |
| position: fixed;
| |
| top: 0;
| |
| left: 0;
| |
| right: 0;
| |
| bottom: 0;
| |
| background: rgba(0,0,0,0.5);
| |
| z-index: 999;
| |
| }
| |
| | |
| /* 确保avatar-frame正确显示 */
| |
| .avatar-frame {
| |
| display: inline-block;
| |
| margin: 0;
| |
| cursor: move; /* 显示可移动光标 */
| |
| }
| |
| | |
| .avatar-frame.dragging {
| |
| opacity: 0.5;
| |
| }
| |
| | |
| /* 空的tier-row显示提示 */
| |
| .tier-row:empty::before {
| |
| content: '拖放角色到这里';
| |
| color: #999;
| |
| font-size: 14px;
| |
| position: absolute;
| |
| left: 50%;
| |
| top: 50%;
| |
| transform: translate(-50%, -50%);
| |
| pointer-events: none;
| |
| }
| |
| </style>
| |
| | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
| |
| | |
| <script>
| |
| (function() {
| |
| 'use strict';
| |
|
| |
| if (window.TierlistMakerInitialized) { | |
| console.log('TierlistMaker already initialized');
| |
| return;
| |
| }
| |
|
| |
| const TierlistMaker = {
| |
| draggedElement: null,
| |
| sourceContainer: null,
| |
| editMode: false,
| |
| initRetryCount: 0,
| |
| maxRetries: 10,
| |
|
| |
| init: function() {
| |
| if (document.readyState === 'loading') {
| |
| document.addEventListener('DOMContentLoaded', () => this.setup());
| |
| } else {
| |
| this.setup();
| |
| }
| |
| },
| |
|
| |
| setup: function() {
| |
| const characterPool = document.getElementById('character-pool');
| |
| const avatars = characterPool ? characterPool.querySelectorAll('.avatar-frame') : [];
| |
|
| |
| if (avatars.length === 0 && this.initRetryCount < this.maxRetries) {
| |
| this.initRetryCount++;
| |
| console.log('等待角色加载...', this.initRetryCount);
| |
| setTimeout(() => this.setup(), 300);
| |
| return;
| |
| }
| |
|
| |
| console.log('找到角色数量:', avatars.length);
| |
|
| |
| this.cleanupContainers();
| |
| this.initDragAndDrop();
| |
| this.initButtons();
| |
| },
| |
|
| |
| cleanupContainers: function() {
| |
| const containers = document.querySelectorAll('.tier-row, #character-pool'); | |
| containers.forEach(container => {
| |
| const children = Array.from(container.childNodes);
| |
| children.forEach(child => {
| |
| if (child.nodeType === Node.TEXT_NODE && !child.textContent.trim()) {
| |
| container.removeChild(child);
| |
| } else if (child.nodeType === Node.ELEMENT_NODE) {
| |
| if (!child.classList.contains('avatar-frame') &&
| |
| !child.querySelector('.avatar-frame') &&
| |
| !child.textContent.trim()) {
| |
| container.removeChild(child);
| |
| }
| |
| }
| |
| });
| |
| });
| |
| },
| |
|
| |
| initDragAndDrop: function() {
| |
| console.log('初始化拖拽功能...');
| |
|
| |
| // 初始化所有avatar的拖拽
| |
| this.initAvatarsDraggable();
| |
|
| |
| // 初始化所有drop区域
| |
| this.initDropZones();
| |
| },
| |
|
| |
| // 初始化所有avatar元素的拖拽功能
| |
| initAvatarsDraggable: function() {
| |
| const allAvatars = document.querySelectorAll('.avatar-frame');
| |
| console.log('设置可拖拽的角色数量:', allAvatars.length);
| |
|
| |
| allAvatars.forEach(avatar => {
| |
| if (!avatar.hasAttribute('draggable')) {
| |
| avatar.setAttribute('draggable', 'true');
| |
|
| |
| // 移除旧的事件监听器(如果存在)
| |
| avatar.ondragstart = null;
| |
| avatar.ondragend = null;
| |
|
| |
| // 添加新的事件监听器
| |
| avatar.addEventListener('dragstart', (e) => {
| |
| this.handleDragStart(e, avatar);
| |
| });
| |
|
| |
| avatar.addEventListener('dragend', (e) => {
| |
| this.handleDragEnd(e, avatar);
| |
| });
| |
|
| |
| console.log('已设置拖拽:', avatar);
| |
| } | | } |
| | n.querySelectorAll && n.querySelectorAll('.avatar-frame').forEach(makeDraggable); |
| | if (pool.contains(n)) cleanupEmptyPlaceholdersIn(pool); |
| | } |
| }); | | }); |
| },
| | } |
|
| | }); |
| // 初始化所有drop区域
| | }); |
| initDropZones: function() {
| | obs.observe(pool, { childList: true, subtree: true }); |
| // 为所有tier行添加drop事件
| | } |
| const tierRows = document.querySelectorAll('.tier-row');
| | }); |
| console.log('初始化drop区域数量:', tierRows.length);
| |
|
| |
| tierRows.forEach(row => {
| |
| // 移除旧的事件监听器
| |
| const newRow = row.cloneNode(true);
| |
| row.parentNode.replaceChild(newRow, row);
| |
|
| |
| // 添加新的事件监听器
| |
| newRow.addEventListener('dragover', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| e.dataTransfer.dropEffect = 'move';
| |
| newRow.classList.add('drag-over');
| |
| });
| |
|
| |
| newRow.addEventListener('dragleave', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| // 检查是否真的离开了该元素
| |
| const rect = newRow.getBoundingClientRect();
| |
| if (e.clientX < rect.left || e.clientX >= rect.right ||
| |
| e.clientY < rect.top || e.clientY >= rect.bottom) {
| |
| newRow.classList.remove('drag-over');
| |
| }
| |
| });
| |
|
| |
| newRow.addEventListener('drop', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| this.handleDrop(e, newRow);
| |
| });
| |
|
| |
| // 重新设置该行中已有avatar的拖拽
| |
| newRow.querySelectorAll('.avatar-frame').forEach(avatar => {
| |
| if (!avatar.hasAttribute('draggable')) {
| |
| avatar.setAttribute('draggable', 'true');
| |
| avatar.addEventListener('dragstart', (e) => this.handleDragStart(e, avatar));
| |
| avatar.addEventListener('dragend', (e) => this.handleDragEnd(e, avatar));
| |
| }
| |
| });
| |
| });
| |
|
| |
| // 为角色池添加drop事件
| |
| const characterPool = document.getElementById('character-pool');
| |
| if (characterPool) {
| |
| // 移除旧的事件监听器
| |
| const newPool = characterPool.cloneNode(true);
| |
| characterPool.parentNode.replaceChild(newPool, characterPool);
| |
|
| |
| newPool.addEventListener('dragover', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| e.dataTransfer.dropEffect = 'move';
| |
| newPool.classList.add('drag-over');
| |
| });
| |
|
| |
| newPool.addEventListener('dragleave', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| const rect = newPool.getBoundingClientRect();
| |
| if (e.clientX < rect.left || e.clientX >= rect.right ||
| |
| e.clientY < rect.top || e.clientY >= rect.bottom) {
| |
| newPool.classList.remove('drag-over');
| |
| }
| |
| });
| |
|
| |
| newPool.addEventListener('drop', (e) => {
| |
| e.preventDefault();
| |
| e.stopPropagation();
| |
| this.handleDrop(e, newPool);
| |
| });
| |
|
| |
| // 重新设置角色池中avatar的拖拽
| |
| newPool.querySelectorAll('.avatar-frame').forEach(avatar => {
| |
| if (!avatar.hasAttribute('draggable')) {
| |
| avatar.setAttribute('draggable', 'true');
| |
| avatar.addEventListener('dragstart', (e) => this.handleDragStart(e, avatar));
| |
| avatar.addEventListener('dragend', (e) => this.handleDragEnd(e, avatar));
| |
| }
| |
| });
| |
| }
| |
| },
| |
|
| |
| handleDragStart: function(e, element) {
| |
| console.log('开始拖拽:', element);
| |
| this.draggedElement = element;
| |
| this.sourceContainer = element.parentElement;
| |
| element.classList.add('dragging');
| |
| e.dataTransfer.effectAllowed = 'move';
| |
| e.dataTransfer.setData('text/html', element.innerHTML);
| |
| },
| |
|
| |
| handleDragEnd: function(e, element) {
| |
| console.log('结束拖拽');
| |
| element.classList.remove('dragging');
| |
|
| |
| document.querySelectorAll('.drag-over').forEach(el => {
| |
| el.classList.remove('drag-over');
| |
| });
| |
|
| |
| this.cleanupContainers();
| |
| this.saveState();
| |
|
| |
| this.draggedElement = null;
| |
| this.sourceContainer = null;
| |
| },
| |
|
| |
| handleDrop: function(e, targetContainer) {
| |
| console.log('放置到:', targetContainer);
| |
|
| |
| targetContainer.classList.remove('drag-over');
| |
|
| |
| if (this.draggedElement && this.draggedElement.parentElement !== targetContainer) {
| |
| // 从原位置移除
| |
| if (this.draggedElement.parentElement) {
| |
| this.draggedElement.parentElement.removeChild(this.draggedElement);
| |
| }
| |
|
| |
| // 添加到新位置
| |
| targetContainer.appendChild(this.draggedElement);
| |
|
| |
| // 确保样式正常
| |
| this.draggedElement.style.opacity = '1';
| |
| const img = this.draggedElement.querySelector('img');
| |
| if (img) {
| |
| img.style.opacity = '1';
| |
| }
| |
|
| |
| this.cleanupContainers();
| |
|
| |
| console.log('放置成功');
| |
| }
| |
| },
| |
|
| |
| initButtons: function() {
| |
| const saveBtn = document.getElementById('save-tierlist-btn');
| |
| const resetBtn = document.getElementById('reset-tierlist-btn');
| |
| const addRowBtn = document.getElementById('add-row-btn');
| |
| const editModeBtn = document.getElementById('edit-mode-btn');
| |
|
| |
| if (saveBtn) {
| |
| saveBtn.onclick = () => this.saveTierlist();
| |
| }
| |
|
| |
| if (resetBtn) {
| |
| resetBtn.onclick = () => this.resetTierlist();
| |
| }
| |
|
| |
| if (addRowBtn) {
| |
| addRowBtn.onclick = () => this.addRow();
| |
| }
| |
|
| |
| if (editModeBtn) {
| |
| editModeBtn.onclick = () => this.toggleEditMode();
| |
| }
| |
| },
| |
|
| |
| toggleEditMode: function() {
| |
| this.editMode = !this.editMode;
| |
| const btn = document.getElementById('edit-mode-btn');
| |
| const table = document.getElementById('tierlist-table');
| |
|
| |
| if (this.editMode) {
| |
| btn.classList.add('active');
| |
| btn.textContent = '完成编辑';
| |
| table.classList.add('edit-mode');
| |
|
| |
| document.querySelectorAll('.tier-header').forEach(header => {
| |
| header.classList.add('editable');
| |
| if (!header.querySelector('.delete-row-btn')) {
| |
| const deleteBtn = document.createElement('button');
| |
| deleteBtn.className = 'delete-row-btn';
| |
| deleteBtn.textContent = '删除';
| |
| deleteBtn.onclick = (e) => {
| |
| e.stopPropagation();
| |
| this.deleteRow(header.closest('tr'));
| |
| };
| |
| header.appendChild(deleteBtn);
| |
| }
| |
|
| |
| header.onclick = () => this.editTierHeader(header);
| |
| });
| |
| } else {
| |
| btn.classList.remove('active');
| |
| btn.textContent = '编辑模式';
| |
| table.classList.remove('edit-mode');
| |
|
| |
| document.querySelectorAll('.tier-header').forEach(header => {
| |
| header.classList.remove('editable');
| |
| header.onclick = null;
| |
| });
| |
| }
| |
| },
| |
|
| |
| editTierHeader: function(header) {
| |
| const currentText = header.textContent.replace('删除', '').trim();
| |
| const currentBgColor = header.style.backgroundColor || '#000000';
| |
|
| |
| const overlay = document.createElement('div');
| |
| overlay.className = 'overlay';
| |
|
| |
| const popup = document.createElement('div');
| |
| popup.className = 'color-picker-popup';
| |
| popup.innerHTML = `
| |
| <h4>编辑Tier</h4>
| |
| <label>Tier名称:</label>
| |
| <input type="text" id="tier-name-input" value="${currentText}" maxlength="10">
| |
| <label>背景颜色:</label>
| |
| <input type="color" id="tier-color-input" value="${this.rgbToHex(currentBgColor)}">
| |
| <div class="button-group">
| |
| <button class="btn-confirm">确定</button>
| |
| <button class="btn-cancel">取消</button>
| |
| </div>
| |
| `;
| |
|
| |
| document.body.appendChild(overlay);
| |
| document.body.appendChild(popup);
| |
|
| |
| const nameInput = popup.querySelector('#tier-name-input');
| |
| const colorInput = popup.querySelector('#tier-color-input');
| |
|
| |
| popup.querySelector('.btn-confirm').onclick = () => {
| |
| const newName = nameInput.value.trim();
| |
| const newColor = colorInput.value;
| |
|
| |
| if (newName) {
| |
| header.setAttribute('data-tier', newName);
| |
| const deleteBtn = header.querySelector('.delete-row-btn');
| |
| if (deleteBtn) deleteBtn.remove();
| |
| header.textContent = newName;
| |
| header.style.backgroundColor = newColor;
| |
|
| |
| const newDeleteBtn = document.createElement('button');
| |
| newDeleteBtn.className = 'delete-row-btn';
| |
| newDeleteBtn.textContent = '删除';
| |
| newDeleteBtn.onclick = (e) => {
| |
| e.stopPropagation();
| |
| this.deleteRow(header.closest('tr'));
| |
| };
| |
| header.appendChild(newDeleteBtn);
| |
|
| |
| const row = header.closest('tr').querySelector('.tier-row');
| |
| if (row) {
| |
| row.setAttribute('data-tier', newName);
| |
| }
| |
|
| |
| this.saveState();
| |
| }
| |
|
| |
| document.body.removeChild(overlay);
| |
| document.body.removeChild(popup);
| |
| };
| |
|
| |
| popup.querySelector('.btn-cancel').onclick = () => {
| |
| document.body.removeChild(overlay);
| |
| document.body.removeChild(popup);
| |
| };
| |
|
| |
| overlay.onclick = () => {
| |
| document.body.removeChild(overlay);
| |
| document.body.removeChild(popup);
| |
| };
| |
|
| |
| nameInput.focus();
| |
| nameInput.select();
| |
| },
| |
|
| |
| rgbToHex: function(rgb) {
| |
| if (rgb.startsWith('#')) return rgb;
| |
|
| |
| const values = rgb.match(/\d+/g);
| |
| if (!values || values.length < 3) return '#000000';
| |
|
| |
| const r = parseInt(values[0]).toString(16).padStart(2, '0');
| |
| const g = parseInt(values[1]).toString(16).padStart(2, '0');
| |
| const b = parseInt(values[2]).toString(16).padStart(2, '0');
| |
|
| |
| return '#' + r + g + b;
| |
| },
| |
|
| |
| addRow: function() {
| |
| const table = document.getElementById('tierlist-table');
| |
| if (!table) return;
| |
|
| |
| const tbody = table.querySelector('tbody');
| |
| const tierCount = document.querySelectorAll('.tier-row').length;
| |
| const tierName = 'T' + (tierCount + 1);
| |
|
| |
| const newRow = document.createElement('tr');
| |
| newRow.innerHTML = `
| |
| <th style="width: 100px; background-color: #9e9e9e; color: white; font-size: 20px; text-align: center" class="tier-header" data-tier="${tierName}">${tierName}</th>
| |
| <td class="tier-row" data-tier="${tierName}"></td>
| |
| `;
| |
|
| |
| tbody.appendChild(newRow);
| |
|
| |
| console.log('添加新行:', tierName);
| |
|
| |
| // 重新初始化所有drop区域(包括新行)
| |
| this.initDropZones();
| |
|
| |
| // 如果在编辑模式下,添加编辑功能
| |
| if (this.editMode) {
| |
| const header = newRow.querySelector('.tier-header');
| |
| header.classList.add('editable');
| |
|
| |
| const deleteBtn = document.createElement('button');
| |
| deleteBtn.className = 'delete-row-btn';
| |
| deleteBtn.textContent = '删除';
| |
| deleteBtn.onclick = (e) => {
| |
| e.stopPropagation();
| |
| this.deleteRow(newRow);
| |
| };
| |
| header.appendChild(deleteBtn);
| |
|
| |
| header.onclick = () => this.editTierHeader(header);
| |
| }
| |
|
| |
| this.saveState();
| |
| }, | |
|
| |
| deleteRow: function(row) {
| |
| if (!confirm('确定要删除这一行吗?行内的角色将移回角色池。')) {
| |
| return;
| |
| }
| |
|
| |
| const tierRow = row.querySelector('.tier-row');
| |
| const avatars = Array.from(tierRow.querySelectorAll('.avatar-frame'));
| |
| const pool = document.getElementById('character-pool');
| |
|
| |
| avatars.forEach(avatar => {
| |
| pool.appendChild(avatar);
| |
| });
| |
|
| |
| row.remove();
| |
|
| |
| this.cleanupContainers();
| |
| this.saveState();
| |
| },
| |
|
| |
| saveState: function() {
| |
| const state = {
| |
| rows: [],
| |
| pool: []
| |
| };
| |
|
| |
| document.querySelectorAll('#tierlist-table tbody tr').forEach(row => {
| |
| const header = row.querySelector('.tier-header');
| |
| const tierRow = row.querySelector('.tier-row');
| |
|
| |
| if (!header || !tierRow) return;
| |
|
| |
| const rowData = {
| |
| name: header.getAttribute('data-tier'),
| |
| bgColor: header.style.backgroundColor,
| |
| characters: []
| |
| };
| |
|
| |
| tierRow.querySelectorAll('.avatar-frame').forEach(avatar => {
| |
| const charId = this.getCharacterId(avatar);
| |
| if (charId) {
| |
| rowData.characters.push(charId);
| |
| }
| |
| });
| |
|
| |
| state.rows.push(rowData);
| |
| });
| |
|
| |
| const pool = document.getElementById('character-pool');
| |
| if (pool) {
| |
| pool.querySelectorAll('.avatar-frame').forEach(avatar => {
| |
| const charId = this.getCharacterId(avatar);
| |
| if (charId) {
| |
| state.pool.push(charId);
| |
| }
| |
| });
| |
| }
| |
|
| |
| try {
| |
| localStorage.setItem('tierlist-state', JSON.stringify(state));
| |
| console.log('状态已保存');
| |
| } catch (e) {
| |
| console.warn('无法保存状态:', e);
| |
| }
| |
| },
| |
|
| |
| loadState: function() {
| |
| try {
| |
| const stateJson = localStorage.getItem('tierlist-state');
| |
| if (!stateJson) {
| |
| console.log('没有保存的状态');
| |
| return;
| |
| }
| |
|
| |
| const state = JSON.parse(stateJson);
| |
| console.log('加载保存的状态:', state);
| |
|
| |
| const tbody = document.querySelector('#tierlist-table tbody');
| |
| const rows = Array.from(tbody.querySelectorAll('tr'));
| |
|
| |
| if (state.rows && state.rows.length > 0) {
| |
| rows.forEach((row, index) => {
| |
| if (index >= state.rows.length) {
| |
| row.remove();
| |
| } else {
| |
| const header = row.querySelector('.tier-header');
| |
| const savedRow = state.rows[index];
| |
|
| |
| if (header && savedRow) {
| |
| header.textContent = savedRow.name;
| |
| header.setAttribute('data-tier', savedRow.name);
| |
| header.style.backgroundColor = savedRow.bgColor;
| |
|
| |
| const tierRow = row.querySelector('.tier-row');
| |
| if (tierRow) {
| |
| tierRow.setAttribute('data-tier', savedRow.name);
| |
| tierRow.innerHTML = '';
| |
| }
| |
| }
| |
| }
| |
| });
| |
|
| |
| for (let i = rows.length; i < state.rows.length; i++) {
| |
| const savedRow = state.rows[i];
| |
| const newRow = document.createElement('tr');
| |
| newRow.innerHTML = `
| |
| <th style="width: 100px; background-color: ${savedRow.bgColor}; color: white; font-size: 20px; text-align: center" class="tier-header" data-tier="${savedRow.name}">${savedRow.name}</th>
| |
| <td class="tier-row" data-tier="${savedRow.name}"></td>
| |
| `;
| |
| tbody.appendChild(newRow);
| |
| }
| |
| }
| |
|
| |
| // 重新初始化所有drop区域
| |
| this.initDropZones();
| |
|
| |
| setTimeout(() => {
| |
| state.rows.forEach((rowData, index) => {
| |
| const tierRow = document.querySelectorAll('.tier-row')[index];
| |
| if (!tierRow) return;
| |
|
| |
| rowData.characters.forEach(charId => {
| |
| const avatar = this.findAvatarById(charId);
| |
| if (avatar && avatar.parentElement) {
| |
| tierRow.appendChild(avatar);
| |
| }
| |
| });
| |
| });
| |
|
| |
| // 重新初始化拖拽
| |
| this.initAvatarsDraggable();
| |
| this.cleanupContainers();
| |
| console.log('状态加载完成');
| |
| }, 200);
| |
|
| |
| } catch (e) {
| |
| console.warn('无法加载状态:', e);
| |
| }
| |
| },
| |
|
| |
| getCharacterId: function(avatar) {
| |
| const img = avatar.querySelector('img');
| |
| if (img) {
| |
| const src = img.getAttribute('src');
| |
| if (src) {
| |
| const match = src.match(/\/(\d+)\./);
| |
| if (match) return match[1];
| |
| }
| |
| }
| |
|
| |
| const name = avatar.querySelector('.avatar-name');
| |
| if (name) {
| |
| return name.textContent.trim();
| |
| }
| |
|
| |
| return avatar.outerHTML;
| |
| },
| |
|
| |
| findAvatarById: function(charId) {
| |
| const allAvatars = document.querySelectorAll('.avatar-frame');
| |
| for (let avatar of allAvatars) {
| |
| if (this.getCharacterId(avatar) === charId) {
| |
| return avatar;
| |
| }
| |
| }
| |
| return null;
| |
| },
| |
|
| |
| saveTierlist: function() {
| |
| const table = document.getElementById('tierlist-table');
| |
| if (!table) {
| |
| alert('未找到 Tierlist 表格!');
| |
| return;
| |
| }
| |
|
| |
| if (typeof html2canvas === 'undefined') {
| |
| alert('正在加载图片生成库,请稍后再试...');
| |
| return;
| |
| }
| |
|
| |
| const controls = document.querySelector('.tierlist-controls');
| |
| const poolContainer = document.querySelector('.character-pool-container');
| |
|
| |
| const originalControlsDisplay = controls ? controls.style.display : '';
| |
| const originalPoolDisplay = poolContainer ? poolContainer.style.display : '';
| |
|
| |
| const deleteButtons = document.querySelectorAll('.delete-row-btn');
| |
| deleteButtons.forEach(btn => btn.style.display = 'none');
| |
|
| |
| if (controls) controls.style.display = 'none';
| |
| if (poolContainer) poolContainer.style.display = 'none';
| |
|
| |
| html2canvas(table, {
| |
| scale: 2,
| |
| backgroundColor: '#ffffff',
| |
| logging: false,
| |
| useCORS: true,
| |
| allowTaint: true
| |
| }).then(canvas => {
| |
| if (controls) controls.style.display = originalControlsDisplay;
| |
| if (poolContainer) poolContainer.style.display = originalPoolDisplay;
| |
| deleteButtons.forEach(btn => btn.style.display = '');
| |
|
| |
| const link = document.createElement('a');
| |
| const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, -5);
| |
| link.download = 'tierlist_' + timestamp + '.png';
| |
| link.href = canvas.toDataURL('image/png');
| |
| link.click();
| |
| }).catch(err => {
| |
| console.error('生成图片失败:', err);
| |
| if (controls) controls.style.display = originalControlsDisplay;
| |
| if (poolContainer) poolContainer.style.display = originalPoolDisplay;
| |
| deleteButtons.forEach(btn => btn.style.display = '');
| |
| alert('生成图片失败,请查看控制台了解详情');
| |
| });
| |
| },
| |
|
| |
| resetTierlist: function() {
| |
| if (!confirm('确定要重置所有排列吗?此操作不可撤销。')) {
| |
| return;
| |
| }
| |
|
| |
| const pool = document.getElementById('character-pool');
| |
| if (!pool) {
| |
| alert('未找到角色池!');
| |
| return;
| |
| }
| |
|
| |
| const allAvatars = Array.from(document.querySelectorAll('.avatar-frame'));
| |
|
| |
| document.querySelectorAll('.tier-row').forEach(row => {
| |
| row.innerHTML = '';
| |
| });
| |
|
| |
| pool.innerHTML = '';
| |
|
| |
| allAvatars.forEach(avatar => {
| |
| pool.appendChild(avatar);
| |
| avatar.style.opacity = '1';
| |
| const img = avatar.querySelector('img');
| |
| if (img) {
| |
| img.style.opacity = '1';
| |
| }
| |
| });
| |
|
| |
| // 重新初始化拖拽功能
| |
| this.initAvatarsDraggable();
| |
| this.cleanupContainers();
| |
|
| |
| try {
| |
| localStorage.removeItem('tierlist-state');
| |
| console.log('状态已清除');
| |
| } catch (e) {
| |
| console.warn('无法清除状态:', e);
| |
| }
| |
|
| |
| alert('重置完成!');
| |
| }
| |
| };
| |
|
| |
| window.TierlistMakerInitialized = true;
| |
| window.TierlistMaker = TierlistMaker;
| |
|
| |
| TierlistMaker.init();
| |
|
| |
| // 添加手动加载状态的功能
| |
| window.loadTierlistState = function() {
| |
| if (window.TierlistMaker) {
| |
| window.TierlistMaker.loadState();
| |
| }
| |
| };
| |
| })(); | | })(); |
| </script> | | </script> |
| </includeonly> | | </includeonly> |