优化:百家乐骰子悬浮按钮支持拖拽移动,位置记忆 localStorage

This commit is contained in:
2026-03-03 17:00:19 +08:00
parent 9f5d213d99
commit 0fd4f51b5e

View File

@@ -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 {