Files
official_network/docs/响应式设计指南.md
张成 c4148d9eb6 1
2025-08-25 15:24:23 +08:00

489 lines
11 KiB
Markdown

# 响应式设计指南 - 不使用媒体查询
## 概述
本指南介绍如何使用 JavaScript 检测屏幕尺寸来替代传统的 CSS 媒体查询,实现更灵活、更可控的响应式设计。
## 解决方案架构
### 1. CSS 容器查询 (Container Queries)
- **文件**: `src/assets/css/responsive_without_media.css`
- **优势**: 最新的 CSS 标准,基于容器而非视口
- **兼容性**: 现代浏览器支持
### 2. JavaScript 检测 + 类名控制
- **文件**: `src/static/responsive_helper.js`
- **优势**: 完全兼容,可编程控制
- **兼容性**: 所有浏览器支持
### 3. Vue2 组件化响应式
- **文件**: `src/components/ResponsiveLayout.vue`
- **优势**: 组件化,易于维护
- **兼容性**: Vue2 项目
## 使用方法
### 基础使用
#### 1. 引入响应式助手
```html
<!-- 在 index.html 中引入 -->
<script src="/static/responsive_helper.js"></script>
```
#### 2. 使用响应式布局组件
```vue
<template>
<ResponsiveLayout :showDebug="true" @screenSizeChange="handleScreenChange">
<div class="page-content">
<!-- 你的内容 -->
</div>
</ResponsiveLayout>
</template>
<script>
import ResponsiveLayout from '@/components/ResponsiveLayout.vue';
export default {
components: { ResponsiveLayout },
methods: {
handleScreenChange(event) {
console.log('屏幕尺寸变化:', event.detail);
// 根据屏幕尺寸执行不同逻辑
}
}
};
</script>
```
#### 3. 使用响应式 CSS 类
```html
<!-- 根据屏幕尺寸显示/隐藏 -->
<div class="responsive-hidden-xs">超小屏幕隐藏</div>
<div class="responsive-hidden-sm">小屏幕隐藏</div>
<div class="responsive-hidden-md">中等屏幕隐藏</div>
<div class="responsive-hidden-lg">大屏幕隐藏</div>
<div class="responsive-hidden-xl">超大屏幕隐藏</div>
<!-- 根据屏幕尺寸显示 -->
<div class="responsive-visible-xs">超小屏幕显示</div>
<div class="responsive-visible-sm">小屏幕显示</div>
<div class="responsive-visible-md">中等屏幕显示</div>
<div class="responsive-visible-lg">大屏幕显示</div>
<div class="responsive-visible-xl">超大屏幕显示</div>
```
### 高级使用
#### 1. 自定义断点
```vue
<template>
<ResponsiveLayout :customBreakpoints="customBreakpoints">
<!-- 内容 -->
</ResponsiveLayout>
</template>
<script>
export default {
data() {
return {
customBreakpoints: {
xs: 320, // 超小屏幕
sm: 576, // 小屏幕
md: 768, // 中等屏幕
lg: 992, // 大屏幕
xl: 1200, // 超大屏幕
xxl: 1400 // 超超大屏幕
}
};
}
};
</script>
```
#### 2. 响应式内容控制
```vue
<template>
<div>
<!-- 移动端内容 -->
<div v-if="isMobile" class="mobile-content">
<h2>移动端优化内容</h2>
<p>触摸友好的界面设计</p>
</div>
<!-- 桌面端内容 -->
<div v-if="isDesktop" class="desktop-content">
<h2>桌面端完整内容</h2>
<p>鼠标和键盘友好的界面</p>
</div>
<!-- 平板端内容 -->
<div v-if="isTablet" class="tablet-content">
<h2>平板端适配内容</h2>
<p>触摸和鼠标混合操作</p>
</div>
</div>
</template>
<script>
export default {
computed: {
isMobile() {
return this.$refs.responsiveLayout?.isMobile || false;
},
isTablet() {
return this.$refs.responsiveLayout?.isTablet || false;
},
isDesktop() {
return this.$refs.responsiveLayout?.isDesktop || false;
}
}
};
</script>
```
#### 3. 动态样式调整
```vue
<template>
<div :class="dynamicClasses">
<button @click="adjustLayout">调整布局</button>
</div>
</template>
<script>
export default {
computed: {
dynamicClasses() {
const classes = ['base-layout'];
if (this.$refs.responsiveLayout) {
const size = this.$refs.responsiveLayout.currentScreenSize;
classes.push(`layout-${size}`);
if (this.$refs.responsiveLayout.isMobile) {
classes.push('mobile-optimized');
}
}
return classes;
}
},
methods: {
adjustLayout() {
const element = this.$el.querySelector('.content');
if (this.$refs.responsiveLayout) {
// 根据断点显示/隐藏元素
this.$refs.responsiveLayout.responsiveShow(element, 'md');
}
}
}
};
</script>
```
## CSS 类名系统
### 响应式断点类名
```css
/* 屏幕尺寸类名 */
.screen-xs { /* 超小屏幕样式 */ }
.screen-sm { /* 小屏幕样式 */ }
.screen-md { /* 中等屏幕样式 */ }
.screen-lg { /* 大屏幕样式 */ }
.screen-xl { /* 超大屏幕样式 */ }
.screen-xxl { /* 超超大屏幕样式 */ }
/* 容器尺寸类名 */
.container-xs { /* 超小容器样式 */ }
.container-sm { /* 小容器样式 */ }
.container-md { /* 中等容器样式 */ }
.container-lg { /* 大容器样式 */ }
.container-xl { /* 超大容器样式 */ }
.container-xxl { /* 超超大容器样式 */ }
```
### 响应式工具类
```css
/* 显示/隐藏 */
.responsive-hidden-xs { display: none !important; }
.responsive-visible-xs { display: block !important; }
/* 布局 */
.responsive-grid { display: grid !important; }
.responsive-flex { display: flex !important; }
.responsive-block { display: block !important; }
/* 间距 */
.responsive-m-0 { margin: 0 !important; }
.responsive-p-3 { padding: 1rem !important; }
/* 文本 */
.responsive-text-center { text-align: center; }
.responsive-text-primary { color: #3498db; }
/* 阴影 */
.responsive-shadow { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
.responsive-shadow-lg { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); }
```
## JavaScript API
### 全局方法
```javascript
// 响应式显示元素
window.responsiveShow(element, breakpoint);
// 响应式隐藏元素
window.responsiveHide(element, breakpoint);
// 响应式切换类名
window.responsiveToggleClass(element, className, breakpoint);
// 获取当前屏幕信息
const screenInfo = window.responsiveHelper.getCurrentScreenInfo();
```
### 事件监听
```javascript
// 监听屏幕尺寸变化
window.addEventListener('screenSizeChange', (event) => {
const { size, width, height, breakpoint } = event.detail;
if (size === 'xs' || size === 'sm' || size === 'md') {
// 移动端逻辑
console.log('切换到移动端');
} else if (size === 'lg') {
// 平板端逻辑
console.log('切换到平板端');
} else {
// 桌面端逻辑
console.log('切换到桌面端');
}
});
```
### 断点检测
```javascript
// 检查是否匹配特定断点
const isMobile = window.responsiveHelper.matchesBreakpoint('md');
const isTablet = window.responsiveHelper.matchesBreakpoint('lg');
const isDesktop = !window.responsiveHelper.matchesBreakpoint('lg');
```
## 最佳实践
### 1. 性能优化
```javascript
// 使用防抖优化 resize 事件
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
// 执行响应式逻辑
}, 100);
});
```
### 2. 渐进增强
```javascript
// 检测功能支持
if (CSS.supports('container-type', 'inline-size')) {
// 使用容器查询
console.log('支持容器查询');
} else {
// 回退到 JavaScript 检测
console.log('使用 JavaScript 检测');
}
```
### 3. 组件化设计
```vue
<!-- 创建可复用的响应式组件 -->
<template>
<div :class="responsiveClasses">
<slot name="mobile" v-if="isMobile"></slot>
<slot name="tablet" v-else-if="isTablet"></slot>
<slot name="desktop" v-else></slot>
<slot v-if="!isMobile && !isTablet && !isDesktop"></slot>
</div>
</template>
<script>
export default {
name: 'ResponsiveSlot',
inject: ['responsiveLayout'],
computed: {
isMobile() {
return this.responsiveLayout?.isMobile || false;
},
isTablet() {
return this.responsiveLayout?.isTablet || false;
},
isDesktop() {
return this.responsiveLayout?.isDesktop || false;
},
responsiveClasses() {
return {
'responsive-slot': true,
[`screen-${this.responsiveLayout?.currentScreenSize}`]: true
};
}
}
};
</script>
```
### 4. 主题切换
```javascript
// 根据屏幕尺寸切换主题
function switchThemeByScreen() {
const screenInfo = window.responsiveHelper.getCurrentScreenInfo();
if (screenInfo.isMobile) {
document.body.classList.add('theme-mobile');
document.body.classList.remove('theme-desktop');
} else {
document.body.classList.add('theme-desktop');
document.body.classList.remove('theme-mobile');
}
}
// 监听屏幕变化
window.addEventListener('screenSizeChange', switchThemeByScreen);
```
## 迁移指南
### 从媒体查询迁移
#### 原来的 CSS
```css
@media (max-width: 768px) {
.mobile-menu {
display: block;
}
.desktop-menu {
display: none;
}
}
```
#### 新的 JavaScript 方式
```javascript
// 在组件中
mounted() {
this.updateMenuVisibility();
window.addEventListener('screenSizeChange', this.updateMenuVisibility);
},
methods: {
updateMenuVisibility() {
const mobileMenu = this.$el.querySelector('.mobile-menu');
const desktopMenu = this.$el.querySelector('.desktop-menu');
if (this.$refs.responsiveLayout.isMobile) {
mobileMenu.style.display = 'block';
desktopMenu.style.display = 'none';
} else {
mobileMenu.style.display = 'none';
desktopMenu.style.display = 'block';
}
}
}
```
#### 新的 CSS 类方式
```css
/* 使用响应式类名 */
.mobile-menu {
display: none;
}
.desktop-menu {
display: block;
}
/* 移动端显示 */
.screen-xs .mobile-menu,
.screen-sm .mobile-menu,
.screen-md .mobile-menu {
display: block;
}
.screen-xs .desktop-menu,
.screen-sm .desktop-menu,
.screen-md .desktop-menu {
display: none;
}
```
## 调试和测试
### 1. 启用调试模式
```vue
<ResponsiveLayout :showDebug="true">
<!-- 内容 -->
</ResponsiveLayout>
```
### 2. 控制台调试
```javascript
// 查看当前屏幕信息
console.log(window.responsiveHelper.getCurrentScreenInfo());
// 手动触发屏幕变化
window.dispatchEvent(new Event('resize'));
```
### 3. 测试不同屏幕尺寸
```javascript
// 模拟不同屏幕尺寸
function simulateScreenSize(width) {
Object.defineProperty(window, 'innerWidth', {
writable: true,
configurable: true,
value: width
});
window.dispatchEvent(new Event('resize'));
}
// 测试移动端
simulateScreenSize(375);
// 测试平板端
simulateScreenSize(768);
// 测试桌面端
simulateScreenSize(1200);
```
## 总结
通过使用 JavaScript 检测屏幕尺寸替代媒体查询,我们获得了:
1. **更好的控制性**: 可以编程控制响应式行为
2. **更高的灵活性**: 支持复杂的响应式逻辑
3. **更好的性能**: 避免 CSS 重排和重绘
4. **更好的维护性**: 集中管理响应式逻辑
5. **更好的兼容性**: 支持所有浏览器
这种方案特别适合需要复杂响应式逻辑的现代 Web 应用。