MediaWiki:CardSys.js
来自卡厄思梦境WIKI
注意:在发布之后,您可能需要清除浏览器缓存才能看到所作出的更改的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Edge:按住Ctrl的同时单击刷新,或按Ctrl-F5。
(function() {
// 防止重复初始化
if (window.cardSystemInitialized) return;
window.cardSystemInitialized = true;
// 缓存DOM元素
var overlayCache = null;
var containerCache = null;
// 保存当前卡牌信息,用于返回
var currentCardInfo = null;
// 添加历史栈来记录浏览历史
var viewHistory = [];
// API缓存
var apiCache = {};
// 预加载队列
var preloadQueue = new Set();
var preloadWorker = null;
// 添加请求队列控制并发
var requestQueue = [];
var activeRequests = 0;
var MAX_CONCURRENT_REQUESTS = 3; // 限制最大并发请求数
// 添加请求超时控制
var REQUEST_TIMEOUT = 10000; // 10秒超时
// 智能缓存管理器
var cacheManager = {
maxSize: 100,
accessTime: {},
set: function(key, value) {
apiCache[key] = value;
this.accessTime[key] = Date.now();
var keys = Object.keys(apiCache);
if (keys.length > this.maxSize) {
var oldestKey = keys[0];
var oldestTime = this.accessTime[oldestKey] || 0;
for (var i = 1; i < keys.length; i++) {
var time = this.accessTime[keys[i]] || 0;
if (time < oldestTime) {
oldestKey = keys[i];
oldestTime = time;
}
}
delete apiCache[oldestKey];
delete this.accessTime[oldestKey];
}
},
get: function(key) {
if (apiCache[key]) {
this.accessTime[key] = Date.now();
return apiCache[key];
}
return null;
}
};
// 添加Loading动画CSS
function addLoadingStyles() {
if (!document.getElementById('card-loading-styles')) {
var style = document.createElement('style');
style.id = 'card-loading-styles';
style.textContent = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.card-fade-in {
animation: fadeIn 0.3s ease-in;
}
`;
document.head.appendChild(style);
}
}
// 创建loading占位符
function createLoadingPlaceholder(text, scale) {
var placeholder = document.createElement('div');
placeholder.className = 'card-loading';
var baseStyle = 'width: 168px; height: 230px; background: rgba(255,255,255,0.1); border: 2px dashed rgba(255,255,255,0.3); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white;';
if (scale) {
baseStyle += ' transform: scale(' + scale + '); transform-origin: center center;';
}
placeholder.style.cssText = baseStyle;
placeholder.innerHTML = '<div style="text-align: center;">' +
'<div class="loading-spinner" style="border: 3px solid rgba(255,255,255,0.3); border-top: 3px solid white; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 0 auto 10px;"></div>' +
'<div style="font-size: 12px;">' + (text || '加载中...') + '</div>' +
'</div>';
return placeholder;
}
// 错误占位符
function createErrorPlaceholder(text, scale) {
var placeholder = document.createElement('div');
placeholder.className = 'card-error';
var baseStyle = 'width: 168px; height: 230px; background: rgba(255,0,0,0.1); border: 2px dashed rgba(255,0,0,0.3); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #ff6b6b;';
if (scale) {
baseStyle += ' transform: scale(' + scale + '); transform-origin: center center;';
}
placeholder.style.cssText = baseStyle;
placeholder.innerHTML = '<div style="text-align: center; padding: 10px;">' +
'<div style="font-size: 30px; margin-bottom: 10px;">⚠</div>' +
'<div style="font-size: 12px;">' + (text || '加载失败') + '</div>' +
'</div>';
return placeholder;
}
// 请求队列处理器
function processRequestQueue() {
if (requestQueue.length === 0 || activeRequests >= MAX_CONCURRENT_REQUESTS) {
return;
}
var request = requestQueue.shift();
activeRequests++;
request.execute(function() {
activeRequests--;
processRequestQueue(); // 处理下一个请求
});
}
// 添加到请求队列
function queueRequest(executeFn) {
return new Promise(function(resolve, reject) {
requestQueue.push({
execute: function(done) {
executeFn()
.then(function(result) {
resolve(result);
done();
})
.catch(function(error) {
reject(error);
done();
});
}
});
processRequestQueue();
});
}
// 优化的API请求函数,添加超时和错误处理
function fetchCardHTML(character, cardName, deckType, callback) {
var cacheKey = character + '|' + cardName + '|' + (deckType || '');
// 检查缓存
var cached = cacheManager.get(cacheKey);
if (cached) {
callback(cached, null);
return;
}
// 使用请求队列
queueRequest(function() {
return new Promise(function(resolve, reject) {
var api = new mw.Api();
var wikitext = '{{#invoke:卡牌|main|' + character + '|' + cardName + '|' + (deckType || '') + '}}';
var timeoutId = setTimeout(function() {
reject(new Error('请求超时'));
}, REQUEST_TIMEOUT);
api.parse(wikitext)
.done(function(html) {
clearTimeout(timeoutId);
cacheManager.set(cacheKey, html);
resolve(html);
})
.fail(function(error) {
clearTimeout(timeoutId);
console.error('加载卡牌失败:', character, cardName, deckType, error);
reject(error);
});
});
})
.then(function(html) {
callback(html, null);
})
.catch(function(error) {
callback(null, error);
});
}
// 批量获取卡牌HTML
function fetchCardHTMLBatch(requests, callback) {
var results = {};
var errors = {};
var pending = [];
// 先检查缓存
requests.forEach(function(req) {
var cacheKey = req.character + '|' + req.cardName + '|' + (req.deckType || '');
var cached = cacheManager.get(cacheKey);
if (cached) {
results[cacheKey] = cached;
} else {
pending.push(req);
}
});
// 如果全部都有缓存,直接返回
if (pending.length === 0) {
callback(results, errors);
return;
}
// 限制批量请求数量,分批处理
var batchSize = 5;
var batches = [];
for (var i = 0; i < pending.length; i += batchSize) {
batches.push(pending.slice(i, i + batchSize));
}
var currentBatch = 0;
function processBatch() {
if (currentBatch >= batches.length) {
callback(results, errors);
return;
}
var batch = batches[currentBatch];
var completed = 0;
batch.forEach(function(req) {
fetchCardHTML(req.character, req.cardName, req.deckType, function(html, error) {
var cacheKey = req.character + '|' + req.cardName + '|' + (req.deckType || '');
if (error) {
errors[cacheKey] = error;
} else {
results[cacheKey] = html;
}
completed++;
if (completed === batch.length) {
currentBatch++;
// 延迟处理下一批,避免请求过快
setTimeout(processBatch, 200);
}
});
});
}
processBatch();
}
// 预加载管理器
function preloadCardData(character, cardName, deckType) {
var cacheKey = character + '|' + cardName + '|' + (deckType || '');
if (!cacheManager.get(cacheKey) && !preloadQueue.has(cacheKey)) {
preloadQueue.add(cacheKey);
if (!preloadWorker) {
preloadWorker = setTimeout(processPreloadQueue, 500);
}
}
}
// 批量处理预加载队列
function processPreloadQueue() {
preloadWorker = null;
if (preloadQueue.size === 0) return;
var batch = Array.from(preloadQueue).slice(0, 2);
batch.forEach(function(key) {
preloadQueue.delete(key);
});
batch.forEach(function(cacheKey) {
var parts = cacheKey.split('|');
fetchCardHTML(parts[0], parts[1], parts[2], function() {
// 预加载完成,数据已缓存
});
});
// 如果还有剩余,继续处理
if (preloadQueue.size > 0) {
preloadWorker = setTimeout(processPreloadQueue, 1000);
}
}
// 创建遮罩层和容器
function createCardOverlay() {
if (overlayCache && containerCache) {
return { overlay: overlayCache, container: containerCache };
}
var overlay = document.createElement('div');
overlay.id = 'card-overlay';
overlay.style.cssText = 'display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 9999; overflow-y: auto;';
var container = document.createElement('div');
container.id = 'card-display-container';
container.style.cssText = 'position: relative; min-height: 100vh; padding: 40px 20px; display: flex; align-items: center; justify-content: center;';
overlay.appendChild(container);
document.body.appendChild(overlay);
overlay.addEventListener('click', function(e) {
if (e.target === overlay) {
closeCardDisplay();
}
});
overlayCache = overlay;
containerCache = container;
return { overlay: overlay, container: container };
}
// 创建关闭按钮
function createCloseButton() {
var closeBtn = document.createElement('div');
closeBtn.style.cssText = 'position: fixed; top: 20px; right: 20px; width: 40px; height: 40px; background: rgba(255,255,255,0.1); border: 2px solid white; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 10001; transition: all 0.3s;';
closeBtn.innerHTML = '<span style="color: white; font-size: 24px; font-weight: bold; line-height: 1;">×</span>';
closeBtn.onmouseover = function() {
this.style.background = 'rgba(255,255,255,0.2)';
this.style.transform = 'scale(1.1)';
};
closeBtn.onmouseout = function() {
this.style.background = 'rgba(255,255,255,0.1)';
this.style.transform = 'scale(1)';
};
closeBtn.onclick = function() {
closeCardDisplay();
};
return closeBtn;
}
// 关闭卡牌展示
function closeCardDisplay() {
var overlay = document.getElementById('card-overlay');
if (overlay) {
overlay.style.display = 'none';
var container = overlay.querySelector('#card-display-container');
if (container) {
container.innerHTML = '';
}
}
currentCardInfo = null;
viewHistory = [];
}
// 返回上一层
function goBack() {
if (viewHistory.length > 1) {
viewHistory.pop();
var previousView = viewHistory[viewHistory.length - 1];
if (previousView.type === 'enlarged') {
showEnlargedCard(previousView.data.element, -1);
} else if (previousView.type === 'derivedCards') {
showAllDerivedCards(previousView.data.character, previousView.data.derivedCardsList, -1);
} else if (previousView.type === 'variantCards') {
showVariantCards(previousView.data.character, previousView.data.cardName, previousView.data.variantType, -1);
}
} else if (viewHistory.length === 1) {
closeCardDisplay();
} else {
closeCardDisplay();
}
}
// 检查卡牌变体
function checkCardVariants(character, cardName, callback) {
var variants = { lingguang: false, shenguang: false };
var checkCount = 0;
var totalChecks = 2;
function checkComplete() {
checkCount++;
if (checkCount === totalChecks) {
callback(variants);
}
}
fetchCardHTML(character, cardName, '灵光一闪', function(html, error) {
if (!error && html && !html.includes('找不到卡组')) {
variants.lingguang = true;
}
checkComplete();
});
fetchCardHTML(character, cardName, '神之一闪', function(html, error) {
if (!error && html && !html.includes('找不到卡组')) {
variants.shenguang = true;
}
checkComplete();
});
}
// 放大显示卡牌
function showEnlargedCard(cardElement, addToHistory) {
var elements = createCardOverlay();
var container = elements.container;
var cardName = cardElement.dataset.cardName;
var character = cardElement.dataset.character;
var deckType = cardElement.dataset.deckType;
var derivedCards = cardElement.dataset.derivedCards;
var hasMechanism = cardElement.dataset.hasMechanism === 'true';
addLoadingStyles();
currentCardInfo = {
element: cardElement,
cardName: cardName,
character: character,
deckType: deckType,
derivedCards: derivedCards
};
if (addToHistory === -1) {
if (viewHistory.length > 0) {
viewHistory[viewHistory.length - 1] = {
type: 'enlarged',
data: currentCardInfo
};
}
} else if (addToHistory !== false) {
viewHistory.push({
type: 'enlarged',
data: currentCardInfo
});
}
container.style.cssText = 'position: relative; min-height: 100vh; padding: 40px 20px; display: flex; align-items: center; justify-content: center;';
var contentWrapper = document.createElement('div');
contentWrapper.style.cssText = 'display: flex; align-items: flex-start; gap: 0px; position: relative;';
var centerContainer = document.createElement('div');
centerContainer.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 0px;';
var mainCardContainer = document.createElement('div');
mainCardContainer.style.cssText = 'width: 336px; height: 460px; display: flex; align-items: center; justify-content: center; position: relative;';
var cardInner = document.createElement('div');
cardInner.style.cssText = 'transform: scale(2); position: relative;';
var enlargedCard = cardElement.cloneNode(true);
enlargedCard.style.width = '168px';
enlargedCard.style.height = '230px';
enlargedCard.style.cursor = 'default';
enlargedCard.style.position = 'relative';
enlargedCard.style.display = 'block';
enlargedCard.onclick = null;
enlargedCard.classList.add('card-fade-in');
cardInner.appendChild(enlargedCard);
mainCardContainer.appendChild(cardInner);
centerContainer.appendChild(mainCardContainer);
// 处理衍生卡牌
if (derivedCards && derivedCards.trim() !== '') {
var leftContainer = document.createElement('div');
leftContainer.style.cssText = 'display: flex; flex-direction: column; gap: 0px; align-items: center;';
var derivedCardsList = derivedCards.split('、');
var derivedCardWrapper = document.createElement('div');
derivedCardWrapper.style.cssText = 'width: 252px; height: 345px; display: flex; align-items: center; justify-content: center;';
var placeholder = createLoadingPlaceholder('加载衍生卡牌...', 1.5);
derivedCardWrapper.appendChild(placeholder);
leftContainer.appendChild(derivedCardWrapper);
fetchCardHTML(character, derivedCardsList[0].trim(), '', function(html, error) {
if (error || !html) {
var errorPlaceholder = createErrorPlaceholder('加载失败', 1.5);
derivedCardWrapper.removeChild(placeholder);
derivedCardWrapper.appendChild(errorPlaceholder);
return;
}
var firstDerivedCard = document.createElement('div');
firstDerivedCard.id = 'derived-cards-display';
firstDerivedCard.style.cssText = 'transform: scale(1.5); transform-origin: center center; opacity: 0;';
firstDerivedCard.innerHTML = html;
var cards = firstDerivedCard.querySelectorAll('.game-card');
cards.forEach(function(card) {
card.style.cursor = 'default';
card.onclick = function(e) {
e.stopPropagation();
e.preventDefault();
};
});
derivedCardWrapper.removeChild(placeholder);
derivedCardWrapper.appendChild(firstDerivedCard);
setTimeout(function() {
firstDerivedCard.style.transition = 'opacity 0.3s';
firstDerivedCard.style.opacity = '1';
}, 10);
});
if (derivedCardsList.length > 1) {
var viewAllBtn = document.createElement('div');
viewAllBtn.style.cssText = 'padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; margin-top: 0px;';
viewAllBtn.textContent = '查看所有衍生卡牌';
viewAllBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
viewAllBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
viewAllBtn.onclick = function() {
showAllDerivedCards(character, derivedCardsList, true);
};
leftContainer.appendChild(viewAllBtn);
}
contentWrapper.appendChild(leftContainer);
}
var buttonsContainer = document.createElement('div');
buttonsContainer.style.cssText = 'display: flex; gap: 15px; white-space: nowrap; min-height: 50px; align-items: center; justify-content: center;';
var checkingVariants = document.createElement('div');
checkingVariants.style.cssText = 'color: rgba(255,255,255,0.5); font-size: 12px;';
checkingVariants.textContent = '检查变体卡牌...';
buttonsContainer.appendChild(checkingVariants);
centerContainer.appendChild(buttonsContainer);
checkCardVariants(character, cardName, function(variants) {
if (buttonsContainer.contains(checkingVariants)) {
buttonsContainer.removeChild(checkingVariants);
}
if (variants.lingguang) {
var lingguangBtn = document.createElement('div');
lingguangBtn.style.cssText = 'padding: 10px 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; white-space: nowrap; min-width: 120px; text-align: center; opacity: 0;';
lingguangBtn.textContent = '灵光一闪';
lingguangBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
lingguangBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
lingguangBtn.onclick = function() {
showVariantCards(character, cardName, '灵光一闪', true);
};
buttonsContainer.appendChild(lingguangBtn);
setTimeout(function() {
lingguangBtn.style.transition = 'opacity 0.3s';
lingguangBtn.style.opacity = '1';
}, 10);
}
if (variants.shenguang) {
var shenguangBtn = document.createElement('div');
shenguangBtn.style.cssText = 'padding: 10px 30px; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; white-space: nowrap; min-width: 120px; text-align: center; opacity: 0;';
shenguangBtn.textContent = '神之一闪';
shenguangBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
shenguangBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
shenguangBtn.onclick = function() {
showVariantCards(character, cardName, '神之一闪', true);
};
buttonsContainer.appendChild(shenguangBtn);
setTimeout(function() {
shenguangBtn.style.transition = 'opacity 0.3s';
shenguangBtn.style.opacity = '1';
}, 10);
}
if (!variants.lingguang && !variants.shenguang) {
centerContainer.removeChild(buttonsContainer);
}
});
contentWrapper.appendChild(centerContainer);
if (hasMechanism) {
var mechanismContainer = cardElement.nextElementSibling;
if (mechanismContainer && mechanismContainer.classList.contains('mechanism-container')) {
var mechanismDisplay = document.createElement('div');
mechanismDisplay.style.cssText = 'display: flex; flex-direction: column; gap: 0px; max-width: 320px; min-width: 280px;';
mechanismDisplay.innerHTML = mechanismContainer.innerHTML;
mechanismDisplay.style.display = 'flex';
contentWrapper.appendChild(mechanismDisplay);
}
}
container.innerHTML = '';
container.appendChild(contentWrapper);
if (viewHistory.length > 1) {
var backBtn = document.createElement('div');
backBtn.style.cssText = 'position: fixed; top: 20px; left: 20px; padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); z-index: 10001; transition: transform 0.2s;';
backBtn.textContent = '← 返回';
backBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
backBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
backBtn.onclick = function() {
goBack();
};
container.appendChild(backBtn);
}
container.appendChild(createCloseButton());
elements.overlay.style.display = 'block';
}
// 显示所有衍生卡牌
function showAllDerivedCards(character, derivedCardsList, addToHistory) {
var overlay = document.getElementById('card-overlay');
var container = document.getElementById('card-display-container');
if (addToHistory === -1) {
if (viewHistory.length > 0) {
viewHistory[viewHistory.length - 1] = {
type: 'derivedCards',
data: {
character: character,
derivedCardsList: derivedCardsList
}
};
}
} else if (addToHistory === true) {
viewHistory.push({
type: 'derivedCards',
data: {
character: character,
derivedCardsList: derivedCardsList
}
});
} else if (addToHistory === 0) {
if (viewHistory.length > 0) {
viewHistory.pop();
}
viewHistory.push({
type: 'derivedCards',
data: {
character: character,
derivedCardsList: derivedCardsList
}
});
}
container.innerHTML = '';
container.style.cssText = 'position: relative; padding: 40px; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;';
var title = document.createElement('div');
title.style.cssText = 'color: white; font-size: 28px; font-weight: bold; margin-bottom: 30px; text-align: center;';
title.textContent = '衍生卡牌';
container.appendChild(title);
var cardsContainer = document.createElement('div');
cardsContainer.style.cssText = 'display: flex; flex-wrap: wrap; gap: 30px; justify-content: center; max-width: 1400px; transform: scale(1.5); transform-origin: center center; padding: 40px;';
var uniqueCards = [...new Set(derivedCardsList.map(function(name) { return name.trim(); }))];
var placeholders = [];
uniqueCards.forEach(function() {
var placeholder = createLoadingPlaceholder('加载中...', null);
placeholders.push(placeholder);
cardsContainer.appendChild(placeholder);
});
container.appendChild(cardsContainer);
var requests = uniqueCards.map(function(cardName) {
return { character: character, cardName: cardName, deckType: '' };
});
fetchCardHTMLBatch(requests, function(results, errors) {
uniqueCards.forEach(function(cardName, index) {
var cacheKey = character + '|' + cardName + '|';
if (errors[cacheKey]) {
var errorPlaceholder = createErrorPlaceholder('加载失败', null);
cardsContainer.replaceChild(errorPlaceholder, placeholders[index]);
return;
}
var html = results[cacheKey];
if (html) {
var cardWrapper = document.createElement('div');
cardWrapper.style.cssText = 'opacity: 0;';
cardWrapper.innerHTML = html;
var cards = cardWrapper.querySelectorAll('.game-card');
cards.forEach(function(card) {
card.style.cursor = 'default';
card.onclick = function(e) {
e.stopPropagation();
e.preventDefault();
};
var derivedCards = card.dataset.derivedCards;
if (derivedCards && derivedCards.trim() !== '') {
var buttonContainer = document.createElement('div');
buttonContainer.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 10px;';
var cardContainer = document.createElement('div');
cardContainer.appendChild(card.cloneNode(true));
buttonContainer.appendChild(cardContainer);
var viewDerivedBtn = document.createElement('div');
viewDerivedBtn.style.cssText = 'padding: 8px 15px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; font-size: 12px;';
viewDerivedBtn.textContent = '查看衍生卡牌';
viewDerivedBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
viewDerivedBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
viewDerivedBtn.onclick = function(e) {
e.stopPropagation();
showAllDerivedCards(character, derivedCards.split('、'), 0);
};
buttonContainer.appendChild(viewDerivedBtn);
cardsContainer.replaceChild(buttonContainer, placeholders[index]);
setTimeout(function() {
buttonContainer.style.transition = 'opacity 0.3s';
buttonContainer.style.opacity = '1';
}, 10);
} else {
cardsContainer.replaceChild(card, placeholders[index]);
setTimeout(function() {
card.style.transition = 'opacity 0.3s';
card.style.opacity = '1';
}, 10);
}
});
}
});
});
var backBtn = document.createElement('div');
backBtn.style.cssText = 'position: fixed; top: 20px; left: 20px; padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); z-index: 10001; transition: transform 0.2s;';
backBtn.textContent = '← 返回';
backBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
backBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
backBtn.onclick = function() {
goBack();
};
container.appendChild(backBtn);
container.appendChild(createCloseButton());
}
// 显示变体卡牌
function showVariantCards(character, cardName, variantType, addToHistory) {
var overlay = document.getElementById('card-overlay');
var container = document.getElementById('card-display-container');
if (addToHistory === -1) {
if (viewHistory.length > 0) {
viewHistory[viewHistory.length - 1] = {
type: 'variantCards',
data: {
character: character,
cardName: cardName,
variantType: variantType
}
};
}
} else if (addToHistory === true) {
viewHistory.push({
type: 'variantCards',
data: {
character: character,
cardName: cardName,
variantType: variantType
}
});
}
container.innerHTML = '';
container.style.cssText = 'position: relative; padding: 40px; min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;';
var title = document.createElement('div');
title.style.cssText = 'color: white; font-size: 28px; font-weight: bold; margin-bottom: 30px; text-align: center; background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;';
title.textContent = cardName + ' - ' + variantType;
container.appendChild(title);
var cardsContainer = document.createElement('div');
cardsContainer.style.cssText = 'display: flex; flex-wrap: nowrap; gap: 0px; justify-content: center; max-width: 1400px; overflow-x: auto; padding: 40px; transform: scale(1.5); transform-origin: center center;';
var loadingPlaceholder = createLoadingPlaceholder('加载变体卡牌...', null);
cardsContainer.appendChild(loadingPlaceholder);
container.appendChild(cardsContainer);
fetchCardHTML(character, cardName, variantType, function(html, error) {
if (error || !html) {
cardsContainer.removeChild(loadingPlaceholder);
var errorPlaceholder = createErrorPlaceholder('加载变体失败', null);
cardsContainer.appendChild(errorPlaceholder);
return;
}
var tempContainer = document.createElement('div');
tempContainer.innerHTML = html;
cardsContainer.removeChild(loadingPlaceholder);
var cards = tempContainer.querySelectorAll('.game-card');
cards.forEach(function(card, index) {
card.style.cursor = 'default';
card.onclick = null;
card.style.flexShrink = '0';
card.style.opacity = '0';
var derivedCards = card.getAttribute('data-derived-cards');
var hasDerivedCards = false;
if (derivedCards !== null && derivedCards !== undefined) {
var trimmedValue = String(derivedCards).trim();
if (trimmedValue.length > 0 &&
trimmedValue !== 'undefined' &&
trimmedValue !== 'null' &&
trimmedValue !== 'false' &&
trimmedValue !== '0') {
hasDerivedCards = true;
}
}
if (hasDerivedCards) {
var cardWrapper = document.createElement('div');
cardWrapper.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 10px; flex-shrink: 0; opacity: 0;';
var cardClone = card.cloneNode(true);
cardClone.style.cursor = 'default';
cardClone.onclick = null;
cardClone.style.opacity = '1';
cardWrapper.appendChild(cardClone);
var viewDerivedBtn = document.createElement('div');
viewDerivedBtn.style.cssText = 'padding: 8px 15px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; white-space: nowrap; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); transition: transform 0.2s; font-size: 12px;';
viewDerivedBtn.textContent = '查看衍生卡牌';
viewDerivedBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
viewDerivedBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
viewDerivedBtn.setAttribute('data-derived-list', derivedCards);
viewDerivedBtn.onclick = function(e) {
e.stopPropagation();
var derivedList = this.getAttribute('data-derived-list');
showAllDerivedCards(character, derivedList.split('、'), true);
};
cardWrapper.appendChild(viewDerivedBtn);
cardsContainer.appendChild(cardWrapper);
setTimeout(function() {
cardWrapper.style.transition = 'opacity 0.3s';
cardWrapper.style.opacity = '1';
}, 50 * index);
} else {
cardsContainer.appendChild(card);
setTimeout(function() {
card.style.transition = 'opacity 0.3s';
card.style.opacity = '1';
}, 50 * index);
}
});
});
var backBtn = document.createElement('div');
backBtn.style.cssText = 'position: fixed; top: 20px; left: 20px; padding: 10px 20px; background: linear-gradient(135deg, #4a90e2, #357abd); color: white; border-radius: 6px; cursor: pointer; font-weight: bold; box-shadow: 0 2px 8px rgba(0,0,0,0.3); z-index: 10001; transition: transform 0.2s;';
backBtn.textContent = '← 返回';
backBtn.onmouseover = function() { this.style.transform = 'scale(1.05)'; };
backBtn.onmouseout = function() { this.style.transform = 'scale(1)'; };
backBtn.onclick = function() {
goBack();
};
container.appendChild(backBtn);
container.appendChild(createCloseButton());
}
// 鼠标悬停时预加载
function initPreloadEvents() {
var preloadTimeout = null;
document.addEventListener('mouseover', function(e) {
var card = e.target.closest('.game-card');
if (card && !card.closest('#card-overlay')) {
clearTimeout(preloadTimeout);
preloadTimeout = setTimeout(function() {
var character = card.dataset.character;
var cardName = card.dataset.cardName;
var derivedCards = card.dataset.derivedCards;
if (!character || !cardName) return;
// 只在空闲时预加载
if (activeRequests < 2) {
preloadCardData(character, cardName, '灵光一闪');
preloadCardData(character, cardName, '神之一闪');
if (derivedCards && derivedCards.trim() !== '') {
var cardsList = derivedCards.split('、');
var preloadCount = Math.min(2, cardsList.length); // 减少预加载数量
for (var i = 0; i < preloadCount; i++) {
preloadCardData(character, cardsList[i].trim(), '');
}
}
}
}, 500); // 增加延迟
}
});
document.addEventListener('mouseout', function(e) {
var card = e.target.closest('.game-card');
if (card && !card.closest('#card-overlay')) {
clearTimeout(preloadTimeout);
}
});
}
// 初始化卡牌点击事件
function initCardClickEvents() {
document.addEventListener('click', function(e) {
var card = e.target.closest('.game-card');
if (card && !card.closest('#card-overlay')) {
e.preventDefault();
showEnlargedCard(card);
}
});
// 延迟初始化预加载,避免影响页面初始加载
setTimeout(function() {
initPreloadEvents();
}, 3000); // 页面加载3秒后才启用预加载
addLoadingStyles();
}
// 添加键盘快捷键支持
function initKeyboardShortcuts() {
document.addEventListener('keydown', function(e) {
var overlay = document.getElementById('card-overlay');
if (overlay && overlay.style.display !== 'none') {
if (e.key === 'Escape') {
e.preventDefault();
closeCardDisplay();
} else if (e.key === 'Backspace' || e.key === 'ArrowLeft') {
e.preventDefault();
goBack();
}
}
});
}
// 优化滚动性能
function optimizeScrollPerformance() {
var scrollTimeout;
var overlay = document.getElementById('card-overlay');
if (overlay) {
overlay.addEventListener('scroll', function() {
if (!overlay.classList.contains('is-scrolling')) {
overlay.classList.add('is-scrolling');
}
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function() {
overlay.classList.remove('is-scrolling');
}, 150);
}, { passive: true }); // 添加 passive 标志提升性能
}
}
// 清理函数 - 更激进的清理策略
function cleanup() {
if (Object.keys(apiCache).length > cacheManager.maxSize * 1.2) {
var keys = Object.keys(apiCache);
var toDelete = keys.length - cacheManager.maxSize;
keys.sort(function(a, b) {
return (cacheManager.accessTime[a] || 0) - (cacheManager.accessTime[b] || 0);
});
for (var i = 0; i < toDelete; i++) {
delete apiCache[keys[i]];
delete cacheManager.accessTime[keys[i]];
}
console.log('缓存清理完成,删除了 ' + toDelete + ' 条记录');
}
// 清理预加载队列
if (preloadQueue.size > 10) {
preloadQueue.clear();
console.log('预加载队列已清空');
}
}
// 定期清理(每3分钟)
setInterval(cleanup, 3 * 60 * 1000);
// 页面卸载时清理
window.addEventListener('beforeunload', function() {
apiCache = {};
cacheManager.accessTime = {};
preloadQueue.clear();
});
// 监控内存使用(仅在支持的浏览器中)
function monitorMemory() {
if (window.performance && window.performance.memory) {
var memory = window.performance.memory;
var usedPercent = (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100;
if (usedPercent > 80) {
console.warn('内存使用率过高: ' + usedPercent.toFixed(2) + '%');
cleanup(); // 强制清理
}
}
}
// 每分钟检查一次内存
setInterval(monitorMemory, 60 * 1000);
// 页面加载完成后初始化
function init() {
initCardClickEvents();
initKeyboardShortcuts();
// 延迟执行性能优化,避免阻塞主线程
setTimeout(function() {
optimizeScrollPerformance();
}, 1000);
console.log('卡牌系统初始化完成');
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();