Files
n8n_Demo/web_frontend/web_result/js/mobile-optimize.js
Yep_Q 3825deb3e0 优化项目配置和页面结构
- 更新settings.local.json,移除冗余的权限设置,添加新的Playwright相关权限。
- 删除exhibition_demo_project_2025.md文档,清理不再使用的文件。
- 更新多个HTML页面,统一viewport设置,添加页面加载动画、错误处理和性能优化脚本。
- 统一使用Tailwind CSS的引入方式,提升页面加载性能。
- 增强导航组件,支持移动端菜单和返回顶部功能,改善用户体验。
2025-09-10 02:35:16 +08:00

516 lines
17 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 移动端优化组件
(function() {
let isMobile = false;
let isTablet = false;
let currentOrientation = 'portrait';
// 检测设备类型
function detectDevice() {
const userAgent = navigator.userAgent.toLowerCase();
const screenWidth = window.innerWidth;
const screenHeight = window.innerHeight;
// 检测是否为移动设备
isMobile = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent) || screenWidth <= 768;
isTablet = /ipad|android(?!.*mobile)|tablet/i.test(userAgent) || (screenWidth > 768 && screenWidth <= 1024);
// 检测屏幕方向
currentOrientation = screenWidth > screenHeight ? 'landscape' : 'portrait';
// 添加设备类到body确保body存在
if (document.body) {
document.body.classList.remove('mobile', 'tablet', 'desktop', 'portrait', 'landscape');
document.body.classList.add(
isMobile ? 'mobile' : isTablet ? 'tablet' : 'desktop',
currentOrientation
);
}
return { isMobile, isTablet, currentOrientation };
}
// 添加移动端优化样式
function addMobileStyles() {
const style = document.createElement('style');
style.textContent = `
/* 移动端基础优化 */
* {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* 允许文本选择 */
p, h1, h2, h3, h4, h5, h6, span, div, article, section {
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
user-select: text;
}
/* 移动端滚动优化 */
html {
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
}
/* 移动端字体优化 */
body.mobile {
font-size: 16px; /* 防止iOS缩放 */
line-height: 1.6;
-webkit-text-size-adjust: 100%;
-moz-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
/* 移动端容器优化 */
.container {
padding-left: 1rem;
padding-right: 1rem;
}
body.mobile .container {
padding-left: 1rem;
padding-right: 1rem;
}
body.tablet .container {
padding-left: 2rem;
padding-right: 2rem;
}
/* 移动端导航优化 */
body.mobile #navbar {
padding: 0.75rem 1rem;
}
body.mobile .nav-container {
padding: 0.75rem 0;
}
/* 移动端按钮优化 */
body.mobile button,
body.mobile .btn {
min-height: 44px; /* iOS推荐的最小触摸目标 */
padding: 0.75rem 1.5rem;
font-size: 1rem;
}
/* 移动端表单优化 */
body.mobile input,
body.mobile textarea,
body.mobile select {
min-height: 44px;
padding: 0.75rem;
font-size: 16px; /* 防止iOS缩放 */
border-radius: 8px;
}
/* 移动端卡片优化 */
body.mobile .card,
body.mobile .glass-card {
margin-bottom: 1rem;
padding: 1rem;
border-radius: 12px;
}
/* 移动端文字优化 */
body.mobile h1 {
font-size: 2rem;
line-height: 1.2;
margin-bottom: 1rem;
}
body.mobile h2 {
font-size: 1.75rem;
line-height: 1.3;
margin-bottom: 0.75rem;
}
body.mobile h3 {
font-size: 1.5rem;
line-height: 1.4;
margin-bottom: 0.5rem;
}
body.mobile p {
font-size: 1rem;
line-height: 1.6;
margin-bottom: 1rem;
}
/* 移动端网格优化 */
body.mobile .grid {
grid-template-columns: 1fr;
gap: 1rem;
}
body.mobile .grid-cols-2,
body.mobile .grid-cols-3,
body.mobile .grid-cols-4,
body.mobile .md\\:grid-cols-2,
body.mobile .md\\:grid-cols-3,
body.mobile .lg\\:grid-cols-3 {
grid-template-columns: 1fr;
}
/* 平板端网格优化 */
body.tablet .grid-cols-3,
body.tablet .lg\\:grid-cols-3 {
grid-template-columns: repeat(2, 1fr);
}
/* 移动端间距优化 */
body.mobile .py-16 { padding-top: 3rem; padding-bottom: 3rem; }
body.mobile .py-12 { padding-top: 2rem; padding-bottom: 2rem; }
body.mobile .py-8 { padding-top: 1.5rem; padding-bottom: 1.5rem; }
body.mobile .mb-12 { margin-bottom: 2rem; }
body.mobile .mb-8 { margin-bottom: 1.5rem; }
/* 移动端图片优化 */
body.mobile img {
max-width: 100%;
height: auto;
border-radius: 8px;
}
/* 横屏优化 */
body.mobile.landscape {
/* 横屏时减少垂直间距 */
}
body.mobile.landscape .py-16 {
padding-top: 2rem;
padding-bottom: 2rem;
}
body.mobile.landscape h1 {
font-size: 1.75rem;
margin-bottom: 0.75rem;
}
/* 移动端返回顶部按钮优化 */
body.mobile #back-to-top {
bottom: 1.5rem;
right: 1.5rem;
}
body.mobile .back-to-top-btn {
width: 3rem;
height: 3rem;
}
/* 移动端页面加载器优化 */
body.mobile #page-loader .w-20 {
width: 4rem;
height: 4rem;
}
body.mobile #page-loader h1 {
font-size: 1.25rem;
}
body.mobile #page-loader .w-64 {
width: 16rem;
}
/* 防止页面缩放 */
@media screen and (max-width: 768px) {
html {
zoom: 1;
-ms-zoom: 1;
-webkit-zoom: 1;
-moz-zoom: 1;
}
}
/* 触摸设备特定优化 */
@media (hover: none) and (pointer: coarse) {
/* 移除hover效果使用active效果 */
.hover\\:scale-110:hover {
transform: none;
}
.hover\\:scale-110:active {
transform: scale(1.05);
}
.hover\\:shadow-xl:hover {
box-shadow: none;
}
.hover\\:shadow-xl:active {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
}
/* 安全区域适配iPhone X等带刘海屏的设备 */
@supports (padding: max(0px)) {
body.mobile {
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
body.mobile #navbar {
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
padding-top: max(0.75rem, env(safe-area-inset-top));
}
body.mobile #back-to-top {
right: max(1.5rem, env(safe-area-inset-right));
bottom: max(1.5rem, env(safe-area-inset-bottom));
}
}
`;
document.head.appendChild(style);
}
// 优化图片加载
function optimizeImages() {
const images = document.querySelectorAll('img');
images.forEach(img => {
// 添加懒加载
if (!img.loading) {
img.loading = 'lazy';
}
// 添加错误处理
img.addEventListener('error', function() {
this.style.display = 'none';
});
// 移动端图片优化
if (isMobile) {
// 移动端使用较小的图片
const src = img.src;
if (src && !src.includes('placeholder')) {
// 这里可以添加图片压缩逻辑
}
}
});
}
// 优化触摸事件
function optimizeTouch() {
// 添加触摸反馈
document.addEventListener('touchstart', function(e) {
const target = e.target;
if (target.tagName === 'BUTTON' || target.classList.contains('btn') || target.tagName === 'A') {
target.style.opacity = '0.7';
}
}, { passive: true });
document.addEventListener('touchend', function(e) {
const target = e.target;
if (target.tagName === 'BUTTON' || target.classList.contains('btn') || target.tagName === 'A') {
setTimeout(() => {
target.style.opacity = '';
}, 150);
}
}, { passive: true });
// 防止双击缩放
let lastTouchEnd = 0;
document.addEventListener('touchend', function(event) {
const now = (new Date()).getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
}
// 处理屏幕方向变化
function handleOrientationChange() {
// 延迟执行以确保尺寸更新
setTimeout(() => {
detectDevice();
// 重新计算布局
const event = new Event('resize');
window.dispatchEvent(event);
// 滚动到顶部(防止方向变化后位置错乱)
if (window.scrollY > 100) {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}, 100);
}
// 优化键盘弹出时的布局
function handleKeyboard() {
if (!isMobile) return;
const originalHeight = window.innerHeight;
let keyboardOpen = false;
window.addEventListener('resize', function() {
const currentHeight = window.innerHeight;
const heightDifference = originalHeight - currentHeight;
// 键盘弹出高度减少超过150px
if (heightDifference > 150 && !keyboardOpen) {
keyboardOpen = true;
document.body.classList.add('keyboard-open');
// 隐藏导航栏(为输入框腾出空间)
const navbar = document.getElementById('navbar');
if (navbar) {
navbar.style.transform = 'translateY(-100%)';
}
// 隐藏返回顶部按钮
const backToTop = document.getElementById('back-to-top');
if (backToTop) {
backToTop.style.display = 'none';
}
}
// 键盘收起
else if (heightDifference <= 150 && keyboardOpen) {
keyboardOpen = false;
document.body.classList.remove('keyboard-open');
// 恢复导航栏
const navbar = document.getElementById('navbar');
if (navbar) {
navbar.style.transform = '';
}
// 恢复返回顶部按钮
const backToTop = document.getElementById('back-to-top');
if (backToTop) {
backToTop.style.display = '';
}
}
});
}
// 性能优化
function optimizePerformance() {
// 使用 Intersection Observer 优化动画
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('animate-visible');
}
});
}, {
threshold: 0.1,
rootMargin: '50px'
});
// 观察所有动画元素
document.querySelectorAll('[class*="animate-"]').forEach(el => {
if (!el.classList.contains('animate-visible')) {
observer.observe(el);
}
});
}
// 移动端减少动画
if (isMobile) {
const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
if (mediaQuery.matches) {
document.body.classList.add('reduce-motion');
}
}
}
// 添加调试信息(开发环境)
function addDebugInfo() {
if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
const debugInfo = document.createElement('div');
debugInfo.style.cssText = `
position: fixed;
top: 70px;
right: 10px;
background: rgba(0,0,0,0.8);
color: white;
padding: 8px;
border-radius: 4px;
font-size: 12px;
z-index: 10000;
font-family: monospace;
`;
function updateDebugInfo() {
const { isMobile, isTablet, currentOrientation } = detectDevice();
debugInfo.innerHTML = `
${window.innerWidth}×${window.innerHeight}<br>
${isMobile ? 'Mobile' : isTablet ? 'Tablet' : 'Desktop'}<br>
${currentOrientation}
`;
}
updateDebugInfo();
document.body.appendChild(debugInfo);
window.addEventListener('resize', updateDebugInfo);
window.addEventListener('orientationchange', updateDebugInfo);
}
}
// 初始化移动端优化
function init() {
// 检测设备类型
detectDevice();
// 添加移动端样式
addMobileStyles();
// 优化触摸体验
optimizeTouch();
// 处理屏幕方向变化
window.addEventListener('orientationchange', handleOrientationChange);
window.addEventListener('resize', () => {
setTimeout(detectDevice, 100);
});
// 页面加载完成后的优化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
optimizeImages();
handleKeyboard();
optimizePerformance();
addDebugInfo();
}, 500);
});
} else {
setTimeout(() => {
optimizeImages();
handleKeyboard();
optimizePerformance();
addDebugInfo();
}, 500);
}
// 监听页面加载完成事件
document.addEventListener('pageLoaded', () => {
setTimeout(() => {
optimizeImages();
optimizePerformance();
}, 100);
});
}
// 提供外部接口
window.MobileOptimize = {
detectDevice,
isMobile: () => isMobile,
isTablet: () => isTablet,
getCurrentOrientation: () => currentOrientation,
optimizeImages,
optimizePerformance
};
// 初始化
init();
})();