This commit is contained in:
张成
2025-08-25 15:57:54 +08:00
parent 1ad48b234c
commit 3ed48736b6
19 changed files with 4233 additions and 2097 deletions

312
docs/LESS使用指南.md Normal file
View File

@@ -0,0 +1,312 @@
# LESS 使用指南
## 概述
本项目已全面从 CSS 转换为 LESS使用 LESS 的嵌套结构、变量、混合等特性来提高代码的可维护性和复用性。
## 🎯 LESS 的优势
### 1. **嵌套结构**
- 更清晰的代码层次结构
- 减少选择器重复
- 提高代码可读性
### 2. **变量系统**
- 统一的颜色、字体、间距管理
- 快速修改全局样式
- 减少重复值
### 3. **混合Mixins**
- 可复用的样式块
- 参数化样式
- 减少代码重复
### 4. **函数和运算**
- 动态计算尺寸
- 颜色混合和透明度
- 响应式断点管理
## 📁 文件结构
```
src/assets/css/
├── variables.less # 全局变量定义
├── common.less # 通用样式
├── animations.less # 动画效果
├── mobile_responsive.less # 移动端响应式
└── common_mobile.less # 通用移动端适配
```
## 🔧 已配置的 LESS 功能
### 1. **全局变量**
- 颜色系统(主色、成功、警告、错误等)
- 字体系统(大小、行高、字重)
- 间距系统(内边距、外边距)
- 断点系统(移动端、平板、桌面)
- 动画系统(时长、缓动、延迟)
### 2. **响应式混合**
```less
.mobile({
// 移动端样式
});
.tablet({
// 平板端样式
});
.desktop({
// 桌面端样式
});
```
### 3. **设备检测混合**
```less
.touch-device({
// 触摸设备样式
});
.high-dpi({
// 高分辨率屏幕样式
});
.landscape({
// 横屏模式样式
});
```
## 📝 使用方法
### 1. **引入变量文件**
```less
@import './variables.less';
```
### 2. **使用变量**
```less
.button {
background-color: @primary-color;
padding: @padding-md;
border-radius: @border-radius-base;
font-size: @font-size-base;
}
```
### 3. **嵌套结构**
```less
.card {
padding: @card-padding-base;
border: @border-width-base solid @border-color;
.card-header {
padding: @padding-md;
border-bottom: @border-width-base solid @border-color-light;
.card-title {
font-size: @font-size-h4;
color: @heading-color;
margin: 0;
}
}
.card-body {
padding: @padding-md;
.card-text {
color: @text-color;
line-height: @line-height-base;
}
}
}
```
### 4. **使用混合**
```less
.responsive-button {
.mobile({
width: 100%;
padding: @padding-sm;
font-size: @font-size-sm;
});
.tablet({
width: auto;
padding: @padding-md;
font-size: @font-size-base;
});
.desktop({
padding: @padding-lg;
font-size: @font-size-lg;
});
}
```
### 5. **颜色操作**
```less
.button {
background-color: @primary-color;
&:hover {
background-color: lighten(@primary-color, 10%);
}
&:active {
background-color: darken(@primary-color, 10%);
}
&.disabled {
background-color: fade(@primary-color, 50%);
}
}
```
## 🎨 颜色系统
### 主色调
- `@primary-color`: #3498db
- `@primary-light`: #5dade2
- `@primary-dark`: #2980b9
- `@primary-lighter`: #ebf3fd
### 功能色
- `@success-color`: #52c41a
- `@warning-color`: #faad14
- `@error-color`: #f5222d
- `@info-color`: #1890ff
### 中性色
- `@white`: #ffffff
- `@black`: #000000
- `@gray-1``@gray-10`: 从浅到深的灰色
## 📱 响应式断点
### 断点变量
- `@screen-xs`: 480px
- `@screen-sm`: 576px
- `@screen-md`: 768px
- `@screen-lg`: 992px
- `@screen-xl`: 1200px
- `@screen-xxl`: 1600px
### 设备断点
- `@mobile-breakpoint`: 768px
- `@tablet-breakpoint`: 992px
- `@desktop-breakpoint`: 1200px
## 🔄 动画系统
### 动画时长
- `@animation-duration-base`: 0.2s
- `@animation-duration-fast`: 0.1s
- `@animation-duration-slow`: 0.3s
- `@animation-duration-slower`: 0.5s
### 动画缓动
- `@animation-timing-base`: ease
- `@animation-timing-ease-in`: ease-in
- `@animation-timing-ease-out`: ease-out
- `@animation-timing-ease-in-out`: ease-in-out
- `@animation-timing-linear`: linear
## 🛠️ 开发工具
### 1. **Vue CLI 配置**
项目已配置 LESS 支持,包括:
- LESS 编译器
- 全局变量注入
- 自动前缀处理
### 2. **构建命令**
```bash
# 开发模式
yarn serve
# 生产构建
yarn build
```
## 📋 最佳实践
### 1. **变量命名**
- 使用语义化名称
- 遵循 BEM 命名规范
- 保持命名一致性
### 2. **嵌套深度**
- 避免超过 3 层嵌套
- 使用 `&` 符号引用父选择器
- 保持选择器简洁
### 3. **混合使用**
- 创建可复用的混合
- 参数化常用样式
- 避免过度抽象
### 4. **文件组织**
- 按功能模块组织文件
- 使用 `@import` 引入依赖
- 保持文件结构清晰
## 🚀 性能优化
### 1. **变量缓存**
- 减少重复计算
- 使用预定义值
- 避免运行时计算
### 2. **选择器优化**
- 避免过深嵌套
- 使用类选择器
- 减少选择器复杂度
### 3. **媒体查询优化**
- 使用混合管理断点
- 避免重复的媒体查询
- 合并相似的样式规则
## 🔍 调试技巧
### 1. **浏览器开发工具**
- 查看编译后的 CSS
- 检查选择器优先级
- 调试响应式样式
### 2. **LESS 编译错误**
- 检查语法错误
- 验证变量引用
- 确认文件路径
### 3. **样式冲突**
- 使用 `!important` 谨慎
- 检查选择器特异性
- 验证样式继承
## 📚 学习资源
### 1. **官方文档**
- [LESS 官网](http://lesscss.org/)
- [LESS 语言特性](http://lesscss.org/features/)
- [LESS 函数参考](http://lesscss.org/functions/)
### 2. **在线工具**
- [LESS 在线编译器](http://lesscss.org/less-preview/)
- [LESS 语法检查器](https://github.com/less/less.js)
### 3. **社区资源**
- [LESS GitHub](https://github.com/less/less.js)
- [LESS 论坛](https://github.com/less/less.js/discussions)
## 🎉 总结
通过使用 LESS我们实现了
1. **更好的代码组织**:嵌套结构和模块化文件
2. **统一的样式管理**:全局变量和混合系统
3. **高效的开发流程**:快速修改和样式复用
4. **响应式设计**:断点管理和设备适配
5. **维护性提升**:清晰的代码结构和语义化命名
LESS 为项目提供了强大的样式管理能力,让开发更加高效,维护更加简单。

View File

@@ -0,0 +1,314 @@
# 动画效果使用指南
## 概述
本项目已集成丰富的动画效果库包含多种CSS动画、悬停效果、滚动触发动画等让页面更加生动有趣。
## 🎯 已集成的动画类型
### 1. 基础动画类
#### 淡入动画
- `.fade-in` - 淡入
- `.fade-in-up` - 从下方淡入
- `.fade-in-down` - 从上方淡入
- `.fade-in-left` - 从左侧淡入
- `.fade-in-right` - 从右侧淡入
#### 滑入动画
- `.slide-in-up` - 从下方滑入
- `.slide-in-down` - 从上方滑入
- `.slide-in-left` - 从左侧滑入
- `.slide-in-right` - 从右侧滑入
#### 缩放动画
- `.zoom-in` - 缩放进入
- `.zoom-out` - 缩放退出
#### 特殊效果动画
- `.bounce` - 弹跳
- `.pulse` - 脉冲
- `.shake` - 抖动
- `.swing` - 摇摆
- `.rotate-in` - 旋转进入
- `.flip-in-x` - X轴翻转
- `.flip-in-y` - Y轴翻转
- `.light-speed-in` - 光速进入
- `.rubber-band` - 橡皮筋
- `.wobble` - 摇摆
- `.tada` - 庆祝
- `.heart-beat` - 心跳
- `.hinge` - 铰链
- `.roll-in` - 滚入
- `.roll-out` - 滚出
### 2. 悬停动画效果
- `.hover-lift` - 悬停时上浮
- `.hover-scale` - 悬停时缩放
- `.hover-rotate` - 悬停时旋转
- `.hover-glow` - 悬停时发光
- `.hover-bounce` - 悬停时弹跳
### 3. 滚动触发动画
- `.animate-on-scroll` - 滚动时触发动画
- `.animate-stagger` - 交错动画容器
### 4. 高级动画效果
- `.gradient-bg` - 渐变背景动画
- `.neon-text` - 霓虹灯文字效果
- `.wave` - 波浪效果
- `.particles` - 粒子效果
- `.flip-card` - 3D翻转卡片
- `.typewriter` - 打字机效果
## 🚀 使用方法
### 基础用法
```html
<!-- 添加动画类 -->
<div class="animate fade-in-up">这个元素会从下方淡入</div>
<!-- 设置动画时长 -->
<div class="animate fast fade-in-up">快速动画</div>
<div class="animate slow fade-in-up">慢速动画</div>
<!-- 设置动画延迟 -->
<div class="animate fade-in-up delay-1s">延迟1秒</div>
<div class="animate fade-in-up delay-2s">延迟2秒</div>
<!-- 无限循环 -->
<div class="animate infinite pulse">无限脉冲</div>
```
### 悬停效果
```html
<!-- 悬停时上浮 -->
<div class="hover-lift">悬停时会上浮</div>
<!-- 悬停时缩放 -->
<div class="hover-scale">悬停时会缩放</div>
<!-- 悬停时发光 -->
<div class="hover-glow">悬停时会发光</div>
```
### 滚动触发动画
```html
<!-- 滚动时触发 -->
<div class="animate-on-scroll">滚动到此处时显示</div>
<!-- 交错动画 -->
<div class="animate-stagger">
<div>第一个元素</div>
<div>第二个元素</div>
<div>第三个元素</div>
</div>
```
### 组合使用
```html
<!-- 组合多个动画类 -->
<div class="animate fade-in-up delay-1s hover-lift">
延迟淡入 + 悬停上浮
</div>
<!-- 动画容器 + 悬停效果 -->
<div class="animate-stagger">
<div class="hover-scale">悬停缩放</div>
<div class="hover-glow">悬停发光</div>
<div class="hover-rotate">悬停旋转</div>
</div>
```
## 🎨 自定义动画
### 创建新的关键帧动画
```css
@keyframes customAnimation {
0% {
opacity: 0;
transform: scale(0.5);
}
50% {
opacity: 0.5;
transform: scale(1.2);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.custom-animate {
animation-name: customAnimation;
animation-duration: 2s;
animation-timing-function: ease-in-out;
}
```
### 自定义悬停效果
```css
.custom-hover {
transition: all 0.3s ease;
}
.custom-hover:hover {
transform: translateY(-20px) rotate(10deg);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
}
```
## 🔧 JavaScript 动画控制
### 使用动画助手
```javascript
// 手动触发动画
window.animationHelper.triggerAnimation(element, 'fade-in');
// 添加滚动动画
window.animationHelper.addScrollAnimation(element, {
threshold: 0.2,
delay: 0.5
});
// 添加交错动画
window.animationHelper.addStaggerAnimation(container, {
delay: 0.2,
staggerDelay: 0.1
});
```
### 事件监听
```javascript
// 监听动画开始事件
element.addEventListener('animationStart', (event) => {
console.log('动画开始:', event.detail);
});
// 监听动画触发事件
element.addEventListener('animationTrigger', (event) => {
console.log('动画触发:', event.detail);
});
```
## 📱 响应式动画
### 移动端优化
```css
/* 移动端减少动画复杂度 */
@media (max-width: 768px) {
.animate {
animation-duration: 0.5s;
}
.floating-particles {
display: none;
}
}
```
### 性能优化
```css
/* 使用 will-change 优化性能 */
.animate {
will-change: transform, opacity;
}
/* 使用 transform3d 启用硬件加速 */
.animate {
transform: translate3d(0, 0, 0);
}
```
## 🎭 动画最佳实践
### 1. 适度使用
- 不要过度使用动画,影响用户体验
- 保持动画简洁明了
- 考虑用户的动画偏好设置
### 2. 性能考虑
- 使用 `transform``opacity` 属性
- 避免在动画中改变布局属性
- 合理使用 `will-change` 属性
### 3. 可访问性
- 尊重用户的 `prefers-reduced-motion` 设置
- 提供动画开关选项
- 确保动画不影响内容可读性
### 4. 时机控制
- 页面加载完成后延迟启动动画
- 滚动触发动画使用 Intersection Observer
- 合理设置动画延迟和持续时间
## 🐛 常见问题
### Q: 动画不工作?
A: 检查是否正确引入了 `animations.css` 文件,确保元素有正确的类名。
### Q: 动画性能差?
A: 使用 `transform``opacity` 属性,避免改变布局属性,启用硬件加速。
### Q: 移动端动画卡顿?
A: 减少动画复杂度,使用更简单的动画效果,考虑禁用某些复杂动画。
### Q: 如何禁用动画?
A: 在CSS中添加 `animation: none !important;` 或使用 `prefers-reduced-motion` 媒体查询。
## 📚 示例代码
### 完整的动画页面示例
```html
<template>
<div class="animated-page">
<!-- 滚动进度条 -->
<div class="scroll-progress-bar" data-scroll-progress="bar"></div>
<!-- 横幅区域 -->
<div class="banner animate-on-scroll">
<h1 class="animate fade-in-down text-glow">欢迎访问</h1>
<p class="animate fade-in-up delay-1s">精彩内容即将呈现</p>
</div>
<!-- 内容区域 -->
<div class="content animate-stagger">
<div class="card hover-lift">
<div class="icon animate pulse infinite">🚀</div>
<h3>快速开始</h3>
<p>简单易用的开发体验</p>
</div>
<div class="card hover-scale">
<div class="icon animate bounce delay-1s"></div>
<h3>高性能</h3>
<p>优化的性能表现</p>
</div>
<div class="card hover-glow">
<div class="icon animate wobble delay-2s">🎨</div>
<h3>美观设计</h3>
<p>现代化的视觉体验</p>
</div>
</div>
</div>
</template>
```
## 🎉 总结
通过合理使用这些动画效果,可以让您的页面更加生动有趣,提升用户体验。记住要适度使用,注重性能优化,并考虑可访问性需求。

View File

@@ -0,0 +1,307 @@
# 移动端适配指南
## 概述
本项目已全面适配移动端,包括响应式布局、触摸优化、性能优化等,确保在各种移动设备上都有良好的用户体验。
## 🎯 已实现的移动端适配
### 1. 响应式导航
- **桌面端导航**:完整的主菜单和下拉菜单
- **移动端导航**:汉堡菜单 + 全屏移动端菜单
- **返回按钮**:移动端菜单中的返回功能,已修复显示问题
### 2. 响应式布局
- **断点设置**
- 移动端≤768px
- 平板端769px-1024px
- 桌面端:>1024px
- **网格系统**:自动从多列调整为单列
- **容器适配**:边距和间距自动调整
### 3. 触摸设备优化
- **触摸友好尺寸**按钮最小高度44px
- **触摸友好间距**:菜单项间距优化
- **触摸反馈**:移动端禁用悬停效果
### 4. 性能优化
- **移动端动画简化**:减少复杂动画
- **图片优化**:高分辨率屏幕支持
- **硬件加速**启用GPU加速
## 📱 移动端适配详情
### 头部导航适配
#### 桌面端导航
```html
<div class="bottom desktop">
<!-- 完整的主菜单 -->
</div>
```
#### 移动端导航
```html
<div class="bottom headerBottom mobile">
<!-- 移动端导航栏 -->
</div>
<div id="mobileMenu" class="headerMobileMenu bread">
<!-- 移动端全屏菜单 -->
</div>
```
#### 返回按钮修复
```css
/* 返回按钮移动端适配 */
.goBack {
margin-top: 30px;
padding-top: 20px;
border-top: 2px solid rgba(255, 255, 255, 0.3);
}
.linkGoBack {
display: flex;
align-items: center;
color: white;
text-decoration: none;
font-size: 16px;
padding: 15px 0;
}
.linkGoBack img {
width: 20px;
height: 20px;
margin-right: 10px;
filter: brightness(0) invert(1);
}
```
### 页面布局适配
#### 横幅区域
```css
@media (max-width: 768px) {
.page-banner {
padding: 60px 0 40px !important;
}
.banner-title {
font-size: 2.5rem !important;
line-height: 1.2 !important;
}
.banner-subtitle {
font-size: 1.2rem !important;
line-height: 1.4 !important;
}
}
```
#### 网格布局
```css
@media (max-width: 768px) {
.advantages-grid,
.areas-grid,
.services-grid {
grid-template-columns: 1fr !important;
gap: 20px !important;
}
}
```
#### 卡片组件
```css
@media (max-width: 768px) {
.card,
.advantage-card,
.area-card {
padding: 25px 20px !important;
margin-bottom: 20px !important;
}
}
```
## 🔧 使用方法
### 1. 自动适配
大部分页面会自动适配移动端,无需额外配置。
### 2. 手动添加移动端类
```html
<!-- 移动端隐藏 -->
<div class="desktop-only">仅桌面端显示</div>
<!-- 移动端显示 -->
<div class="mobile-only">仅移动端显示</div>
<!-- 响应式容器 -->
<div class="container">自动适配边距</div>
<!-- 响应式网格 -->
<div class="grid">自动调整列数</div>
```
### 3. 自定义断点
```css
/* 自定义移动端断点 */
@media (max-width: 600px) {
.custom-element {
font-size: 14px;
}
}
```
## 📐 断点规范
### 标准断点
```css
/* 超小屏幕 */
@media (max-width: 360px) { }
/* 小屏幕手机 */
@media (max-width: 480px) { }
/* 移动端 */
@media (max-width: 768px) { }
/* 平板端 */
@media (min-width: 769px) and (max-width: 1024px) { }
/* 桌面端 */
@media (min-width: 1025px) { }
```
### 特殊断点
```css
/* 横屏模式 */
@media (orientation: landscape) and (max-height: 500px) { }
/* 触摸设备 */
@media (hover: none) and (pointer: coarse) { }
/* 高分辨率屏幕 */
@media (-webkit-min-device-pixel-ratio: 2) { }
/* 深色模式 */
@media (prefers-color-scheme: dark) { }
/* 减少动画偏好 */
@media (prefers-reduced-motion: reduce) { }
```
## 🎨 移动端样式规范
### 1. 字体大小
- **主标题**:移动端 2.5rem,小屏幕 2rem
- **副标题**:移动端 1.2rem,小屏幕 1rem
- **正文**:移动端 1rem小屏幕 0.95rem
### 2. 间距规范
- **页面间距**:移动端 40px小屏幕 30px
- **容器边距**:移动端 15px小屏幕 10px
- **卡片内边距**:移动端 25px 20px小屏幕 20px 15px
### 3. 触摸优化
- **按钮最小尺寸**44px × 44px
- **触摸间距**:最小 8px
- **触摸反馈**:禁用悬停效果
## 🚀 性能优化建议
### 1. 移动端优化
```css
/* 减少动画复杂度 */
@media (max-width: 768px) {
.animate {
animation-duration: 0.5s;
}
.floating-particles {
display: none;
}
}
```
### 2. 触摸设备优化
```css
/* 触摸友好的交互 */
@media (hover: none) and (pointer: coarse) {
.hover-effect {
display: none;
}
.touch-friendly {
min-height: 44px;
}
}
```
### 3. 高分辨率优化
```css
/* 高分辨率屏幕优化 */
@media (-webkit-min-device-pixel-ratio: 2) {
.icon {
image-rendering: -webkit-optimize-contrast;
}
}
```
## 🐛 常见问题解决
### Q: 返回按钮在移动端不显示?
A: 已修复,现在返回按钮在移动端菜单中正确显示,带有白色图标和文字。
### Q: 移动端菜单无法关闭?
A: 支持多种关闭方式:
- 点击返回按钮
- 点击菜单项
- 点击外部区域
- 按ESC键
### Q: 移动端动画卡顿?
A: 已优化:
- 减少动画复杂度
- 禁用复杂粒子效果
- 优化触摸设备性能
### Q: 如何自定义移动端样式?
A: 使用 `!important` 覆盖,或添加自定义断点:
```css
@media (max-width: 768px) {
.custom-element {
/* 自定义样式 */
}
}
```
## 📱 测试建议
### 1. 设备测试
- iPhone (各种尺寸)
- Android (各种尺寸)
- iPad (横竖屏)
- 桌面端 (各种分辨率)
### 2. 功能测试
- 导航菜单
- 触摸交互
- 滚动性能
- 动画效果
### 3. 性能测试
- 页面加载速度
- 滚动流畅度
- 内存使用
- 电池消耗
## 🎉 总结
通过全面的移动端适配,项目现在支持:
- ✅ 响应式导航
- ✅ 触摸友好交互
- ✅ 性能优化
- ✅ 多设备兼容
- ✅ 无障碍支持
所有页面都已适配移动端,确保在各种设备上都有良好的用户体验!

View File

@@ -23,6 +23,8 @@
"@vue/cli-plugin-babel": "^3.0.3",
"@vue/cli-service": "^3.0.3",
"autoprefixer": "^10.4.21",
"less": "^4.4.1",
"less-loader": "7.3.0",
"postcss-pxtorem": "^6.1.0",
"vue-template-compiler": "^2.5.17"
},

View File

@@ -1,785 +0,0 @@
/* 动画效果库 - 为项目添加丰富的动画效果 */
/* ===== 基础动画关键帧 ===== */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInUp {
from {
transform: translateY(100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideInDown {
from {
transform: translateY(-100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideInLeft {
from {
transform: translateX(-100px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideInRight {
from {
transform: translateX(100px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.3);
}
50% {
opacity: 1;
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes zoomOut {
from {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 1;
}
to {
opacity: 0;
transform: scale(0.3);
}
}
@keyframes bounce {
0%, 20%, 53%, 80%, 100% {
transform: translate3d(0, 0, 0);
}
40%, 43% {
transform: translate3d(0, -30px, 0);
}
70% {
transform: translate3d(0, -15px, 0);
}
90% {
transform: translate3d(0, -4px, 0);
}
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
@keyframes shake {
0%, 100% {
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
transform: translateX(-10px);
}
20%, 40%, 60%, 80% {
transform: translateX(10px);
}
}
@keyframes swing {
20% {
transform: rotate(15deg);
}
40% {
transform: rotate(-10deg);
}
60% {
transform: rotate(5deg);
}
80% {
transform: rotate(-5deg);
}
100% {
transform: rotate(0deg);
}
}
@keyframes rotateIn {
from {
transform: rotate(-200deg);
opacity: 0;
}
to {
transform: rotate(0);
opacity: 1;
}
}
@keyframes flipInX {
from {
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
opacity: 0;
}
40% {
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
}
60% {
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
}
80% {
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
}
to {
transform: perspective(400px);
opacity: 1;
}
}
@keyframes flipInY {
from {
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
opacity: 0;
}
40% {
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
}
60% {
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
}
80% {
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
}
to {
transform: perspective(400px);
opacity: 1;
}
}
@keyframes lightSpeedIn {
from {
transform: translate3d(100%, 0, 0) skewX(-30deg);
opacity: 0;
}
60% {
transform: skewX(20deg);
opacity: 1;
}
80% {
transform: skewX(-5deg);
}
to {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
@keyframes rubberBand {
from {
transform: scale(1);
}
30% {
transform: scaleX(1.25) scaleY(0.75);
}
40% {
transform: scaleX(0.75) scaleY(1.25);
}
50% {
transform: scaleX(1.15) scaleY(0.85);
}
65% {
transform: scaleX(0.95) scaleY(1.05);
}
75% {
transform: scaleX(1.05) scaleY(0.95);
}
to {
transform: scale(1);
}
}
@keyframes wobble {
from {
transform: translate3d(0, 0, 0);
}
15% {
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
}
30% {
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
}
45% {
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
}
60% {
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
}
75% {
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
}
to {
transform: translate3d(0, 0, 0);
}
}
@keyframes tada {
from {
transform: scale3d(1, 1, 1);
}
10%, 20% {
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
}
30%, 50%, 70%, 90% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
}
40%, 60%, 80% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
}
to {
transform: scale3d(1, 1, 1);
}
}
@keyframes heartBeat {
0% {
transform: scale(1);
}
14% {
transform: scale(1.3);
}
28% {
transform: scale(1);
}
42% {
transform: scale(1.3);
}
70% {
transform: scale(1);
}
}
@keyframes hinge {
0% {
transform: rotate(0);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
20%, 60% {
transform: rotate(80deg);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
40% {
transform: rotate(60deg);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
80% {
transform: rotate(60deg) translateY(0);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
100% {
transform: translateY(700px);
}
}
@keyframes rollIn {
from {
opacity: 0;
transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
@keyframes rollOut {
from {
opacity: 1;
}
to {
opacity: 0;
transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
}
}
/* ===== 动画类 ===== */
.animate {
animation-duration: 1s;
animation-fill-mode: both;
}
.animate.infinite {
animation-iteration-count: infinite;
}
.animate.delay-1s {
animation-delay: 1s;
}
.animate.delay-2s {
animation-delay: 2s;
}
.animate.delay-3s {
animation-delay: 3s;
}
.animate.delay-4s {
animation-delay: 4s;
}
.animate.delay-5s {
animation-delay: 5s;
}
.animate.fast {
animation-duration: 0.5s;
}
.animate.slow {
animation-duration: 2s;
}
.animate.slower {
animation-duration: 3s;
}
/* ===== 淡入动画 ===== */
.fade-in {
animation-name: fadeIn;
}
.fade-in-up {
animation-name: fadeInUp;
}
.fade-in-down {
animation-name: fadeInDown;
}
.fade-in-left {
animation-name: fadeInLeft;
}
.fade-in-right {
animation-name: fadeInRight;
}
/* ===== 滑入动画 ===== */
.slide-in-up {
animation-name: slideInUp;
}
.slide-in-down {
animation-name: slideInDown;
}
.slide-in-left {
animation-name: slideInLeft;
}
.slide-in-right {
animation-name: slideInRight;
}
/* ===== 缩放动画 ===== */
.zoom-in {
animation-name: zoomIn;
}
.zoom-out {
animation-name: zoomOut;
}
/* ===== 特殊效果动画 ===== */
.bounce {
animation-name: bounce;
}
.pulse {
animation-name: pulse;
}
.shake {
animation-name: shake;
}
.swing {
animation-name: swing;
}
.rotate-in {
animation-name: rotateIn;
}
.flip-in-x {
animation-name: flipInX;
}
.flip-in-y {
animation-name: flipInY;
}
.light-speed-in {
animation-name: lightSpeedIn;
}
.rubber-band {
animation-name: rubberBand;
}
.wobble {
animation-name: wobble;
}
.tada {
animation-name: tada;
}
.heart-beat {
animation-name: heartBeat;
}
.hinge {
animation-name: hinge;
}
.roll-in {
animation-name: rollIn;
}
.roll-out {
animation-name: rollOut;
}
/* ===== 悬停动画 ===== */
.hover-lift {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.hover-lift:hover {
transform: translateY(-10px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
.hover-scale {
transition: transform 0.3s ease;
}
.hover-scale:hover {
transform: scale(1.05);
}
.hover-rotate {
transition: transform 0.3s ease;
}
.hover-rotate:hover {
transform: rotate(5deg);
}
.hover-glow {
transition: box-shadow 0.3s ease;
}
.hover-glow:hover {
box-shadow: 0 0 20px rgba(52, 152, 219, 0.5);
}
.hover-bounce {
transition: transform 0.3s ease;
}
.hover-bounce:hover {
animation: bounce 0.6s ease;
}
/* ===== 滚动触发动画 ===== */
.scroll-animate {
opacity: 0;
transform: translateY(30px);
transition: all 0.8s ease;
}
.scroll-animate.animate-in {
opacity: 1;
transform: translateY(0);
}
/* ===== 加载动画 ===== */
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-dots {
display: inline-block;
}
.loading-dots::after {
content: '';
animation: dots 1.5s steps(5, end) infinite;
}
@keyframes dots {
0%, 20% { content: ''; }
40% { content: '.'; }
60% { content: '..'; }
80%, 100% { content: '...'; }
}
/* ===== 打字机效果 ===== */
.typewriter {
overflow: hidden;
border-right: 2px solid #333;
white-space: nowrap;
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink-caret {
from, to { border-color: transparent; }
50% { border-color: #333; }
}
/* ===== 波浪效果 ===== */
.wave {
position: relative;
overflow: hidden;
}
.wave::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
animation: wave 2s infinite;
}
@keyframes wave {
0% { left: -100%; }
100% { left: 100%; }
}
/* ===== 粒子效果 ===== */
.particles {
position: relative;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: #3498db;
border-radius: 50%;
animation: particle-float 3s infinite ease-in-out;
}
.particle:nth-child(1) { animation-delay: 0s; }
.particle:nth-child(2) { animation-delay: 0.5s; }
.particle:nth-child(3) { animation-delay: 1s; }
.particle:nth-child(4) { animation-delay: 1.5s; }
.particle:nth-child(5) { animation-delay: 2s; }
@keyframes particle-float {
0%, 100% {
transform: translateY(0) scale(1);
opacity: 1;
}
50% {
transform: translateY(-20px) scale(1.2);
opacity: 0.7;
}
}
/* ===== 3D翻转效果 ===== */
.flip-card {
perspective: 1000px;
height: 200px;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.8s;
transform-style: preserve-3d;
}
.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}
.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.flip-card-back {
transform: rotateY(180deg);
}
/* ===== 渐变背景动画 ===== */
.gradient-bg {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient-shift 15s ease infinite;
}
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* ===== 霓虹灯效果 ===== */
.neon-text {
color: #fff;
text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6;
animation: neon-pulse 1.5s ease-in-out infinite alternate;
}
@keyframes neon-pulse {
from { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6; }
to { text-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #0073e6, 0 0 8px #0073e6, 0 0 10px #0073e6, 0 0 12px #0073e6, 0 0 14px #0073e6; }
}
/* ===== 响应式动画 ===== */
@media (prefers-reduced-motion: reduce) {
.animate,
.hover-lift,
.hover-scale,
.hover-rotate,
.hover-glow,
.hover-bounce {
animation: none !important;
transition: none !important;
transform: none !important;
}
}
/* ===== 动画工具类 ===== */
.animate-on-scroll {
opacity: 0;
transform: translateY(50px);
transition: all 0.8s ease;
}
.animate-on-scroll.visible {
opacity: 1;
transform: translateY(0);
}
.animate-stagger > * {
opacity: 0;
transform: translateY(30px);
transition: all 0.6s ease;
}
.animate-stagger.visible > * {
opacity: 1;
transform: translateY(0);
}
.animate-stagger.visible > *:nth-child(1) { transition-delay: 0.1s; }
.animate-stagger.visible > *:nth-child(2) { transition-delay: 0.2s; }
.animate-stagger.visible > *:nth-child(3) { transition-delay: 0.3s; }
.animate-stagger.visible > *:nth-child(4) { transition-delay: 0.4s; }
.animate-stagger.visible > *:nth-child(5) { transition-delay: 0.5s; }
.animate-stagger.visible > *:nth-child(6) { transition-delay: 0.6s; }

View File

@@ -0,0 +1,761 @@
// 动画效果库 - LESS版本
@import './variables.less';
// ===== 动画变量 =====
@animation-duration: @animation-duration-base;
@animation-timing: @animation-timing-base;
@animation-fill-mode: both;
// ===== 基础动画关键帧 =====
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInLeft {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeInRight {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInUp {
from {
transform: translateY(100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideInDown {
from {
transform: translateY(-100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideInLeft {
from {
transform: translateX(-100px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideInRight {
from {
transform: translateX(100px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes zoomIn {
from {
opacity: 0;
transform: scale(0.3);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes zoomOut {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.3);
}
}
@keyframes bounce {
0%, 20%, 53%, 80%, 100% {
transform: translate3d(0, 0, 0);
}
40%, 43% {
transform: translate3d(0, -30px, 0);
}
70% {
transform: translate3d(0, -15px, 0);
}
90% {
transform: translate3d(0, -4px, 0);
}
}
@keyframes pulse {
from {
transform: scale3d(1, 1, 1);
}
50% {
transform: scale3d(1.05, 1.05, 1.05);
}
to {
transform: scale3d(1, 1, 1);
}
}
@keyframes shake {
0%, 100% {
transform: translate3d(0, 0, 0);
}
10%, 30%, 50%, 70%, 90% {
transform: translate3d(-10px, 0, 0);
}
20%, 40%, 60%, 80% {
transform: translate3d(10px, 0, 0);
}
}
@keyframes swing {
20% {
transform: rotate(15deg);
}
40% {
transform: rotate(-10deg);
}
60% {
transform: rotate(5deg);
}
80% {
transform: rotate(-5deg);
}
100% {
transform: rotate(0deg);
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes flip {
0% {
transform: perspective(400px) rotateY(0);
}
40% {
transform: perspective(400px) rotateY(90deg);
}
60% {
transform: perspective(400px) rotateY(180deg);
}
80% {
transform: perspective(400px) rotateY(270deg);
}
100% {
transform: perspective(400px) rotateY(360deg);
}
}
@keyframes lightSpeedIn {
from {
transform: translate3d(100%, 0, 0) skewX(-30deg);
opacity: 0;
}
60% {
transform: skewX(20deg);
opacity: 1;
}
80% {
transform: skewX(-5deg);
opacity: 1;
}
to {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
@keyframes rubberBand {
from {
transform: scale3d(1, 1, 1);
}
30% {
transform: scale3d(1.25, 0.75, 1);
}
40% {
transform: scale3d(0.75, 1.25, 1);
}
50% {
transform: scale3d(1.15, 0.85, 1);
}
65% {
transform: scale3d(0.95, 1.05, 1);
}
75% {
transform: scale3d(1.05, 0.95, 1);
}
to {
transform: scale3d(1, 1, 1);
}
}
@keyframes wobble {
0% {
transform: translate3d(0, 0, 0);
}
15% {
transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
}
30% {
transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
}
45% {
transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
}
60% {
transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
}
75% {
transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
}
100% {
transform: translate3d(0, 0, 0);
}
}
@keyframes tada {
0% {
transform: scale3d(1, 1, 1);
}
10%, 20% {
transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg);
}
30%, 50%, 70%, 90% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
}
40%, 60%, 80% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
}
100% {
transform: scale3d(1, 1, 1);
}
}
@keyframes heartBeat {
0% {
transform: scale(1);
}
14% {
transform: scale(1.3);
}
28% {
transform: scale(1);
}
42% {
transform: scale(1.3);
}
70% {
transform: scale(1);
}
}
@keyframes hinge {
0% {
transform: rotate(0);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
20%, 60% {
transform: rotate(80deg);
transform-origin: top left;
animation-timing-function: ease-in-out;
}
40%, 80% {
transform: rotate(60deg);
transform-origin: top left;
animation-timing-function: ease-in-out;
opacity: 1;
}
100% {
transform: translate3d(0, 700px, 0);
opacity: 0;
}
}
@keyframes roll {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
// ===== 基础动画类 =====
.animate {
animation-duration: @animation-duration;
animation-fill-mode: @animation-fill-mode;
animation-timing-function: @animation-timing;
}
// 淡入动画
.fade-in { animation-name: fadeIn; }
.fade-in-up { animation-name: fadeInUp; }
.fade-in-down { animation-name: fadeInDown; }
.fade-in-left { animation-name: fadeInLeft; }
.fade-in-right { animation-name: fadeInRight; }
// 滑入动画
.slide-in-up { animation-name: slideInUp; }
.slide-in-down { animation-name: slideInDown; }
.slide-in-left { animation-name: slideInLeft; }
.slide-in-right { animation-name: slideInRight; }
// 缩放动画
.zoom-in { animation-name: zoomIn; }
.zoom-out { animation-name: zoomOut; }
// 特殊动画
.bounce { animation-name: bounce; }
.pulse { animation-name: pulse; }
.shake { animation-name: shake; }
.swing { animation-name: swing; }
.rotate { animation-name: rotate; }
.flip { animation-name: flip; }
.light-speed-in { animation-name: lightSpeedIn; }
.rubber-band { animation-name: rubberBand; }
.wobble { animation-name: wobble; }
.tada { animation-name: tada; }
.heart-beat { animation-name: heartBeat; }
.hinge { animation-name: hinge; }
.roll { animation-name: roll; }
// ===== 动画时长 =====
.duration-0_5s { animation-duration: 0.5s; }
.duration-1s { animation-duration: 1s; }
.duration-1_5s { animation-duration: 1.5s; }
.duration-2s { animation-duration: 2s; }
.duration-3s { animation-duration: 3s; }
// ===== 动画延迟 =====
.delay-0_5s { animation-delay: 0.5s; }
.delay-1s { animation-delay: 1s; }
.delay-1_5s { animation-delay: 1.5s; }
.delay-2s { animation-delay: 2s; }
.delay-3s { animation-delay: 3s; }
// ===== 动画重复 =====
.infinite { animation-iteration-count: infinite; }
.repeat-2 { animation-iteration-count: 2; }
.repeat-3 { animation-iteration-count: 3; }
// ===== 悬停动画效果 =====
.hover-lift {
transition: transform 0.3s ease, box-shadow 0.3s ease;
&:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
}
.hover-scale {
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
.hover-glow {
transition: box-shadow 0.3s ease;
&:hover {
box-shadow: 0 0 20px rgba(0, 123, 255, 0.5);
}
}
.hover-rotate {
transition: transform 0.3s ease;
&:hover {
transform: rotate(5deg);
}
}
.hover-bounce {
transition: transform 0.3s ease;
&:hover {
animation: bounce 0.6s ease;
}
}
// ===== 滚动触发动画 =====
.scroll-animate {
opacity: 0;
transform: translateY(30px);
transition: all 0.8s ease;
&.animate-in {
opacity: 1;
transform: translateY(0);
}
}
// ===== 交错动画 =====
.animate-stagger {
> * {
opacity: 0;
transform: translateY(20px);
transition: all 0.6s ease;
&:nth-child(1) { transition-delay: 0.1s; }
&:nth-child(2) { transition-delay: 0.2s; }
&:nth-child(3) { transition-delay: 0.3s; }
&:nth-child(4) { transition-delay: 0.4s; }
&:nth-child(5) { transition-delay: 0.5s; }
&:nth-child(6) { transition-delay: 0.6s; }
&.animate-in {
opacity: 1;
transform: translateY(0);
}
}
}
// ===== 加载指示器 =====
.loading-spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
// ===== 打字机效果 =====
.typewriter {
overflow: hidden;
border-right: 2px solid #000;
white-space: nowrap;
animation: typing 3.5s steps(40, end), blink-caret 0.75s step-end infinite;
}
@keyframes typing {
from { width: 0; }
to { width: 100%; }
}
@keyframes blink-caret {
from, to { border-color: transparent; }
50% { border-color: #000; }
}
// ===== 波浪效果 =====
.wave {
position: relative;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.3) 50%, transparent 70%);
animation: wave 2s infinite;
}
}
@keyframes wave {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
// ===== 粒子效果 =====
.particles {
position: relative;
overflow: hidden;
&::before,
&::after {
content: '';
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
animation: float 6s infinite;
}
&::before {
left: 20%;
animation-delay: 0s;
}
&::after {
right: 20%;
animation-delay: 3s;
}
}
@keyframes float {
0%, 100% { transform: translateY(0px) rotate(0deg); opacity: 1; }
50% { transform: translateY(-20px) rotate(180deg); opacity: 0.5; }
}
// ===== 3D翻转卡片 =====
.flip-card {
perspective: 1000px;
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.6s;
transform-style: preserve-3d;
&:hover {
transform: rotateY(180deg);
}
}
.flip-card-front,
.flip-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.flip-card-back {
transform: rotateY(180deg);
}
}
// ===== 渐变背景动画 =====
.gradient-bg {
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
background-size: 400% 400%;
animation: gradient 15s ease infinite;
}
@keyframes gradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
// ===== 霓虹文字效果 =====
.neon-text {
color: #fff;
text-shadow:
0 0 5px #fff,
0 0 10px #fff,
0 0 15px #0073e6,
0 0 20px #0073e6,
0 0 25px #0073e6,
0 0 30px #0073e6,
0 0 35px #0073e6;
animation: neon-pulse 1.5s ease-in-out infinite alternate;
}
@keyframes neon-pulse {
from { text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #0073e6, 0 0 20px #0073e6, 0 0 25px #0073e6, 0 0 30px #0073e6, 0 0 35px #0073e6; }
to { text-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #0073e6, 0 0 8px #0073e6, 0 0 10px #0073e6, 0 0 12px #0073e6, 0 0 14px #0073e6; }
}
// ===== 滚动进度条 =====
.scroll-progress-bar {
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 3px;
background: linear-gradient(90deg, #0073e6, #00d4ff);
z-index: 9999;
transition: width 0.1s ease;
}
// ===== 视差滚动元素 =====
.parallax {
position: relative;
overflow: hidden;
.parallax-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 120%;
background-size: cover;
background-position: center;
transform: translateZ(0);
will-change: transform;
}
}
// ===== 浮动粒子 =====
.floating-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
z-index: 1;
.floating-particle {
position: absolute;
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.6);
border-radius: 50%;
animation: float-particle 8s infinite linear;
&:nth-child(1) { left: 10%; animation-delay: 0s; animation-duration: 8s; }
&:nth-child(2) { left: 20%; animation-delay: 1s; animation-duration: 10s; }
&:nth-child(3) { left: 30%; animation-delay: 2s; animation-duration: 12s; }
&:nth-child(4) { left: 40%; animation-delay: 3s; animation-duration: 9s; }
&:nth-child(5) { left: 50%; animation-delay: 4s; animation-duration: 11s; }
&:nth-child(6) { left: 60%; animation-delay: 5s; animation-duration: 7s; }
&:nth-child(7) { left: 70%; animation-delay: 6s; animation-duration: 13s; }
&:nth-child(8) { left: 80%; animation-delay: 7s; animation-duration: 8s; }
&:nth-child(9) { left: 90%; animation-delay: 8s; animation-duration: 10s; }
&:nth-child(10) { left: 95%; animation-delay: 9s; animation-duration: 12s; }
}
}
@keyframes float-particle {
0% {
transform: translateY(100vh) scale(0);
opacity: 0;
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: translateY(-100px) scale(1);
opacity: 0;
}
}
// ===== 文字发光效果 =====
.text-glow {
text-shadow:
0 0 5px currentColor,
0 0 10px currentColor,
0 0 15px currentColor,
0 0 20px currentColor;
animation: text-glow-pulse 2s ease-in-out infinite alternate;
}
@keyframes text-glow-pulse {
from { text-shadow: 0 0 5px currentColor, 0 0 10px currentColor, 0 0 15px currentColor, 0 0 20px currentColor; }
to { text-shadow: 0 0 10px currentColor, 0 0 20px currentColor, 0 0 30px currentColor, 0 0 40px currentColor; }
}
// ===== 响应式动画考虑 =====
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// ===== 移动端动画优化 =====
@media (max-width: 768px) {
.floating-particles {
display: none; // 移动端隐藏浮动粒子以提升性能
}
.animate {
animation-duration: 0.8s; // 移动端减少动画时长
}
.scroll-animate {
transform: translateY(20px); // 移动端减少移动距离
}
}
// ===== 性能优化 =====
.animate,
.hover-lift,
.hover-scale,
.hover-glow,
.hover-rotate,
.hover-bounce {
will-change: transform, opacity;
transform: translate3d(0, 0, 0); // 启用硬件加速
}
// ===== 动画工具类 =====
.animation-paused { animation-play-state: paused; }
.animation-running { animation-play-state: running; }
.animation-reverse { animation-direction: reverse; }
.animation-alternate { animation-direction: alternate; }
.animation-alternate-reverse { animation-direction: alternate-reverse; }

View File

@@ -1,39 +0,0 @@
.scrollToContentWrapper {
height: 6em;
text-align: center;
z-index: 5000;
}
.scrollToContentWrapper>a.scrollToContent {
position: relative;
display: inline-block;
margin-top: -3em;
background: lightyellow;
width: 4.8em;
height: 4.8em;
line-height: 5.6em;
border: 1px solid #eee;
border-radius: 50%;
background-color: #fff;
text-align: center;
cursor: pointer;
text-decoration: none;
color: #000;
}
.scrollToContentWrapper>a.scrollToContent:hover {
background-color: #000 !important;
border-color: #111;
text-decoration: none;
}
.scrollToContentWrapper>a.scrollToContent:hover img {
-webkit-filter: invert(100%);
filter: invert(100%);
}
.scrollToContentWrapper>a.scrollToContent>img {
height: 1.0em;
}

View File

@@ -0,0 +1,40 @@
// 通用样式 - LESS版本
@import './variables.less';
.scrollToContentWrapper {
height: 6em;
text-align: center;
z-index: 5000;
> a.scrollToContent {
position: relative;
display: inline-block;
margin-top: -3em;
background: lightyellow;
width: 4.8em;
height: 4.8em;
line-height: 5.6em;
border: 1px solid #eee;
border-radius: 50%;
background-color: #fff;
text-align: center;
cursor: pointer;
text-decoration: none;
color: #000;
&:hover {
background-color: #000 !important;
border-color: #111;
text-decoration: none;
img {
-webkit-filter: invert(100%);
filter: invert(100%);
}
}
> img {
height: 1.0em;
}
}
}

View File

@@ -0,0 +1,933 @@
// 通用移动端适配样式 - 适用于所有页面 - LESS版本
@import './variables.less';
// ===== 移动端断点变量 =====
// 使用全局变量文件中的断点
// ===== 移动端基础适配 =====
@media (max-width: @mobile-breakpoint) {
// 页面横幅移动端适配
.page-banner {
padding: 60px 0 40px !important;
}
.banner-title {
font-size: 2.5rem !important;
line-height: 1.2 !important;
}
.banner-subtitle {
font-size: 1.2rem !important;
line-height: 1.4 !important;
}
// 容器移动端适配
.container {
padding: 0 15px !important;
}
// 标题移动端适配
.section-title {
font-size: 2rem !important;
line-height: 1.3 !important;
}
.section-subtitle {
font-size: 1.1rem !important;
line-height: 1.5 !important;
}
// 网格布局移动端适配
.grid,
.advantages-grid,
.areas-grid,
.services-grid,
.team-grid,
.contact-grid,
.tech-grid {
grid-template-columns: 1fr !important;
gap: 20px !important;
}
// 卡片移动端适配
.card,
.advantage-card,
.area-card,
.service-item,
.team-member,
.contact-card,
.tech-layer {
padding: 25px 20px !important;
margin-bottom: 20px !important;
}
// 内容区域移动端适配
.content-section {
margin-bottom: 40px !important;
}
.section-text {
font-size: 1rem !important;
line-height: 1.6 !important;
}
// 图标移动端适配
.icon,
.service-icon,
.advantage-icon,
.area-icon,
.contact-icon {
font-size: 2.5rem !important;
margin-bottom: 15px !important;
}
// 列表移动端适配
.feature-list,
.advantage-features,
.area-features {
padding-left: 20px !important;
li {
margin-bottom: 8px !important;
font-size: 0.95rem !important;
}
}
// 时间线移动端适配
.timeline {
padding-left: 20px !important;
.timeline-item {
margin-bottom: 30px !important;
padding-left: 20px !important;
.timeline-date {
font-size: 0.9rem !important;
margin-bottom: 8px !important;
}
.timeline-title {
font-size: 1.1rem !important;
margin-bottom: 10px !important;
}
.timeline-content {
font-size: 0.95rem !important;
line-height: 1.5 !important;
}
}
}
// 统计数字移动端适配
.stats-section {
padding: 40px 0 !important;
.stats-grid {
grid-template-columns: repeat(2, 1fr) !important;
gap: 20px !important;
}
.stat-item {
text-align: center !important;
padding: 20px 15px !important;
.stat-number {
font-size: 2rem !important;
margin-bottom: 10px !important;
}
.stat-label {
font-size: 0.9rem !important;
}
}
}
// 团队介绍移动端适配
.team-section {
.team-grid {
grid-template-columns: 1fr !important;
gap: 25px !important;
}
.team-member {
text-align: center !important;
.member-photo {
width: 120px !important;
height: 120px !important;
margin: 0 auto 15px !important;
}
.member-name {
font-size: 1.2rem !important;
margin-bottom: 8px !important;
}
.member-position {
font-size: 0.9rem !important;
margin-bottom: 10px !important;
}
.member-description {
font-size: 0.9rem !important;
line-height: 1.5 !important;
}
}
}
// 联系信息移动端适配
.contact-section {
.contact-grid {
grid-template-columns: 1fr !important;
gap: 25px !important;
}
.contact-info {
text-align: center !important;
.contact-icon {
font-size: 2rem !important;
margin-bottom: 15px !important;
}
.contact-title {
font-size: 1.1rem !important;
margin-bottom: 8px !important;
}
.contact-detail {
font-size: 0.95rem !important;
line-height: 1.5 !important;
}
}
}
// 技术栈移动端适配
.tech-section {
.tech-grid {
grid-template-columns: repeat(2, 1fr) !important;
gap: 15px !important;
}
.tech-layer {
padding: 20px 15px !important;
text-align: center !important;
.tech-icon {
font-size: 2rem !important;
margin-bottom: 10px !important;
}
.tech-name {
font-size: 0.9rem !important;
}
}
}
// 解决方案移动端适配
.solutions-section {
.solution-item {
margin-bottom: 30px !important;
padding: 20px !important;
.solution-icon {
font-size: 2.5rem !important;
margin-bottom: 15px !important;
text-align: center !important;
}
.solution-title {
font-size: 1.3rem !important;
margin-bottom: 12px !important;
text-align: center !important;
}
.solution-description {
font-size: 0.95rem !important;
line-height: 1.6 !important;
text-align: center !important;
}
}
}
// 优势特点移动端适配
.advantages-section {
.advantage-item {
margin-bottom: 25px !important;
padding: 20px !important;
text-align: center !important;
.advantage-icon {
font-size: 2.5rem !important;
margin-bottom: 15px !important;
}
.advantage-title {
font-size: 1.2rem !important;
margin-bottom: 10px !important;
}
.advantage-description {
font-size: 0.9rem !important;
line-height: 1.5 !important;
}
}
}
// 服务领域移动端适配
.areas-section {
.area-item {
margin-bottom: 25px !important;
padding: 20px !important;
text-align: center !important;
.area-icon {
font-size: 2.5rem !important;
margin-bottom: 15px !important;
}
.area-title {
font-size: 1.2rem !important;
margin-bottom: 10px !important;
}
.area-description {
font-size: 0.9rem !important;
line-height: 1.5 !important;
}
.area-features {
margin-top: 15px !important;
text-align: left !important;
}
}
}
// 按钮移动端适配
.btn,
.button {
padding: 12px 24px !important;
font-size: 16px !important;
min-height: 44px !important; // 触摸友好尺寸
width: 100% !important; // 移动端全宽按钮
&.btn-large {
padding: 15px 30px !important;
font-size: 18px !important;
}
&.btn-small {
padding: 8px 16px !important;
font-size: 14px !important;
}
&.btn-block {
display: block !important;
width: 100% !important;
}
}
// 表单移动端适配
.form-section {
.form-group {
margin-bottom: 20px !important;
label {
display: block !important;
margin-bottom: 8px !important;
font-weight: 500 !important;
font-size: 0.95rem !important;
}
input,
textarea,
select {
width: 100% !important;
padding: 12px !important;
font-size: 16px !important; // 防止iOS缩放
border: 1px solid #ddd !important;
border-radius: 4px !important;
min-height: 44px !important; // 触摸友好尺寸
&:focus {
outline: none !important;
border-color: #3498db !important;
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2) !important;
}
}
textarea {
min-height: 100px !important;
resize: vertical !important;
}
.form-help {
font-size: 0.85rem !important;
color: #666 !important;
margin-top: 5px !important;
}
}
.form-actions {
text-align: center !important;
margin-top: 30px !important;
.btn {
margin: 0 5px 10px !important;
}
}
}
// 图片移动端适配
.image-section {
img {
max-width: 100% !important;
height: auto !important;
border-radius: 8px !important;
}
.image-caption {
font-size: 0.9rem !important;
color: #666 !important;
text-align: center !important;
margin-top: 10px !important;
}
}
// 视频移动端适配
.video-section {
.video-container {
position: relative !important;
width: 100% !important;
height: 0 !important;
padding-bottom: 56.25% !important; // 16:9 比例
iframe,
video {
position: absolute !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
border-radius: 8px !important;
}
}
}
// 表格移动端适配
.table-section {
.table-responsive {
overflow-x: auto !important;
-webkit-overflow-scrolling: touch !important;
table {
min-width: 600px !important;
font-size: 0.9rem !important;
th,
td {
padding: 8px 12px !important;
white-space: nowrap !important;
}
}
}
}
// 分页移动端适配
.pagination {
display: flex !important;
justify-content: center !important;
flex-wrap: wrap !important;
gap: 5px !important;
margin: 30px 0 !important;
.page-item {
.page-link {
padding: 8px 12px !important;
font-size: 14px !important;
min-width: 40px !important;
text-align: center !important;
border-radius: 4px !important;
}
}
}
// 面包屑移动端适配
.breadcrumb {
padding: 10px 0 !important;
font-size: 0.9rem !important;
.breadcrumb-item {
margin-right: 8px !important;
&:not(:last-child)::after {
content: '>' !important;
margin-left: 8px !important;
color: #999 !important;
}
}
}
// 标签移动端适配
.tags {
display: flex !important;
flex-wrap: wrap !important;
gap: 8px !important;
margin: 15px 0 !important;
.tag {
padding: 4px 8px !important;
font-size: 0.8rem !important;
border-radius: 12px !important;
background: #f0f0f0 !important;
color: #333 !important;
}
}
// 警告框移动端适配
.alert {
padding: 15px !important;
margin: 20px 0 !important;
border-radius: 4px !important;
font-size: 0.95rem !important;
&.alert-success {
background: #d4edda !important;
border: 1px solid #c3e6cb !important;
color: #155724 !important;
}
&.alert-warning {
background: #fff3cd !important;
border: 1px solid #ffeaa7 !important;
color: #856404 !important;
}
&.alert-danger {
background: #f8d7da !important;
border: 1px solid #f5c6cb !important;
color: #721c24 !important;
}
&.alert-info {
background: #d1ecf1 !important;
border: 1px solid #bee5eb !important;
color: #0c5460 !important;
}
}
// 进度条移动端适配
.progress {
height: 20px !important;
margin: 15px 0 !important;
border-radius: 10px !important;
overflow: hidden !important;
.progress-bar {
height: 100% !important;
border-radius: 10px !important;
font-size: 0.8rem !important;
line-height: 20px !important;
}
}
// 模态框移动端适配
.modal {
.modal-dialog {
margin: 10px !important;
max-width: calc(100% - 20px) !important;
}
.modal-content {
border-radius: 8px !important;
}
.modal-header {
padding: 15px 20px !important;
.modal-title {
font-size: 1.2rem !important;
}
}
.modal-body {
padding: 20px !important;
font-size: 0.95rem !important;
}
.modal-footer {
padding: 15px 20px !important;
.btn {
margin: 0 5px !important;
}
}
}
// 工具提示移动端适配
.tooltip {
font-size: 0.85rem !important;
max-width: 200px !important;
}
// 弹出框移动端适配
.popover {
max-width: 250px !important;
font-size: 0.9rem !important;
.popover-header {
font-size: 1rem !important;
padding: 10px 15px !important;
}
.popover-body {
padding: 10px 15px !important;
}
}
// 手风琴移动端适配
.accordion {
.accordion-item {
margin-bottom: 10px !important;
border-radius: 8px !important;
overflow: hidden !important;
.accordion-header {
.accordion-button {
padding: 15px 20px !important;
font-size: 1rem !important;
&:not(.collapsed) {
background-color: #f8f9fa !important;
}
}
}
.accordion-body {
padding: 15px 20px !important;
font-size: 0.95rem !important;
line-height: 1.6 !important;
}
}
}
// 标签页移动端适配
.nav-tabs {
flex-wrap: wrap !important;
.nav-item {
margin-bottom: 5px !important;
.nav-link {
padding: 8px 12px !important;
font-size: 0.9rem !important;
border-radius: 4px !important;
&.active {
background-color: #007bff !important;
border-color: #007bff !important;
color: white !important;
}
}
}
}
// 导航栏移动端适配
.navbar {
.navbar-brand {
font-size: 1.2rem !important;
}
.navbar-nav {
.nav-link {
padding: 10px 15px !important;
font-size: 0.95rem !important;
border-bottom: 1px solid #eee !important;
&:hover {
background-color: #f8f9fa !important;
}
}
}
}
// 侧边栏移动端适配
.sidebar {
position: fixed !important;
top: 0 !important;
left: -100% !important;
width: 80% !important;
height: 100vh !important;
background: white !important;
z-index: 1000 !important;
transition: left 0.3s ease !important;
overflow-y: auto !important;
&.active {
left: 0 !important;
}
.sidebar-header {
padding: 20px !important;
border-bottom: 1px solid #eee !important;
.close-sidebar {
float: right !important;
background: none !important;
border: none !important;
font-size: 1.5rem !important;
cursor: pointer !important;
}
}
.sidebar-body {
padding: 20px !important;
}
}
// 页脚移动端适配
.footer {
padding: 40px 0 20px !important;
text-align: center !important;
.footer-content {
margin-bottom: 30px !important;
.footer-section {
margin-bottom: 25px !important;
.footer-title {
font-size: 1.1rem !important;
margin-bottom: 15px !important;
}
.footer-links {
list-style: none !important;
padding: 0 !important;
li {
margin-bottom: 8px !important;
a {
color: #666 !important;
text-decoration: none !important;
font-size: 0.9rem !important;
&:hover {
color: #333 !important;
}
}
}
}
}
}
.footer-bottom {
border-top: 1px solid #eee !important;
padding-top: 20px !important;
font-size: 0.85rem !important;
color: #999 !important;
}
}
}
// ===== 平板端适配 =====
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
.container {
padding: 0 30px !important;
}
.grid,
.advantages-grid,
.areas-grid,
.services-grid,
.team-grid,
.contact-grid,
.tech-grid {
grid-template-columns: repeat(2, 1fr) !important;
gap: 25px !important;
}
.stats-grid {
grid-template-columns: repeat(4, 1fr) !important;
}
.tech-grid {
grid-template-columns: repeat(3, 1fr) !important;
}
}
// ===== 小屏幕移动端适配 =====
@media (max-width: @small-mobile) {
.container {
padding: 0 10px !important;
}
.banner-title {
font-size: 2rem !important;
}
.banner-subtitle {
font-size: 1rem !important;
}
.section-title {
font-size: 1.8rem !important;
}
.section-subtitle {
font-size: 1rem !important;
}
.stats-grid {
grid-template-columns: 1fr !important;
}
.card,
.advantage-card,
.area-card,
.service-item,
.team-member,
.contact-card,
.tech-layer {
padding: 20px 15px !important;
}
}
// ===== 超小屏幕移动端适配 =====
@media (max-width: @xs-mobile) {
.container {
padding: 0 8px !important;
}
.banner-title {
font-size: 1.8rem !important;
}
.banner-subtitle {
font-size: 0.9rem !important;
}
.section-title {
font-size: 1.6rem !important;
}
.section-subtitle {
font-size: 0.9rem !important;
}
.card,
.advantage-card,
.area-card,
.service-item,
.team-member,
.contact-card,
.tech-layer {
padding: 15px 12px !important;
}
.btn,
.button {
padding: 8px 16px !important;
font-size: 14px !important;
}
}
// ===== 触摸设备优化 =====
@media (hover: none) and (pointer: coarse) {
// 触摸设备禁用悬停效果
.btn:hover,
.button:hover,
.card:hover,
.advantage-card:hover,
.area-card:hover,
.service-item:hover,
.team-member:hover,
.contact-card:hover,
.tech-layer:hover {
transform: none !important;
box-shadow: none !important;
}
// 触摸设备增加触摸反馈
.btn,
.button,
.card,
.advantage-card,
.area-card,
.service-item,
.team-member,
.contact-card,
.tech-layer {
-webkit-tap-highlight-color: rgba(52, 152, 219, 0.3) !important;
&:active {
transform: scale(0.98) !important;
transition: transform 0.1s ease !important;
}
}
}
// ===== 高分辨率屏幕适配 =====
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.icon,
.service-icon,
.advantage-icon,
.area-icon,
.contact-icon {
image-rendering: -webkit-optimize-contrast !important;
image-rendering: crisp-edges !important;
}
}
// ===== 横屏模式适配 =====
@media (orientation: landscape) and (max-height: 500px) {
.page-banner {
padding: 30px 0 20px !important;
}
.banner-title {
font-size: 2rem !important;
margin-bottom: 15px !important;
}
.banner-subtitle {
font-size: 1rem !important;
margin-bottom: 20px !important;
}
.section {
padding: 30px 0 !important;
}
}
// ===== 打印样式 =====
@media print {
.mobile-nav,
.sidebar,
.modal,
.tooltip,
.popover {
display: none !important;
}
.container {
padding: 0 !important;
}
.section {
padding: 20px 0 !important;
page-break-inside: avoid !important;
}
.card,
.advantage-card,
.area-card,
.service-item,
.team-member,
.contact-card,
.tech-layer {
page-break-inside: avoid !important;
margin-bottom: 15px !important;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,251 @@
/*PAGE*/
/* 导入全局变量 */
@import './variables.less';
/* 使用 LESS 变量定义响应式断点 */
@breakpoint-xs: 380px;
@breakpoint-sm: 480px;
@breakpoint-md: 620px;
@breakpoint-lg: 768px;
@breakpoint-xl: 992px;
@breakpoint-xxl: 1200px;
@breakpoint-xxxl: 1500px;
@breakpoint-xxxxl: 1600px;
/* 间距变量 */
@spacing-xs: 0.5em;
@spacing-sm: 1em;
@spacing-md: 1.5em;
@spacing-lg: 2em;
@spacing-xl: 3em;
@spacing-xxl: 4em;
@spacing-xxxl: 5em;
@spacing-xxxxl: 7em;
/* 字体大小变量 */
@font-size-xs: 0.9em;
@font-size-sm: 1.2em;
@font-size-md: 1.5em;
@font-size-lg: 2.5em;
@font-size-xl: 3em;
/* 布局变量 */
@sidebar-width: 25%;
@content-width: 75%;
@content-padding: 4em;
@sidebar-padding: 5em;
.contentPage {
position: relative;
width: 100%;
vertical-align: top;
margin: 0 auto;
padding-top: @spacing-xxxxl;
min-height: 100vh;
/* 容器查询支持 */
container-type: inline-size;
container-name: content-page;
}
/* CONTENT TABLES */
.contentTableLeft {
width: @sidebar-width;
padding-left: @sidebar-padding;
padding-top: @spacing-xl;
vertical-align: top;
}
.contentTableRight {
width: @content-width;
padding-top: 3.5em;
padding-left: @content-padding;
padding-right: @content-padding;
vertical-align: top;
}
/* 使用容器查询替代媒体查询 */
@container content-page (max-width: @breakpoint-xxxxl) {
.contentTableRight {
padding-right: 8em;
}
}
@container content-page (max-width: @breakpoint-xxxl) {
.contentTableRight {
padding-right: 6em;
}
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-xl;
}
}
@container content-page (max-width: @breakpoint-xxl) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-lg;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 75%;
}
.contentTableLeft {
padding-left: @spacing-xl;
padding-top: @spacing-xl;
}
.contentTableRight {
padding-left: @spacing-xl;
padding-right: @spacing-xl;
}
}
@container content-page (max-width: @breakpoint-xl) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-md;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 85%;
}
.contentTableLeft {
padding-left: @spacing-lg;
padding-top: @spacing-lg;
}
.contentTableRight {
padding-left: @spacing-lg;
padding-right: @spacing-lg;
}
}
@container content-page (max-width: @breakpoint-lg) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-sm;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 90%;
}
.contentTableLeft {
padding-left: @spacing-md;
padding-top: @spacing-md;
}
.contentTableRight {
padding-left: @spacing-md;
padding-right: @spacing-md;
}
}
@container content-page (max-width: @breakpoint-md) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-xs;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 95%;
}
.contentTableLeft {
padding-left: @spacing-sm;
padding-top: @spacing-sm;
}
.contentTableRight {
padding-left: @spacing-sm;
padding-right: @spacing-sm;
}
}
@container content-page (max-width: @breakpoint-sm) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-xs;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 100%;
}
.contentTableLeft {
padding-left: @spacing-xs;
padding-top: @spacing-xs;
}
.contentTableRight {
padding-left: @spacing-xs;
padding-right: @spacing-xs;
}
}
@container content-page (max-width: @breakpoint-xs) {
.contentPage .contentPageBanner .bannerBox .bannerBoxTitle {
font-size: @font-size-xs;
}
.contentPage .contentPageBanner .bannerBox .bread {
width: 100%;
}
.contentTableLeft {
padding-left: @spacing-xs;
padding-top: @spacing-xs;
}
.contentTableRight {
padding-left: @spacing-xs;
padding-right: @spacing-xs;
}
}
/* 响应式布局调整 */
@media (max-width: @breakpoint-lg) {
.contentPage {
padding-top: @spacing-xxl;
}
.contentTableLeft,
.contentTableRight {
width: 100%;
display: block;
}
.contentTableLeft {
padding-bottom: @spacing-lg;
}
}
@media (max-width: @breakpoint-md) {
.contentPage {
padding-top: @spacing-xl;
}
.contentTableLeft {
padding-bottom: @spacing-md;
}
}
@media (max-width: @breakpoint-sm) {
.contentPage {
padding-top: @spacing-lg;
}
.contentTableLeft {
padding-bottom: @spacing-sm;
}
}
@media (max-width: @breakpoint-xs) {
.contentPage {
padding-top: @spacing-md;
}
.contentTableLeft {
padding-bottom: @spacing-xs;
}
}

View File

@@ -0,0 +1,602 @@
// 移动端响应式适配样式 - LESS版本
@import './variables.less';
// ===== 移动端断点变量 =====
// 使用全局变量文件中的断点
// ===== 移动端断点 =====
@media (max-width: @mobile-breakpoint) {
// 头部导航移动端适配
.header {
padding: 10px 0;
.content {
padding: 0 15px;
}
}
// 桌面端导航隐藏
.desktop {
display: none !important;
}
// 移动端导航显示
.mobile {
display: flex !important;
}
// 移动端导航样式
.mobile-nav {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.logoCell {
.logo {
height: 40px;
width: auto;
}
}
.mobileIconsCell {
cursor: pointer;
img {
width: 24px;
height: 24px;
}
}
// 移动端菜单样式
.headerMobileMenu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.9);
z-index: 1000;
display: none;
overflow-y: auto;
&.active {
display: block;
}
.menuContent {
padding: 80px 20px 20px;
color: white;
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
margin: 15px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding-bottom: 15px;
}
a {
color: white;
text-decoration: none;
font-size: 18px;
display: block;
padding: 10px 0;
}
.hasSubmenu {
color: #3498db;
font-weight: bold;
margin-bottom: 10px;
}
.subMenu {
margin-left: 20px;
margin-top: 10px;
li {
border-bottom: none;
margin: 10px 0;
padding-bottom: 5px;
a {
font-size: 16px;
color: rgba(255, 255, 255, 0.8);
}
}
}
}
.closeMenu {
position: absolute;
top: 20px;
right: 20px;
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 10px;
&:hover {
color: #3498db;
}
}
.goBack {
margin-top: 30px;
padding-top: 20px;
border-top: 2px solid rgba(255, 255, 255, 0.3);
text-align: center;
a {
color: white;
text-decoration: none;
font-size: 16px;
display: inline-flex;
align-items: center;
gap: 8px;
&:hover {
color: #3498db;
}
img {
width: 16px;
height: 16px;
filter: invert(1);
}
}
}
}
// 移动端横幅适配
.banner {
height: 60vh;
min-height: 400px;
.banner-content {
padding: 40px 20px;
text-align: center;
.banner-title {
font-size: 2.5rem;
line-height: 1.2;
margin-bottom: 20px;
}
.banner-subtitle {
font-size: 1.2rem;
line-height: 1.4;
margin-bottom: 30px;
}
.banner-button {
padding: 12px 24px;
font-size: 16px;
}
}
}
// 移动端内容区域适配
.pageWidth {
padding: 0 15px;
}
.section {
padding: 40px 0;
.section-title {
font-size: 2rem;
line-height: 1.3;
margin-bottom: 20px;
}
.section-subtitle {
font-size: 1.1rem;
line-height: 1.5;
margin-bottom: 30px;
}
}
// 移动端网格布局适配
.grid,
.advantages-grid,
.areas-grid,
.services-grid,
.team-grid,
.contact-grid {
grid-template-columns: 1fr;
gap: 20px;
}
// 移动端卡片适配
.card,
.advantage-card,
.area-card,
.service-card,
.team-card,
.contact-card {
padding: 20px;
margin-bottom: 20px;
.card-title {
font-size: 1.3rem;
margin-bottom: 15px;
}
.card-content {
font-size: 1rem;
line-height: 1.6;
}
}
// 移动端按钮适配
.btn,
.button {
padding: 12px 24px;
font-size: 16px;
min-height: 44px; // 触摸友好尺寸
&.btn-large {
padding: 15px 30px;
font-size: 18px;
}
&.btn-small {
padding: 8px 16px;
font-size: 14px;
}
}
// 移动端表单适配
.form-group {
margin-bottom: 20px;
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}
input,
textarea,
select {
width: 100%;
padding: 12px;
font-size: 16px; // 防止iOS缩放
border: 1px solid #ddd;
border-radius: 4px;
min-height: 44px; // 触摸友好尺寸
&:focus {
outline: none;
border-color: #3498db;
box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
}
}
textarea {
min-height: 100px;
resize: vertical;
}
}
// 移动端图片适配
img {
max-width: 100%;
height: auto;
}
// 移动端图标适配
.icon {
width: 24px;
height: 24px;
&.icon-large {
width: 32px;
height: 32px;
}
&.icon-small {
width: 16px;
height: 16px;
}
}
// 移动端间距适配
.mt-mobile { margin-top: 20px !important; }
.mb-mobile { margin-bottom: 20px !important; }
.ml-mobile { margin-left: 15px !important; }
.mr-mobile { margin-right: 15px !important; }
.pt-mobile { padding-top: 20px !important; }
.pb-mobile { padding-bottom: 20px !important; }
.pl-mobile { padding-left: 15px !important; }
.pr-mobile { padding-right: 15px !important; }
// 移动端隐藏元素
.hide-mobile {
display: none !important;
}
// 移动端显示元素
.show-mobile {
display: block !important;
}
// 移动端文本对齐
.text-center-mobile {
text-align: center !important;
}
.text-left-mobile {
text-align: left !important;
}
.text-right-mobile {
text-align: right !important;
}
}
// ===== 平板端适配 =====
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
.pageWidth {
padding: 0 30px;
}
.grid,
.advantages-grid,
.areas-grid,
.services-grid,
.team-grid,
.contact-grid {
grid-template-columns: repeat(2, 1fr);
gap: 25px;
}
.section {
padding: 50px 0;
}
.banner {
height: 70vh;
.banner-content {
padding: 60px 40px;
.banner-title {
font-size: 3rem;
}
.banner-subtitle {
font-size: 1.4rem;
}
}
}
}
// ===== 小屏幕移动端适配 =====
@media (max-width: @small-mobile) {
.pageWidth {
padding: 0 10px;
}
.banner {
.banner-content {
padding: 30px 15px;
.banner-title {
font-size: 2rem;
}
.banner-subtitle {
font-size: 1rem;
}
}
}
.section {
padding: 30px 0;
.section-title {
font-size: 1.8rem;
}
.section-subtitle {
font-size: 1rem;
}
}
.card,
.advantage-card,
.area-card,
.service-card,
.team-card,
.contact-card {
padding: 15px;
.card-title {
font-size: 1.2rem;
}
}
.btn,
.button {
padding: 10px 20px;
font-size: 15px;
}
}
// ===== 超小屏幕移动端适配 =====
@media (max-width: @xs-mobile) {
.pageWidth {
padding: 0 8px;
}
.banner {
.banner-content {
padding: 25px 10px;
.banner-title {
font-size: 1.8rem;
}
.banner-subtitle {
font-size: 0.9rem;
}
}
}
.section {
padding: 25px 0;
.section-title {
font-size: 1.6rem;
}
.section-subtitle {
font-size: 0.9rem;
}
}
.card,
.advantage-card,
.area-card,
.service-card,
.team-card,
.contact-card {
padding: 12px;
.card-title {
font-size: 1.1rem;
}
}
.btn,
.button {
padding: 8px 16px;
font-size: 14px;
}
}
// ===== 触摸设备优化 =====
@media (hover: none) and (pointer: coarse) {
// 触摸设备禁用悬停效果
.hover-lift:hover,
.hover-scale:hover,
.hover-glow:hover,
.hover-rotate:hover,
.hover-bounce:hover {
transform: none;
box-shadow: none;
}
// 触摸设备增加触摸反馈
.btn,
.button,
.card,
.advantage-card,
.area-card,
.service-card,
.team-card,
.contact-card {
-webkit-tap-highlight-color: rgba(52, 152, 219, 0.3);
&:active {
transform: scale(0.98);
transition: transform 0.1s ease;
}
}
// 触摸设备优化菜单项
.menuContent {
li {
a {
padding: 15px 0; // 增加触摸区域
min-height: 44px; // 触摸友好尺寸
display: flex;
align-items: center;
}
}
}
}
// ===== 高分辨率屏幕适配 =====
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.logo {
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
.icon {
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
}
// ===== 横屏模式适配 =====
@media (orientation: landscape) and (max-height: 500px) {
.headerMobileMenu {
.menuContent {
padding: 60px 20px 20px;
}
.closeMenu {
top: 15px;
right: 15px;
}
}
.banner {
height: 100vh;
.banner-content {
padding: 30px 20px;
.banner-title {
font-size: 2rem;
margin-bottom: 15px;
}
.banner-subtitle {
font-size: 1rem;
margin-bottom: 20px;
}
}
}
}
// ===== 打印样式 =====
@media print {
.headerMobileMenu,
.mobile-nav,
.floating-particles,
.scroll-progress-bar {
display: none !important;
}
.pageWidth {
padding: 0 !important;
}
.section {
padding: 20px 0 !important;
page-break-inside: avoid;
}
.card,
.advantage-card,
.area-card,
.service-card,
.team-card,
.contact-card {
page-break-inside: avoid;
margin-bottom: 15px !important;
}
}

View File

@@ -0,0 +1,279 @@
// ===== LESS 变量定义文件 =====
// ===== 颜色变量 =====
@primary-color: #3498db;
@primary-light: #5dade2;
@primary-dark: #2980b9;
@primary-lighter: #ebf3fd;
@success-color: #52c41a;
@success-light: #73d13d;
@success-dark: #389e0d;
@success-lighter: #f6ffed;
@warning-color: #faad14;
@warning-light: #ffc53d;
@warning-dark: #d48806;
@warning-lighter: #fffbe6;
@error-color: #f5222d;
@error-light: #ff4d4f;
@error-dark: #cf1322;
@error-lighter: #fff2f0;
@info-color: #1890ff;
@info-light: #40a9ff;
@info-dark: #096dd9;
@info-lighter: #e6f7ff;
// 中性色
@white: #ffffff;
@black: #000000;
@gray-1: #fafafa;
@gray-2: #f5f5f5;
@gray-3: #f0f0f0;
@gray-4: #d9d9d9;
@gray-5: #bfbfbf;
@gray-6: #8c8c8c;
@gray-7: #595959;
@gray-8: #434343;
@gray-9: #262626;
@gray-10: #1f1f1f;
// 文字颜色
@text-color: @gray-8;
@text-color-secondary: @gray-6;
@text-color-disabled: @gray-5;
@heading-color: @gray-9;
@link-color: @primary-color;
@link-hover-color: @primary-light;
// 背景颜色
@bg-color: @white;
@bg-color-light: @gray-1;
@bg-color-dark: @gray-2;
// 边框颜色
@border-color: @gray-4;
@border-color-light: @gray-3;
@border-color-dark: @gray-5;
// ===== 字体变量 =====
@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
@font-family-code: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
@font-size-base: 14px;
@font-size-lg: 16px;
@font-size-sm: 12px;
@font-size-xs: 10px;
@font-size-h1: 38px;
@font-size-h2: 30px;
@font-size-h3: 24px;
@font-size-h4: 20px;
@font-size-h5: 16px;
@font-size-h6: 14px;
@line-height-base: 1.5715;
@line-height-lg: 1.5;
@line-height-sm: 1.4;
@line-height-xs: 1.3;
@font-weight-light: 300;
@font-weight-normal: 400;
@font-weight-medium: 500;
@font-weight-semibold: 600;
@font-weight-bold: 700;
@font-weight-extrabold: 800;
// ===== 间距变量 =====
@spacing-xs: 4px;
@spacing-sm: 8px;
@spacing-md: 16px;
@spacing-lg: 24px;
@spacing-xl: 32px;
@spacing-xxl: 48px;
@spacing-xxxl: 64px;
@padding-xs: @spacing-xs;
@padding-sm: @spacing-sm;
@padding-md: @spacing-md;
@padding-lg: @spacing-lg;
@padding-xl: @spacing-xl;
@margin-xs: @spacing-xs;
@margin-sm: @spacing-sm;
@margin-md: @spacing-md;
@margin-lg: @spacing-lg;
@margin-xl: @spacing-xl;
// ===== 尺寸变量 =====
@border-radius-base: 4px;
@border-radius-sm: 2px;
@border-radius-lg: 8px;
@border-radius-xl: 12px;
@border-radius-circle: 50%;
@border-width-base: 1px;
@border-width-thick: 2px;
@border-width-thin: 0.5px;
// ===== 阴影变量 =====
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15);
@box-shadow-sm: 0 1px 4px rgba(0, 0, 0, 0.1);
@box-shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.2);
@box-shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.25);
@text-shadow-base: 0 1px 2px rgba(0, 0, 0, 0.1);
@text-shadow-lg: 0 2px 4px rgba(0, 0, 0, 0.2);
// ===== 断点变量 =====
@screen-xs: 480px;
@screen-sm: 576px;
@screen-md: 768px;
@screen-lg: 992px;
@screen-xl: 1200px;
@screen-xxl: 1600px;
@mobile-breakpoint: @screen-md;
@tablet-breakpoint: @screen-lg;
@desktop-breakpoint: @screen-xl;
// 移动端断点变量
@small-mobile: 480px;
@xs-mobile: 360px;
// ===== 动画变量 =====
@animation-duration-base: 0.2s;
@animation-duration-fast: 0.1s;
@animation-duration-slow: 0.3s;
@animation-duration-slower: 0.5s;
@animation-timing-base: ease;
@animation-timing-ease-in: ease-in;
@animation-timing-ease-out: ease-out;
@animation-timing-ease-in-out: ease-in-out;
@animation-timing-linear: linear;
@animation-delay-base: 0s;
@animation-delay-fast: 0.1s;
@animation-delay-slow: 0.3s;
// ===== Z-index 变量 =====
@zindex-dropdown: 1000;
@zindex-sticky: 1020;
@zindex-fixed: 1030;
@zindex-modal-backdrop: 1040;
@zindex-modal: 1050;
@zindex-popover: 1060;
@zindex-tooltip: 1070;
@zindex-toast: 1080;
// ===== 组件特定变量 =====
// 按钮
@btn-height-base: 32px;
@btn-height-lg: 40px;
@btn-height-sm: 24px;
@btn-padding-horizontal-base: @padding-md;
@btn-padding-horizontal-lg: @padding-lg;
@btn-padding-horizontal-sm: @padding-sm;
// 输入框
@input-height-base: 32px;
@input-height-lg: 40px;
@input-height-sm: 24px;
@input-padding-horizontal: @padding-sm;
// 卡片
@card-padding-base: @padding-lg;
@card-padding-sm: @padding-md;
@card-padding-lg: @padding-xl;
// 表格
@table-padding-vertical: @padding-sm;
@table-padding-horizontal: @padding-md;
// 分页
@pagination-item-size: 32px;
@pagination-item-size-sm: 24px;
// 标签
@tag-height: 20px;
@tag-height-lg: 28px;
@tag-height-sm: 16px;
// 徽章
@badge-height: 20px;
@badge-height-sm: 14px;
@badge-height-lg: 24px;
// ===== 工具函数 =====
// 颜色混合函数
.lighten(@color, @amount) {
color: lighten(@color, @amount);
}
.darken(@color, @amount) {
color: darken(@color, @amount);
}
// 透明度函数
.alpha(@color, @opacity) {
color: fade(@color, @opacity);
}
// 响应式混合
.mobile(@rules) {
@media (max-width: @mobile-breakpoint) {
@rules();
}
}
.tablet(@rules) {
@media (min-width: @mobile-breakpoint + 1) and (max-width: @tablet-breakpoint) {
@rules();
}
}
.desktop(@rules) {
@media (min-width: @tablet-breakpoint + 1) {
@rules();
}
}
// 触摸设备检测
.touch-device(@rules) {
@media (hover: none) and (pointer: coarse) {
@rules();
}
}
// 高分辨率屏幕
.high-dpi(@rules) {
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
@rules();
}
}
// 打印样式
.print(@rules) {
@media print {
@rules();
}
}
// 横屏模式
.landscape(@rules) {
@media (orientation: landscape) and (max-height: 500px) {
@rules();
}
}
// 减少动画偏好
.reduced-motion(@rules) {
@media (prefers-reduced-motion: reduce) {
@rules();
}
}

View File

@@ -116,6 +116,7 @@ export default {
mounted() {
this.initHeader()
this.initScrollListener()
this.initMobileMenu()
},
methods: {
// 封装事件监听器创建,提高代码复用性
@@ -197,6 +198,52 @@ export default {
}
}
});
},
// 初始化移动端菜单
initMobileMenu() {
// 汉堡菜单点击事件
this.add_event_listener("hamburger", "click", () => {
this.toggle_class("mobileMenu", "active", true);
}, true);
// 返回按钮点击事件
this.add_event_listener(".linkGoBack", "click", () => {
this.remove_class("mobileMenu", "active", true);
// 关闭移动端菜单后滚动到顶部
window.scrollTo({
top: 0,
left: 0,
behavior: 'smooth'
});
});
// 点击菜单项后自动关闭菜单
const menuLinks = document.querySelectorAll('.headerMobileMenu a');
menuLinks.forEach(link => {
link.addEventListener('click', () => {
this.remove_class("mobileMenu", "active", true);
});
});
// 点击菜单外部区域关闭菜单
document.addEventListener('click', (e) => {
const mobileMenu = document.getElementById('mobileMenu');
const hamburger = document.getElementById('hamburger');
if (mobileMenu && mobileMenu.classList.contains('active') &&
!mobileMenu.contains(e.target) &&
!hamburger.contains(e.target)) {
this.remove_class("mobileMenu", "active", true);
}
});
// ESC键关闭菜单
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
this.remove_class("mobileMenu", "active", true);
}
});
}
}
}

View File

@@ -1,9 +1,13 @@
import './assets/css/cookieconsent.min.css'
import './assets/css/common.css'
import './assets/css/animations.css'
import './assets/css/common.less'
import './assets/css/content_pages.less'
import './assets/css/animations.less'
import './assets/css/mobile_responsive.less'
import './assets/css/common_mobile.less'
import 'swiper/css/swiper.min.css'
import 'es6-promise/auto'
import './static/animation_helper'
import './static/scroll_helper'
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'

250
src/static/scroll_helper.js Normal file
View File

@@ -0,0 +1,250 @@
/**
* 滚动控制助手 - 处理页面刷新和路由切换时的滚动行为
*/
class ScrollHelper {
constructor() {
this.isInitialized = false;
this.init();
}
/**
* 初始化滚动助手
*/
init() {
if (this.isInitialized) return;
// 监听页面加载完成事件
this.handlePageLoad();
// 监听路由变化事件
this.handleRouteChange();
// 监听页面刷新事件
this.handlePageRefresh();
// 监听浏览器前进后退事件
this.handleBrowserNavigation();
this.isInitialized = true;
}
/**
* 处理页面加载完成
*/
handlePageLoad() {
// 页面完全加载后滚动到顶部
if (document.readyState === 'complete') {
this.scrollToTop();
} else {
window.addEventListener('load', () => {
this.scrollToTop();
});
}
// DOM内容加载完成后也滚动到顶部
document.addEventListener('DOMContentLoaded', () => {
this.scrollToTop();
});
}
/**
* 处理路由变化
*/
handleRouteChange() {
// 监听 Vue Router 的全局前置守卫
if (window.Vue && window.Vue.prototype.$router) {
window.Vue.prototype.$router.beforeEach((to, from, next) => {
// 路由切换时滚动到顶部
this.scrollToTop();
next();
});
}
}
/**
* 处理页面刷新
*/
handlePageRefresh() {
// 监听页面即将刷新事件
window.addEventListener('beforeunload', () => {
// 保存当前滚动位置到 sessionStorage
sessionStorage.setItem('scrollPosition', window.pageYOffset);
});
// 页面加载完成后检查是否需要滚动到顶部
window.addEventListener('load', () => {
const savedPosition = sessionStorage.getItem('scrollPosition');
if (savedPosition) {
// 清除保存的位置
sessionStorage.removeItem('scrollPosition');
// 滚动到顶部
this.scrollToTop();
}
});
}
/**
* 处理浏览器前进后退
*/
handleBrowserNavigation() {
// 监听 popstate 事件(浏览器前进后退)
window.addEventListener('popstate', () => {
// 延迟执行,确保路由更新完成
setTimeout(() => {
this.scrollToTop();
}, 100);
});
}
/**
* 滚动到页面顶部
*/
scrollToTop(options = {}) {
const defaultOptions = {
top: 0,
left: 0,
behavior: 'smooth'
};
const config = { ...defaultOptions, ...options };
// 检查浏览器是否支持平滑滚动
if (!this.supportsSmoothScrolling()) {
config.behavior = 'auto';
}
// 执行滚动
window.scrollTo(config);
// 同时滚动 body 和 html 元素(兼容性处理)
if (document.body) {
document.body.scrollTop = 0;
document.body.scrollLeft = 0;
}
if (document.documentElement) {
document.documentElement.scrollTop = 0;
document.documentElement.scrollLeft = 0;
}
}
/**
* 滚动到指定元素
*/
scrollToElement(selector, options = {}) {
const element = document.querySelector(selector);
if (!element) return;
const defaultOptions = {
behavior: 'smooth',
block: 'start',
inline: 'nearest'
};
const config = { ...defaultOptions, ...options };
// 检查浏览器是否支持 scrollIntoView
if (element.scrollIntoView) {
element.scrollIntoView(config);
} else {
// 降级处理:计算元素位置并滚动
const rect = element.getBoundingClientRect();
const scrollTop = window.pageYOffset + rect.top;
this.scrollToTop({ top: scrollTop, behavior: config.behavior });
}
}
/**
* 检查浏览器是否支持平滑滚动
*/
supportsSmoothScrolling() {
return 'scrollBehavior' in document.documentElement.style;
}
/**
* 获取当前滚动位置
*/
getScrollPosition() {
return {
x: window.pageXOffset || document.documentElement.scrollLeft,
y: window.pageYOffset || document.documentElement.scrollTop
};
}
/**
* 设置滚动位置
*/
setScrollPosition(x, y, behavior = 'smooth') {
const options = {
top: y,
left: x,
behavior: this.supportsSmoothScrolling() ? behavior : 'auto'
};
window.scrollTo(options);
}
/**
* 滚动到底部
*/
scrollToBottom(behavior = 'smooth') {
const scrollHeight = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.body.offsetHeight,
document.documentElement.offsetHeight,
document.body.clientHeight,
document.documentElement.clientHeight
);
this.scrollToTop({
top: scrollHeight,
behavior: behavior
});
}
/**
* 滚动到指定百分比位置
*/
scrollToPercentage(percentage, behavior = 'smooth') {
const scrollHeight = Math.max(
document.body.scrollHeight,
document.documentElement.scrollHeight
);
const targetPosition = (scrollHeight - window.innerHeight) * (percentage / 100);
this.scrollToTop({
top: targetPosition,
behavior: behavior
});
}
/**
* 监听滚动事件
*/
onScroll(callback) {
window.addEventListener('scroll', callback, { passive: true });
}
/**
* 移除滚动监听器
*/
offScroll(callback) {
window.removeEventListener('scroll', callback);
}
/**
* 销毁滚动助手
*/
destroy() {
// 清理事件监听器
this.isInitialized = false;
}
}
// 创建全局实例
window.scrollHelper = new ScrollHelper();
// 导出类(如果使用模块系统)
if (typeof module !== 'undefined' && module.exports) {
module.exports = ScrollHelper;
}

View File

@@ -7,13 +7,27 @@
<!-- 现代化横幅区域 -->
<div class="banner" data-parallax="0.3">
<!-- 浮动粒子背景 -->
<div class="floating-particles">
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
<div class="floating-particle"></div>
</div>
<swiper ref="swiper" :options="swiperOption">
<swiper-slide v-for="banner in banners" :key="banner.img">
<div class="banner-content">
<img :src="banner.img" width="100%" />
<div class="banner-overlay">
<div class="banner-text">
<h1 class="banner-title animate fade-in-down">{{banner.title}}</h1>
<h1 class="banner-title animate fade-in-down text-glow">{{banner.title}}</h1>
<p class="banner-subtitle animate fade-in-up delay-1s">{{banner.subtitle}}</p>
</div>
</div>

View File

@@ -88,6 +88,27 @@ module.exports = {
})
]
}
},
// LESS 配置
less: {
lessOptions: {
javascriptEnabled: true,
modifyVars: {
// 可以在这里定义全局LESS变量
'@primary-color': '#3498db',
'@success-color': '#52c41a',
'@warning-color': '#faad14',
'@error-color': '#f5222d',
'@font-size-base': '14px',
'@heading-color': '#262626',
'@text-color': '#595959',
'@text-color-secondary': '#8c8c8c',
'@disabled-color': '#bfbfbf',
'@border-radius-base': '4px',
'@border-color-base': '#d9d9d9',
'@box-shadow-base': '0 2px 8px rgba(0, 0, 0, 0.15)'
}
}
}
}
},

View File

@@ -795,7 +795,7 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/json-schema@^7.0.5":
"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8":
version "7.0.15"
resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
@@ -1254,7 +1254,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
resolved "https://registry.npmmirror.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
version "6.12.6"
resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -2495,6 +2495,13 @@ cookie@0.7.1:
resolved "https://registry.npmmirror.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
copy-anything@^2.0.1:
version "2.0.6"
resolved "https://registry.npmmirror.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
dependencies:
is-what "^3.14.1"
copy-concurrently@^1.0.0:
version "1.0.5"
resolved "https://registry.npmmirror.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
@@ -3381,7 +3388,7 @@ entities@^2.0.0:
resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
errno@^0.1.3, errno@~0.1.7:
errno@^0.1.1, errno@^0.1.3, errno@~0.1.7:
version "0.1.8"
resolved "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
@@ -4754,6 +4761,13 @@ iconv-lite@0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
@@ -4791,6 +4805,11 @@ ignore@^5.1.1:
resolved "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
image-size@~0.5.0:
version "0.5.5"
resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
image-webpack-loader@^8.1.0:
version "8.1.0"
resolved "https://registry.npmmirror.com/image-webpack-loader/-/image-webpack-loader-8.1.0.tgz#cd97172e1e7304ef5eb898344fc25bbb650fc7d7"
@@ -5415,6 +5434,11 @@ is-weakset@^2.0.3:
call-bound "^1.0.3"
get-intrinsic "^1.2.6"
is-what@^3.14.1:
version "3.14.1"
resolved "https://registry.npmmirror.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -5627,6 +5651,11 @@ kind-of@^6.0.2:
resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
klona@^2.0.4:
version "2.0.6"
resolved "https://registry.npmmirror.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==
launch-editor-middleware@^2.2.1:
version "2.11.1"
resolved "https://registry.npmmirror.com/launch-editor-middleware/-/launch-editor-middleware-2.11.1.tgz#8042f841b7f6cf2d7aafd5e0824e49ab356a5bb1"
@@ -5642,6 +5671,32 @@ launch-editor@^2.11.1, launch-editor@^2.2.1:
picocolors "^1.1.1"
shell-quote "^1.8.3"
less-loader@7.3.0:
version "7.3.0"
resolved "https://registry.npmmirror.com/less-loader/-/less-loader-7.3.0.tgz#f9d6d36d18739d642067a05fb5bd70c8c61317e5"
integrity sha512-Mi8915g7NMaLlgi77mgTTQvK022xKRQBIVDSyfl3ErTuBhmZBQab0mjeJjNNqGbdR+qrfTleKXqbGI4uEFavxg==
dependencies:
klona "^2.0.4"
loader-utils "^2.0.0"
schema-utils "^3.0.0"
less@^4.4.1:
version "4.4.1"
resolved "https://registry.npmmirror.com/less/-/less-4.4.1.tgz#2f97168bf887ca6a9957ee69e16cc34f8b007cc7"
integrity sha512-X9HKyiXPi0f/ed0XhgUlBeFfxrlDP3xR4M7768Zl+WXLUViuL9AOPPJP4nCV0tgRWvTYvpNmN0SFhZOQzy16PA==
dependencies:
copy-anything "^2.0.1"
parse-node-version "^1.0.1"
tslib "^2.3.0"
optionalDependencies:
errno "^0.1.1"
graceful-fs "^4.1.2"
image-size "~0.5.0"
make-dir "^2.1.0"
mime "^1.4.1"
needle "^3.1.0"
source-map "~0.6.0"
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -5799,7 +5854,7 @@ make-dir@^1.0.0, make-dir@^1.2.0:
dependencies:
pify "^3.0.0"
make-dir@^2.0.0:
make-dir@^2.0.0, make-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
@@ -5950,7 +6005,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24,
dependencies:
mime-db "1.52.0"
mime@1.6.0:
mime@1.6.0, mime@^1.4.1:
version "1.6.0"
resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@@ -6140,6 +6195,14 @@ nanomatch@^1.2.9:
snapdragon "^0.8.1"
to-regex "^3.0.1"
needle@^3.1.0:
version "3.3.1"
resolved "https://registry.npmmirror.com/needle/-/needle-3.3.1.tgz#63f75aec580c2e77e209f3f324e2cdf3d29bd049"
integrity sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==
dependencies:
iconv-lite "^0.6.3"
sax "^1.2.4"
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
@@ -6676,6 +6739,11 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
parse-node-version@^1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
parse5-htmlparser2-tree-adapter@^6.0.0:
version "6.0.1"
resolved "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
@@ -7802,11 +7870,16 @@ safe-regex@^1.1.0:
dependencies:
ret "~0.1.10"
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sax@^1.2.4:
version "1.4.1"
resolved "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
sax@~1.2.4:
version "1.2.4"
resolved "https://registry.npmmirror.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -7830,6 +7903,15 @@ schema-utils@^2.6.5, schema-utils@^2.7.1:
ajv "^6.12.4"
ajv-keywords "^3.5.2"
schema-utils@^3.0.0:
version "3.3.0"
resolved "https://registry.npmmirror.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
dependencies:
"@types/json-schema" "^7.0.8"
ajv "^6.12.5"
ajv-keywords "^3.5.2"
seek-bzip@^1.0.5:
version "1.0.6"
resolved "https://registry.npmmirror.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4"
@@ -8801,6 +8883,11 @@ tryer@^1.0.1:
resolved "https://registry.npmmirror.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
tslib@^2.3.0:
version "2.8.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"