优化:百家乐骰子悬浮按钮支持拖拽移动,位置记忆 localStorage
This commit is contained in:
@@ -295,24 +295,131 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ─── 骰子悬浮入口(游戏开启时常驻) ─── --}}
|
||||
{{-- ─── 骰子悬浮入口(游戏开启时常驻,支持拖拽) ─── --}}
|
||||
<div id="baccarat-fab" x-data="{ visible: false }" x-show="visible" x-cloak
|
||||
style="position:fixed; bottom:90px; right:18px; z-index:9900;">
|
||||
<button
|
||||
x-on:click="() => {
|
||||
style="position:fixed; bottom:90px; right:18px; z-index:9900; touch-action:none;">
|
||||
<button id="baccarat-fab-btn" x-on:click.stop="() => {}"
|
||||
style="width:52px; height:52px; border-radius:50%; border:none; cursor:grab;
|
||||
background:linear-gradient(135deg,#7c3aed,#4f46e5);
|
||||
box-shadow:0 4px 20px rgba(124,58,237,.5);
|
||||
font-size:22px; display:flex; align-items:center; justify-content:center;
|
||||
animation:pulse-fab 2s infinite; user-select:none;"
|
||||
title="百家乐下注中(可拖动)">🎲</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 百家乐骰子悬浮按钮拖拽逻辑
|
||||
* 需在 DOM 就绪后初始化,因为 x-cloak 元素初始隐藏
|
||||
*/
|
||||
(function initBaccaratFabDrag() {
|
||||
const LS_KEY = 'baccaratFabPos';
|
||||
|
||||
function attachDrag() {
|
||||
const fab = document.getElementById('baccarat-fab');
|
||||
const btn = document.getElementById('baccarat-fab-btn');
|
||||
if (!fab || !btn || fab._dragInited) return;
|
||||
fab._dragInited = true;
|
||||
|
||||
// 恢复上次拖拽位置
|
||||
const saved = (() => {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem(LS_KEY));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
if (saved) {
|
||||
fab.style.left = saved.left + 'px';
|
||||
fab.style.top = saved.top + 'px';
|
||||
fab.style.right = 'auto';
|
||||
fab.style.bottom = 'auto';
|
||||
}
|
||||
|
||||
let isDragging = false;
|
||||
let startX, startY, startLeft, startTop;
|
||||
|
||||
function onStart(e) {
|
||||
const rect = fab.getBoundingClientRect();
|
||||
// 转为绝对 left/top
|
||||
fab.style.left = rect.left + 'px';
|
||||
fab.style.top = rect.top + 'px';
|
||||
fab.style.right = 'auto';
|
||||
fab.style.bottom = 'auto';
|
||||
|
||||
isDragging = false;
|
||||
const cx = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
const cy = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
startX = cx;
|
||||
startY = cy;
|
||||
startLeft = rect.left;
|
||||
startTop = rect.top;
|
||||
btn.style.cursor = 'grabbing';
|
||||
|
||||
document.addEventListener('mousemove', onMove, {
|
||||
passive: false
|
||||
});
|
||||
document.addEventListener('mouseup', onEnd);
|
||||
document.addEventListener('touchmove', onMove, {
|
||||
passive: false
|
||||
});
|
||||
document.addEventListener('touchend', onEnd);
|
||||
}
|
||||
|
||||
function onMove(e) {
|
||||
e.preventDefault();
|
||||
const cx = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
const cy = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
const dx = cx - startX,
|
||||
dy = cy - startY;
|
||||
if (Math.abs(dx) > 3 || Math.abs(dy) > 3) isDragging = true;
|
||||
if (!isDragging) return;
|
||||
|
||||
const newLeft = Math.max(0, Math.min(window.innerWidth - fab.offsetWidth, startLeft + dx));
|
||||
const newTop = Math.max(0, Math.min(window.innerHeight - fab.offsetHeight, startTop + dy));
|
||||
fab.style.left = newLeft + 'px';
|
||||
fab.style.top = newTop + 'px';
|
||||
}
|
||||
|
||||
function onEnd() {
|
||||
btn.style.cursor = 'grab';
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onEnd);
|
||||
document.removeEventListener('touchmove', onMove);
|
||||
document.removeEventListener('touchend', onEnd);
|
||||
|
||||
if (isDragging) {
|
||||
localStorage.setItem(LS_KEY, JSON.stringify({
|
||||
left: parseInt(fab.style.left),
|
||||
top: parseInt(fab.style.top),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
btn.addEventListener('mousedown', onStart);
|
||||
btn.addEventListener('touchstart', onStart, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
// 非拖拽时才打开面板
|
||||
btn.addEventListener('click', () => {
|
||||
if (isDragging) return;
|
||||
const p = Alpine.$data(document.getElementById('baccarat-panel'));
|
||||
if (!p) return;
|
||||
p.show = true;
|
||||
if (p.phase === 'betting' && p.countdown > 0 && !p.countdownTimer) {
|
||||
p.startCountdown();
|
||||
}
|
||||
}"
|
||||
style="width:52px; height:52px; border-radius:50%; border:none; cursor:pointer;
|
||||
background:linear-gradient(135deg,#7c3aed,#4f46e5);
|
||||
box-shadow:0 4px 20px rgba(124,58,237,.5);
|
||||
font-size:22px; display:flex; align-items:center; justify-content:center;
|
||||
animation:pulse-fab 2s infinite;"
|
||||
title="百家乐下注中">🎲</button>
|
||||
</div>
|
||||
});
|
||||
}
|
||||
|
||||
// 首次尝试(元素可能已在 DOM 中)
|
||||
document.addEventListener('DOMContentLoaded', attachDrag);
|
||||
|
||||
// Alpine 使 x-cloak 元素出现后再次尝试
|
||||
document.addEventListener('alpine:initialized', () => setTimeout(attachDrag, 100));
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes spin {
|
||||
|
||||
Reference in New Issue
Block a user