first commit

This commit is contained in:
闫旭隆
2025-10-17 09:31:28 +08:00
commit 4698145045
589 changed files with 196795 additions and 0 deletions

View File

@ -0,0 +1,373 @@
/**
* 视口和缩放处理器
* 处理页面缩放、视口变化和响应式布局
*/
class ViewportHandler {
constructor() {
this.currentZoom = 1;
this.breakpoints = {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
'2xl': 1536
};
this.init();
}
init() {
// 检测初始缩放级别
this.detectZoomLevel();
// 设置事件监听器
this.setupEventListeners();
// 应用初始视口设置
this.applyViewportSettings();
// 处理初始布局
this.handleViewportChange();
}
/**
* 检测浏览器缩放级别
*/
detectZoomLevel() {
// 方法1使用 window.devicePixelRatio
const pixelRatio = window.devicePixelRatio || 1;
// 方法2使用 outerWidth 和 innerWidth 比较
const zoomLevel = Math.round((window.outerWidth / window.innerWidth) * 100) / 100;
// 方法3使用媒体查询检测
const mqString = `(resolution: ${window.devicePixelRatio}dppx)`;
const mq = window.matchMedia(mqString);
this.currentZoom = pixelRatio;
this.updateZoomClasses();
}
/**
* 设置事件监听器
*/
setupEventListeners() {
// 监听窗口大小变化
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
this.handleViewportChange();
this.detectZoomLevel();
}, 250);
});
// 监听缩放变化
window.addEventListener('wheel', (e) => {
if (e.ctrlKey || e.metaKey) {
setTimeout(() => {
this.detectZoomLevel();
}, 100);
}
});
// 监听方向变化(移动设备)
window.addEventListener('orientationchange', () => {
setTimeout(() => {
this.handleViewportChange();
}, 500);
});
// 监听媒体查询变化
this.setupMediaQueryListeners();
}
/**
* 设置媒体查询监听器
*/
setupMediaQueryListeners() {
// 监听不同断点
Object.entries(this.breakpoints).forEach(([name, width]) => {
const mq = window.matchMedia(`(min-width: ${width}px)`);
mq.addListener((e) => {
if (e.matches) {
this.onBreakpointChange(name, width);
}
});
});
// 监听高DPI屏幕
const highDpiQuery = window.matchMedia('(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)');
highDpiQuery.addListener((e) => {
if (e.matches) {
document.body.classList.add('high-dpi');
} else {
document.body.classList.remove('high-dpi');
}
});
// 监听触摸设备
const touchQuery = window.matchMedia('(hover: none) and (pointer: coarse)');
touchQuery.addListener((e) => {
if (e.matches) {
document.body.classList.add('touch-device');
} else {
document.body.classList.remove('touch-device');
}
});
}
/**
* 处理视口变化
*/
handleViewportChange() {
const viewport = {
width: window.innerWidth,
height: window.innerHeight,
orientation: window.innerWidth > window.innerHeight ? 'landscape' : 'portrait',
zoom: this.currentZoom
};
// 更新CSS变量
this.updateCSSVariables(viewport);
// 调整布局
this.adjustLayout(viewport);
// 优化字体大小
this.optimizeFontSize(viewport);
// 处理特殊组件
this.handleSpecialComponents(viewport);
// 触发自定义事件
window.dispatchEvent(new CustomEvent('viewportChanged', { detail: viewport }));
}
/**
* 更新CSS变量
*/
updateCSSVariables(viewport) {
const root = document.documentElement;
// 视口尺寸
root.style.setProperty('--vw', `${viewport.width * 0.01}px`);
root.style.setProperty('--vh', `${viewport.height * 0.01}px`);
root.style.setProperty('--vmin', `${Math.min(viewport.width, viewport.height) * 0.01}px`);
root.style.setProperty('--vmax', `${Math.max(viewport.width, viewport.height) * 0.01}px`);
// 缩放相关
root.style.setProperty('--zoom-level', this.currentZoom);
root.style.setProperty('--base-font-size', `${16 / this.currentZoom}px`);
// 响应式间距
const spacingUnit = Math.max(4, Math.min(8, viewport.width / 200));
root.style.setProperty('--spacing-unit', `${spacingUnit}px`);
}
/**
* 更新缩放相关的CSS类
*/
updateZoomClasses() {
const body = document.body;
// 移除旧的缩放类
body.classList.remove('zoom-50', 'zoom-75', 'zoom-90', 'zoom-100', 'zoom-110', 'zoom-125', 'zoom-150', 'zoom-200');
// 添加新的缩放类
if (this.currentZoom <= 0.5) {
body.classList.add('zoom-50');
} else if (this.currentZoom <= 0.75) {
body.classList.add('zoom-75');
} else if (this.currentZoom <= 0.9) {
body.classList.add('zoom-90');
} else if (this.currentZoom <= 1.1) {
body.classList.add('zoom-100');
} else if (this.currentZoom <= 1.25) {
body.classList.add('zoom-110');
} else if (this.currentZoom <= 1.5) {
body.classList.add('zoom-125');
} else if (this.currentZoom <= 2) {
body.classList.add('zoom-150');
} else {
body.classList.add('zoom-200');
}
}
/**
* 调整布局
*/
adjustLayout(viewport) {
const sidebar = document.querySelector('.sidebar');
const mainContent = document.querySelector('.main-content');
// 小屏幕自动折叠侧边栏
if (viewport.width < 768 && sidebar && !sidebar.classList.contains('collapsed')) {
// 触发侧边栏折叠
const toggleBtn = document.getElementById('toggleSidebar');
if (toggleBtn) {
toggleBtn.click();
}
}
// 调整聊天消息容器高度
const chatMessages = document.getElementById('chatMessages');
if (chatMessages) {
const headerHeight = document.querySelector('header')?.offsetHeight || 0;
const inputHeight = document.getElementById('chatModeInput')?.offsetHeight || 0;
const availableHeight = viewport.height - headerHeight - inputHeight - 40; // 40px for padding
chatMessages.style.maxHeight = `${availableHeight}px`;
}
}
/**
* 优化字体大小
*/
optimizeFontSize(viewport) {
// 根据视口宽度计算基础字体大小
let baseFontSize = 16;
if (viewport.width < 360) {
baseFontSize = 14;
} else if (viewport.width < 768) {
baseFontSize = 15;
} else if (viewport.width > 1920) {
baseFontSize = 18;
}
// 应用缩放调整
baseFontSize = baseFontSize / this.currentZoom;
// 设置根字体大小
document.documentElement.style.fontSize = `${baseFontSize}px`;
}
/**
* 处理特殊组件
*/
handleSpecialComponents(viewport) {
// 3D新闻卡片调整
const ticker3D = document.querySelector('.ticker-3d-container');
const tickerSection = document.querySelector('.ticker-section');
if (ticker3D) {
// 根据缩放级别调整3D卡片
if (this.currentZoom > 1.5) {
// 高缩放时隐藏
if (tickerSection) tickerSection.style.display = 'none';
} else if (this.currentZoom > 1.25) {
// 中等缩放时缩小
ticker3D.style.transform = 'scale(0.7)';
ticker3D.style.maxHeight = '80px';
if (tickerSection) tickerSection.style.display = 'block';
} else if (viewport.width < 768) {
ticker3D.style.transform = 'scale(0.8)';
if (tickerSection) tickerSection.style.display = 'block';
} else if (viewport.width < 1024) {
ticker3D.style.transform = 'scale(0.9)';
if (tickerSection) tickerSection.style.display = 'block';
} else {
ticker3D.style.transform = 'scale(1)';
ticker3D.style.maxHeight = '';
if (tickerSection) tickerSection.style.display = 'block';
}
// 3D卡片现在固定在底部不需要检测重叠
}
// 文字轮播调整
const rotatingWord = document.querySelector('.rotating-word-3d');
if (rotatingWord) {
if (viewport.width < 480) {
rotatingWord.style.fontSize = '1rem';
} else if (viewport.width < 768) {
rotatingWord.style.fontSize = '1.25rem';
} else {
rotatingWord.style.fontSize = '';
}
}
}
/**
* 应用视口设置
*/
applyViewportSettings() {
// 设置视口meta标签
let viewportMeta = document.querySelector('meta[name="viewport"]');
if (!viewportMeta) {
viewportMeta = document.createElement('meta');
viewportMeta.name = 'viewport';
document.head.appendChild(viewportMeta);
}
// 根据设备类型设置不同的视口配置
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if (isMobile) {
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes';
} else {
viewportMeta.content = 'width=device-width, initial-scale=1.0';
}
}
/**
* 断点变化处理
*/
onBreakpointChange(name, width) {
console.log(`Breakpoint changed to: ${name} (${width}px)`);
// 触发自定义事件
window.dispatchEvent(new CustomEvent('breakpointChanged', {
detail: { name, width }
}));
}
/**
* 获取当前断点
*/
getCurrentBreakpoint() {
const width = window.innerWidth;
let current = 'xs';
for (const [name, breakpoint] of Object.entries(this.breakpoints)) {
if (width >= breakpoint) {
current = name;
}
}
return current;
}
/**
* 检查是否为移动设备
*/
isMobile() {
return window.innerWidth < this.breakpoints.md ||
('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0);
}
/**
* 检查是否为高DPI屏幕
*/
isHighDPI() {
return window.devicePixelRatio > 1 ||
(window.matchMedia && window.matchMedia('(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)').matches);
}
/**
* 强制重新计算布局
*/
forceRecalculate() {
this.detectZoomLevel();
this.handleViewportChange();
}
}
// 创建全局实例
window.viewportHandler = new ViewportHandler();
// 导出给其他模块使用
if (typeof module !== 'undefined' && module.exports) {
module.exports = ViewportHandler;
}