迁移前台基础页面脚本
This commit is contained in:
@@ -0,0 +1,133 @@
|
|||||||
|
// 前台普通页面交互入口,集中管理确认弹窗、聊天室弹窗和说明页导航高亮。
|
||||||
|
|
||||||
|
let frontControlsBound = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取元素上声明的确认文案,并在用户取消时拦截默认行为。
|
||||||
|
*
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {Element} element
|
||||||
|
* @param {string} attribute
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function confirmBeforeAction(event, element, attribute) {
|
||||||
|
const message = element.getAttribute(attribute);
|
||||||
|
if (!message || window.confirm(message)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开独立聊天室窗口,并尽量铺满当前可用屏幕。
|
||||||
|
*
|
||||||
|
* @param {string} url
|
||||||
|
* @param {string} roomName
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function openChatRoomWindow(url, roomName) {
|
||||||
|
const chatWindow = window.open(
|
||||||
|
url,
|
||||||
|
`chatroom_${roomName}`,
|
||||||
|
"toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!chatWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chatWindow.moveTo(0, 0);
|
||||||
|
chatWindow.resizeTo(window.screen.availWidth, window.screen.availHeight);
|
||||||
|
chatWindow.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定说明页右侧导航的可视区高亮。
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function bindGuideNavigation() {
|
||||||
|
const aside = document.getElementById("guide-aside");
|
||||||
|
const nav = document.getElementById("guide-nav");
|
||||||
|
if (!aside || !nav) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkWidth = () => {
|
||||||
|
aside.style.display = window.innerWidth >= 1024 ? "block" : "none";
|
||||||
|
};
|
||||||
|
checkWidth();
|
||||||
|
window.addEventListener("resize", checkWidth);
|
||||||
|
|
||||||
|
const links = Array.from(nav.querySelectorAll("a"));
|
||||||
|
const sections = links
|
||||||
|
.map((link) => {
|
||||||
|
const id = link.getAttribute("href")?.slice(1);
|
||||||
|
const element = id ? document.getElementById(id) : null;
|
||||||
|
|
||||||
|
return element ? { element, link } : null;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const onScroll = () => {
|
||||||
|
let current = sections[0];
|
||||||
|
sections.forEach((section) => {
|
||||||
|
if (section.element.getBoundingClientRect().top <= 120) {
|
||||||
|
current = section;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
links.forEach((link) => link.classList.remove("active"));
|
||||||
|
current?.link.classList.add("active");
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("scroll", onScroll, { passive: true });
|
||||||
|
onScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定前台普通页面的轻量事件代理。
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function bindFrontControls() {
|
||||||
|
if (frontControlsBound || typeof document === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frontControlsBound = true;
|
||||||
|
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
if (!(event.target instanceof Element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitButton = event.target.closest("[data-front-submit-confirm]");
|
||||||
|
if (submitButton && !confirmBeforeAction(event, submitButton, "data-front-submit-confirm")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roomLink = event.target.closest("[data-chat-room-window-url]");
|
||||||
|
if (roomLink) {
|
||||||
|
event.preventDefault();
|
||||||
|
openChatRoomWindow(
|
||||||
|
roomLink.getAttribute("data-chat-room-window-url") ?? "",
|
||||||
|
roomLink.getAttribute("data-chat-room-window-name") ?? "room",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("submit", (event) => {
|
||||||
|
if (!(event.target instanceof HTMLFormElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmBeforeAction(event, event.target, "data-front-confirm");
|
||||||
|
});
|
||||||
|
|
||||||
|
bindGuideNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
|
bindFrontControls();
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
<span>{{ \Carbon\Carbon::parse($msg->post_time)->diffForHumans() }}</span>
|
<span>{{ \Carbon\Carbon::parse($msg->post_time)->diffForHumans() }}</span>
|
||||||
@if ($isFromMe || $isToMe || (Auth::check() && Auth::user()->user_level >= 15))
|
@if ($isFromMe || $isToMe || (Auth::check() && Auth::user()->user_level >= 15))
|
||||||
<form action="{{ route('guestbook.destroy', $msg->id) }}" method="POST"
|
<form action="{{ route('guestbook.destroy', $msg->id) }}" method="POST"
|
||||||
onsubmit="return confirm('确定要抓除这条留言吗?');" class="inline">
|
data-front-confirm="确定要抓除这条留言吗?" class="inline">
|
||||||
@csrf
|
@csrf
|
||||||
@method('DELETE')
|
@method('DELETE')
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
<title>@yield('title', '飘落流星聊天室')</title>
|
<title>@yield('title', '飘落流星聊天室')</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
@vite('resources/js/front.js')
|
||||||
{{-- Alpine.js Intersect 插件(懒加载 x-intersect 需要,必须在主包之前加载) --}}
|
{{-- Alpine.js Intersect 插件(懒加载 x-intersect 需要,必须在主包之前加载) --}}
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/intersect@3.x.x/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/intersect@3.x.x/dist/cdn.min.js"></script>
|
||||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
|||||||
@@ -410,12 +410,12 @@
|
|||||||
@csrf
|
@csrf
|
||||||
<input type="hidden" name="vip_level_id" value="{{ $vip->id }}">
|
<input type="hidden" name="vip_level_id" value="{{ $vip->id }}">
|
||||||
<button type="submit" name="provider" value="alipay"
|
<button type="submit" name="provider" value="alipay"
|
||||||
onclick="return confirm('确认使用支付宝支付 {{ $vip->price }} 元购买【{{ $vip->name }}】吗?');"
|
data-front-submit-confirm="确认使用支付宝支付 {{ $vip->price }} 元购买【{{ $vip->name }}】吗?"
|
||||||
class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-bold hover:bg-indigo-700 transition">
|
class="px-3 py-1.5 rounded-lg bg-indigo-600 text-white text-xs font-bold hover:bg-indigo-700 transition">
|
||||||
支付宝
|
支付宝
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" name="provider" value="wechat"
|
<button type="submit" name="provider" value="wechat"
|
||||||
onclick="return confirm('确认使用微信支付 {{ $vip->price }} 元购买【{{ $vip->name }}】吗?');"
|
data-front-submit-confirm="确认使用微信支付 {{ $vip->price }} 元购买【{{ $vip->name }}】吗?"
|
||||||
class="px-3 py-1.5 rounded-lg bg-emerald-600 text-white text-xs font-bold hover:bg-emerald-700 transition">
|
class="px-3 py-1.5 rounded-lg bg-emerald-600 text-white text-xs font-bold hover:bg-emerald-700 transition">
|
||||||
微信
|
微信
|
||||||
</button>
|
</button>
|
||||||
@@ -551,48 +551,3 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('scripts')
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/**
|
|
||||||
* 滚动时高亮右侧导航当前所在板块
|
|
||||||
*/
|
|
||||||
(function() {
|
|
||||||
// 屏幕宽度 >= 1024px 时显示右侧导航
|
|
||||||
const aside = document.getElementById('guide-aside');
|
|
||||||
const nav = document.getElementById('guide-nav');
|
|
||||||
if (!aside || !nav) return;
|
|
||||||
|
|
||||||
function checkWidth() {
|
|
||||||
aside.style.display = window.innerWidth >= 1024 ? 'block' : 'none';
|
|
||||||
}
|
|
||||||
window.addEventListener('resize', checkWidth);
|
|
||||||
checkWidth();
|
|
||||||
|
|
||||||
const links = nav.querySelectorAll('a');
|
|
||||||
const sections = [];
|
|
||||||
links.forEach(a => {
|
|
||||||
const id = a.getAttribute('href').slice(1);
|
|
||||||
const el = document.getElementById(id);
|
|
||||||
if (el) sections.push({
|
|
||||||
el,
|
|
||||||
link: a
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function onScroll() {
|
|
||||||
let current = sections[0];
|
|
||||||
for (const s of sections) {
|
|
||||||
if (s.el.getBoundingClientRect().top <= 120) current = s;
|
|
||||||
}
|
|
||||||
links.forEach(a => a.classList.remove('active'));
|
|
||||||
if (current) current.link.classList.add('active');
|
|
||||||
}
|
|
||||||
window.addEventListener('scroll', onScroll, {
|
|
||||||
passive: true
|
|
||||||
});
|
|
||||||
onScroll();
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
@endsection
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@
|
|||||||
转让
|
转让
|
||||||
</button>
|
</button>
|
||||||
<form action="{{ route('rooms.destroy', $room->id) }}" method="POST" class="inline"
|
<form action="{{ route('rooms.destroy', $room->id) }}" method="POST" class="inline"
|
||||||
onsubmit="return confirm('警告:确实要彻底解散「{{ $room->name }}」吗?此操作不可逆!');">
|
data-front-confirm="警告:确实要彻底解散「{{ $room->name }}」吗?此操作不可逆!">
|
||||||
@csrf @method('delete')
|
@csrf @method('delete')
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="text-xs text-red-600 hover:text-red-800 font-semibold px-2 py-1 rounded hover:bg-red-50 transition">解散</button>
|
class="text-xs text-red-600 hover:text-red-800 font-semibold px-2 py-1 rounded hover:bg-red-50 transition">解散</button>
|
||||||
@@ -117,7 +117,8 @@
|
|||||||
|
|
||||||
{{-- 进入按钮 --}}
|
{{-- 进入按钮 --}}
|
||||||
<a href="#"
|
<a href="#"
|
||||||
onclick="openChatRoom('{{ route('chat.room', $room->id) }}', '{{ $room->name }}'); return false;"
|
data-chat-room-window-url="{{ route('chat.room', $room->id) }}"
|
||||||
|
data-chat-room-window-name="{{ $room->name }}"
|
||||||
class="bg-indigo-600 text-white hover:bg-indigo-700 px-4 py-2 rounded-t-xl rounded-br-xl text-sm font-bold shadow-md hover:shadow-lg transition-all transform group-hover:-translate-y-0.5">
|
class="bg-indigo-600 text-white hover:bg-indigo-700 px-4 py-2 rounded-t-xl rounded-br-xl text-sm font-bold shadow-md hover:shadow-lg transition-all transform group-hover:-translate-y-0.5">
|
||||||
立刻进入 →
|
立刻进入 →
|
||||||
</a>
|
</a>
|
||||||
@@ -417,24 +418,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('scripts')
|
|
||||||
{{-- 原版风格:弹出独立聊天窗口 --}}
|
|
||||||
<script>
|
|
||||||
/**
|
|
||||||
* 打开聊天室弹出窗口(复刻原版 DEFAULT.asp 的 launchchat 函数)
|
|
||||||
*/
|
|
||||||
function openChatRoom(url, roomName) {
|
|
||||||
var chatWin = window.open(
|
|
||||||
url,
|
|
||||||
'chatroom_' + roomName,
|
|
||||||
'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes'
|
|
||||||
);
|
|
||||||
if (chatWin) {
|
|
||||||
chatWin.moveTo(0, 0);
|
|
||||||
chatWin.resizeTo(screen.availWidth, screen.availHeight);
|
|
||||||
chatWin.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@endsection
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export default defineConfig({
|
|||||||
"resources/js/app.js",
|
"resources/js/app.js",
|
||||||
"resources/js/chat.js",
|
"resources/js/chat.js",
|
||||||
"resources/js/effects.js",
|
"resources/js/effects.js",
|
||||||
|
"resources/js/front.js",
|
||||||
],
|
],
|
||||||
refresh: true,
|
refresh: true,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user