修复冲突问题

This commit is contained in:
CN-JS-HuiBai
2026-04-06 02:38:45 +08:00
parent 90e72af72c
commit 225ec71ac3

View File

@@ -207,19 +207,20 @@
dom.btnChangePassword.addEventListener('click', saveChangePassword); dom.btnChangePassword.addEventListener('click', saveChangePassword);
} }
// Globe expansion (FLIP animation) // Globe expansion (FLIP animation via Web Animations API)
let savedGlobeRect = null; let savedGlobeRect = null;
let globeAnimating = false;
function expandGlobe() { function expandGlobe() {
if (dom.globeCard.classList.contains('expanded')) return; if (dom.globeCard.classList.contains('expanded') || globeAnimating) return;
globeAnimating = true;
// Save original rect for FLIP // FLIP: capture original position
savedGlobeRect = dom.globeCard.getBoundingClientRect(); savedGlobeRect = dom.globeCard.getBoundingClientRect();
// Apply expanded state
dom.globeCard.classList.add('expanded'); dom.globeCard.classList.add('expanded');
dom.btnExpandGlobe.classList.add('active'); dom.btnExpandGlobe.classList.add('active');
// Update button icon/title
dom.btnExpandGlobe.title = '缩小显示'; dom.btnExpandGlobe.title = '缩小显示';
dom.btnExpandGlobe.innerHTML = ` dom.btnExpandGlobe.innerHTML = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width: 18px; height: 18px;"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width: 18px; height: 18px;">
@@ -227,59 +228,53 @@
</svg> </svg>
`; `;
// Resize ECharts immediately (prevents flash)
if (myMap2D) myMap2D.resize(); if (myMap2D) myMap2D.resize();
// FLIP: capture expanded position
const endRect = dom.globeCard.getBoundingClientRect(); const endRect = dom.globeCard.getBoundingClientRect();
const scaleX = savedGlobeRect.width / endRect.width; const scaleX = savedGlobeRect.width / endRect.width;
const scaleY = savedGlobeRect.height / endRect.height; const scaleY = savedGlobeRect.height / endRect.height;
// Using top-left for math (transformOrigin: 0 0)
const dx = savedGlobeRect.left - endRect.left; const dx = savedGlobeRect.left - endRect.left;
const dy = savedGlobeRect.top - endRect.top; const dy = savedGlobeRect.top - endRect.top;
dom.globeCard.style.willChange = 'transform, box-shadow'; // Animate using Web Animations API (bypasses all CSS conflicts)
dom.globeCard.style.transformOrigin = '0 0'; const anim = dom.globeCard.animate([
dom.globeCard.style.transition = 'none'; {
dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`; transform: `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`,
dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent'; boxShadow: '0 0 0 0 transparent, 0 0 0 0 transparent',
offset: 0
},
{
transform: 'translate(0, 0) scale(1)',
boxShadow: '0 0 80px rgba(0,0,0,0.8), 0 0 0 100vh rgba(0,0,0,0.65)',
offset: 1
}
], {
duration: 400,
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
fill: 'none'
});
dom.globeCard.offsetHeight; // Force reflow anim.onfinish = () => {
globeAnimating = false;
dom.globeCard.style.transition = 'transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease';
dom.globeCard.style.transform = 'translate(0px, 0px) scale(1)';
dom.globeCard.style.boxShadow = '';
const onTransitionEnd = (e) => {
if (e.propertyName !== 'transform') return;
dom.globeCard.removeEventListener('transitionend', onTransitionEnd);
dom.globeCard.style.transition = '';
dom.globeCard.style.willChange = '';
dom.globeCard.style.transformOrigin = '';
dom.globeCard.style.transform = '';
}; };
dom.globeCard.addEventListener('transitionend', onTransitionEnd);
} }
function collapseGlobe() { function collapseGlobe() {
if (!dom.globeCard.classList.contains('expanded')) return; if (!dom.globeCard.classList.contains('expanded') || globeAnimating) return;
if (dom.globeCard.classList.contains('globe-collapsing')) return; globeAnimating = true;
const resetState = () => { const resetState = () => {
dom.globeCard.classList.remove('expanded', 'globe-collapsing'); dom.globeCard.classList.remove('expanded', 'globe-collapsing');
dom.btnExpandGlobe.classList.remove('active'); dom.btnExpandGlobe.classList.remove('active');
dom.globeCard.style.transition = '';
dom.globeCard.style.transform = '';
dom.globeCard.style.boxShadow = '';
dom.globeCard.style.willChange = '';
// Restore button icon/title
dom.btnExpandGlobe.title = '放大显示'; dom.btnExpandGlobe.title = '放大显示';
dom.btnExpandGlobe.innerHTML = ` dom.btnExpandGlobe.innerHTML = `
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width: 18px; height: 18px;"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width: 18px; height: 18px;">
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" /> <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
</svg> </svg>
`; `;
globeAnimating = false;
if (myMap2D) requestAnimationFrame(() => myMap2D.resize()); if (myMap2D) requestAnimationFrame(() => myMap2D.resize());
}; };
@@ -290,43 +285,35 @@
dom.globeCard.classList.add('globe-collapsing'); dom.globeCard.classList.add('globe-collapsing');
// FLIP: compute target transform to original position
const expandedRect = dom.globeCard.getBoundingClientRect(); const expandedRect = dom.globeCard.getBoundingClientRect();
const scaleX = savedGlobeRect.width / expandedRect.width; const scaleX = savedGlobeRect.width / expandedRect.width;
const scaleY = savedGlobeRect.height / expandedRect.height; const scaleY = savedGlobeRect.height / expandedRect.height;
// Match origin used in expand
const dx = savedGlobeRect.left - expandedRect.left; const dx = savedGlobeRect.left - expandedRect.left;
const dy = savedGlobeRect.top - expandedRect.top; const dy = savedGlobeRect.top - expandedRect.top;
// Force setup the expanded state with origin // Animate from current expanded state to original rect
dom.globeCard.style.transformOrigin = '0 0'; const anim = dom.globeCard.animate([
dom.globeCard.style.transform = 'translate(0px, 0px) scale(1)'; {
dom.globeCard.style.boxShadow = ''; // Reset to what CSS says transform: 'translate(0, 0) scale(1)',
dom.globeCard.offsetHeight; // Critical sync reflow boxShadow: '0 0 80px rgba(0,0,0,0.8), 0 0 0 100vh rgba(0,0,0,0.65)',
offset: 0
},
{
transform: `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`,
boxShadow: '0 0 0 0 transparent, 0 0 0 0 transparent',
offset: 1
}
], {
duration: 350,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
fill: 'forwards' // Hold final frame until we remove class
});
dom.globeCard.style.willChange = 'transform, box-shadow'; anim.onfinish = () => {
dom.globeCard.style.transition = 'transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s ease'; anim.cancel(); // Release the fill-forwards hold
// Apply target values immediately after reflow
dom.globeCard.style.transform = `translate(${dx}px, ${dy}px) scale(${scaleX}, ${scaleY})`;
dom.globeCard.style.boxShadow = '0 0 0 0 transparent, 0 0 0 0 transparent';
let transitionFinished = false;
const onTransitionEnd = (e) => {
if (e.propertyName !== 'transform') return;
transitionFinished = true;
dom.globeCard.removeEventListener('transitionend', onTransitionEnd);
resetState(); resetState();
}; };
dom.globeCard.addEventListener('transitionend', onTransitionEnd);
// Robustness fallback
setTimeout(() => {
if (!transitionFinished) {
dom.globeCard.removeEventListener('transitionend', onTransitionEnd);
resetState();
}
}, 500);
} }
if (dom.btnExpandGlobe) { if (dom.btnExpandGlobe) {