1
This commit is contained in:
353
src/static/responsive_helper.js
Normal file
353
src/static/responsive_helper.js
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* 响应式助手 - 替代媒体查询的JavaScript解决方案
|
||||
* 动态检测屏幕尺寸并添加相应的响应式类名
|
||||
*/
|
||||
|
||||
class ResponsiveHelper {
|
||||
constructor() {
|
||||
// 响应式断点定义
|
||||
this.breakpoints = {
|
||||
xs: 380,
|
||||
sm: 480,
|
||||
md: 620,
|
||||
lg: 768,
|
||||
xl: 992,
|
||||
xxl: 1200,
|
||||
xxxl: 1500,
|
||||
xxxxl: 1600
|
||||
};
|
||||
|
||||
// 当前屏幕尺寸
|
||||
this.currentSize = '';
|
||||
|
||||
// 初始化
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化响应式助手
|
||||
*/
|
||||
init() {
|
||||
// 添加容器查询支持检测
|
||||
this.addContainerQuerySupport();
|
||||
|
||||
// 检测初始屏幕尺寸
|
||||
this.detectScreenSize();
|
||||
|
||||
// 监听窗口大小变化
|
||||
this.addResizeListener();
|
||||
|
||||
// 监听方向变化
|
||||
this.addOrientationListener();
|
||||
|
||||
// 添加触摸设备检测
|
||||
this.detectTouchDevice();
|
||||
|
||||
// 添加高分辨率屏幕检测
|
||||
this.detectHighDPI();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测当前屏幕尺寸并添加相应类名
|
||||
*/
|
||||
detectScreenSize() {
|
||||
const width = window.innerWidth;
|
||||
let newSize = '';
|
||||
|
||||
// 根据宽度确定屏幕尺寸
|
||||
if (width <= this.breakpoints.xs) {
|
||||
newSize = 'xs';
|
||||
} else if (width <= this.breakpoints.sm) {
|
||||
newSize = 'sm';
|
||||
} else if (width <= this.breakpoints.md) {
|
||||
newSize = 'md';
|
||||
} else if (width <= this.breakpoints.lg) {
|
||||
newSize = 'lg';
|
||||
} else if (width <= this.breakpoints.xl) {
|
||||
newSize = 'xl';
|
||||
} else if (width <= this.breakpoints.xxl) {
|
||||
newSize = 'xxl';
|
||||
} else if (width <= this.breakpoints.xxxl) {
|
||||
newSize = 'xxxl';
|
||||
} else {
|
||||
newSize = 'xxxxl';
|
||||
}
|
||||
|
||||
// 如果尺寸发生变化,更新类名
|
||||
if (newSize !== this.currentSize) {
|
||||
this.updateScreenClasses(newSize);
|
||||
this.currentSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新屏幕尺寸相关的CSS类名
|
||||
*/
|
||||
updateScreenClasses(newSize) {
|
||||
const body = document.body;
|
||||
const html = document.documentElement;
|
||||
|
||||
// 移除旧的屏幕尺寸类名
|
||||
const oldClasses = Object.values(this.breakpoints).map(size => `screen-${size}`);
|
||||
body.classList.remove(...oldClasses);
|
||||
html.classList.remove(...oldClasses);
|
||||
|
||||
// 添加新的屏幕尺寸类名
|
||||
body.classList.add(`screen-${newSize}`);
|
||||
html.classList.add(`screen-${newSize}`);
|
||||
|
||||
// 添加响应式容器类名
|
||||
this.addResponsiveContainerClasses();
|
||||
|
||||
// 触发自定义事件
|
||||
this.triggerScreenChangeEvent(newSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加响应式容器类名
|
||||
*/
|
||||
addResponsiveContainerClasses() {
|
||||
const containers = document.querySelectorAll('.responsive-container');
|
||||
|
||||
containers.forEach(container => {
|
||||
const width = container.offsetWidth;
|
||||
let containerSize = '';
|
||||
|
||||
// 根据容器宽度确定尺寸
|
||||
if (width <= this.breakpoints.xs) {
|
||||
containerSize = 'xs';
|
||||
} else if (width <= this.breakpoints.sm) {
|
||||
containerSize = 'sm';
|
||||
} else if (width <= this.breakpoints.md) {
|
||||
containerSize = 'md';
|
||||
} else if (width <= this.breakpoints.lg) {
|
||||
containerSize = 'lg';
|
||||
} else if (width <= this.breakpoints.xl) {
|
||||
containerSize = 'xl';
|
||||
} else if (width <= this.breakpoints.xxl) {
|
||||
containerSize = 'xxl';
|
||||
} else if (width <= this.breakpoints.xxxl) {
|
||||
containerSize = 'xxxl';
|
||||
} else {
|
||||
containerSize = 'xxxxl';
|
||||
}
|
||||
|
||||
// 移除旧的容器尺寸类名
|
||||
const oldContainerClasses = Object.values(this.breakpoints).map(size => `container-${size}`);
|
||||
container.classList.remove(...oldContainerClasses);
|
||||
|
||||
// 添加新的容器尺寸类名
|
||||
container.classList.add(`container-${containerSize}`);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加容器查询支持
|
||||
*/
|
||||
addContainerQuerySupport() {
|
||||
// 检测浏览器是否支持容器查询
|
||||
if (CSS.supports('container-type', 'inline-size')) {
|
||||
document.documentElement.classList.add('supports-container-queries');
|
||||
} else {
|
||||
document.documentElement.classList.add('no-container-queries');
|
||||
// 为不支持容器查询的浏览器提供回退方案
|
||||
this.addContainerQueryPolyfill();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 容器查询回退方案
|
||||
*/
|
||||
addContainerQueryPolyfill() {
|
||||
// 创建 ResizeObserver 来监听容器大小变化
|
||||
if (window.ResizeObserver) {
|
||||
const containers = document.querySelectorAll('.responsive-container');
|
||||
|
||||
containers.forEach(container => {
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
this.addResponsiveContainerClasses();
|
||||
});
|
||||
|
||||
resizeObserver.observe(container);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加窗口大小变化监听器
|
||||
*/
|
||||
addResizeListener() {
|
||||
let resizeTimeout;
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
// 使用防抖优化性能
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => {
|
||||
this.detectScreenSize();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加方向变化监听器
|
||||
*/
|
||||
addOrientationListener() {
|
||||
window.addEventListener('orientationchange', () => {
|
||||
// 方向变化后延迟检测,确保布局已更新
|
||||
setTimeout(() => {
|
||||
this.detectScreenSize();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测触摸设备
|
||||
*/
|
||||
detectTouchDevice() {
|
||||
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
|
||||
document.documentElement.classList.add('touch-device');
|
||||
} else {
|
||||
document.documentElement.classList.add('no-touch-device');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测高分辨率屏幕
|
||||
*/
|
||||
detectHighDPI() {
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
|
||||
if (dpr >= 2) {
|
||||
document.documentElement.classList.add('high-dpi');
|
||||
} else {
|
||||
document.documentElement.classList.add('low-dpi');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发屏幕变化事件
|
||||
*/
|
||||
triggerScreenChangeEvent(newSize) {
|
||||
const event = new CustomEvent('screenSizeChange', {
|
||||
detail: {
|
||||
size: newSize,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
breakpoint: this.breakpoints[newSize]
|
||||
}
|
||||
});
|
||||
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前屏幕尺寸信息
|
||||
*/
|
||||
getCurrentScreenInfo() {
|
||||
return {
|
||||
size: this.currentSize,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
breakpoint: this.breakpoints[this.currentSize],
|
||||
isMobile: this.currentSize === 'xs' || this.currentSize === 'sm' || this.currentSize === 'md',
|
||||
isTablet: this.currentSize === 'lg',
|
||||
isDesktop: this.currentSize === 'xl' || this.currentSize === 'xxl' || this.currentSize === 'xxxl' || this.currentSize === 'xxxxl'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否匹配特定断点
|
||||
*/
|
||||
matchesBreakpoint(breakpoint) {
|
||||
const width = window.innerWidth;
|
||||
return width <= this.breakpoints[breakpoint];
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加响应式工具方法
|
||||
*/
|
||||
addResponsiveUtils() {
|
||||
// 添加响应式显示/隐藏方法
|
||||
window.responsiveShow = (element, breakpoint = 'lg') => {
|
||||
if (this.matchesBreakpoint(breakpoint)) {
|
||||
element.style.display = 'block';
|
||||
} else {
|
||||
element.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
window.responsiveHide = (element, breakpoint = 'lg') => {
|
||||
if (this.matchesBreakpoint(breakpoint)) {
|
||||
element.style.display = 'none';
|
||||
} else {
|
||||
element.style.display = 'block';
|
||||
}
|
||||
};
|
||||
|
||||
// 添加响应式类名切换方法
|
||||
window.responsiveToggleClass = (element, className, breakpoint = 'lg') => {
|
||||
if (this.matchesBreakpoint(breakpoint)) {
|
||||
element.classList.add(className);
|
||||
} else {
|
||||
element.classList.remove(className);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁响应式助手
|
||||
*/
|
||||
destroy() {
|
||||
// 移除事件监听器
|
||||
window.removeEventListener('resize', this.detectScreenSize);
|
||||
window.removeEventListener('orientationchange', this.detectScreenSize);
|
||||
|
||||
// 移除类名
|
||||
const body = document.body;
|
||||
const html = document.documentElement;
|
||||
const oldClasses = Object.values(this.breakpoints).map(size => `screen-${size}`);
|
||||
body.classList.remove(...oldClasses);
|
||||
html.classList.remove(...oldClasses);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局实例
|
||||
window.responsiveHelper = new ResponsiveHelper();
|
||||
|
||||
// 添加响应式工具方法
|
||||
window.responsiveHelper.addResponsiveUtils();
|
||||
|
||||
// 导出类(如果使用模块系统)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = ResponsiveHelper;
|
||||
}
|
||||
|
||||
// 使用示例:
|
||||
/*
|
||||
// 监听屏幕尺寸变化
|
||||
window.addEventListener('screenSizeChange', (event) => {
|
||||
console.log('屏幕尺寸变化:', event.detail);
|
||||
|
||||
// 根据屏幕尺寸执行不同逻辑
|
||||
if (event.detail.size === 'xs' || event.detail.size === 'sm') {
|
||||
// 移动端逻辑
|
||||
console.log('移动端设备');
|
||||
} else if (event.detail.size === 'lg') {
|
||||
// 平板逻辑
|
||||
console.log('平板设备');
|
||||
} else {
|
||||
// 桌面端逻辑
|
||||
console.log('桌面端设备');
|
||||
}
|
||||
});
|
||||
|
||||
// 检查当前屏幕信息
|
||||
const screenInfo = window.responsiveHelper.getCurrentScreenInfo();
|
||||
console.log('当前屏幕信息:', screenInfo);
|
||||
|
||||
// 使用响应式工具方法
|
||||
const element = document.querySelector('.my-element');
|
||||
window.responsiveShow(element, 'md'); // 在中等屏幕以下显示
|
||||
window.responsiveHide(element, 'lg'); // 在大屏幕以上隐藏
|
||||
window.responsiveToggleClass(element, 'mobile-style', 'md'); // 在中等屏幕以下添加移动端样式
|
||||
*/
|
||||
Reference in New Issue
Block a user