Browse Source

feat(home): 为浮动图表添加漂浮动画效果

在首页的浮动图表中,新增了漂浮动画效果,使其在页面中随机移动。当鼠标悬停时,动画暂停,移开后继续。同时优化了图表的样式和交互体验。
hpAlivsliu 3 months ago
parent
commit
07d4c03668
1 changed files with 106 additions and 45 deletions
  1. 106 45
      src/pages/home/index.vue

+ 106 - 45
src/pages/home/index.vue

@@ -5,11 +5,15 @@
          :style="{'background': 'url('+curMenu.img+') top no-repeat','background-size': 'cover'}"></div>
          :style="{'background': 'url('+curMenu.img+') top no-repeat','background-size': 'cover'}"></div>
 
 
   <!-- 新增浮动图表 -->
   <!-- 新增浮动图表 -->
-  <div class="fixed-chart" @click="toAi">
+  <div class="fixed-chart" 
+       @click="toAi"
+       @mouseenter="isHovering = true"
+       @mouseleave="isHovering = false">
     <div class="chart-content">
     <div class="chart-content">
-      <img src="/images/home/fixedAi.png"  alt="动态图表">
+      <img src="/images/home/fixedAi.png" alt="动态图表">
     </div>
     </div>
   </div>
   </div>
+  
 </div>
 </div>
   <div class="content-bg pt10 pb80">
   <div class="content-bg pt10 pb80">
     <div class="main pt50">
     <div class="main pt50">
@@ -189,11 +193,12 @@ export default {
       }],
       }],
       isTeacher:false,
       isTeacher:false,
       zpList:[],
       zpList:[],
-      // 新增拖拽相关数据
-      dragPosition: { x: 200, y: 300 }, // 初始位置
-      dragging: false,
-      startX: 0,
-      startY: 0
+      // 新增漂浮动画相关数据
+      floatPosition: { x: 0, y: 0 },  // 漂浮位置偏移量
+      floatVelocity: { x: 1, y: 1 },  // 漂浮速度
+      isHovering: false,              // 是否鼠标悬停
+      animationFrameId: null,         // 动画帧ID
+    
     }
     }
 
 
   },
   },
@@ -359,67 +364,123 @@ export default {
         this.liveData[1].bgImg = bgImg2;
         this.liveData[1].bgImg = bgImg2;
       }
       }
     },
     },
-    // 新增拖拽方法
-    startDrag(e) {
-      this.dragging = true
-      const clientX = e.clientX || e.touches[0].clientX
-      const clientY = e.clientY || e.touches[0].clientY
+    // 漂浮动画方法
+    startFloating() {
+      const floatElement = document.querySelector('.fixed-chart');
       
       
-      this.startX = clientX - this.dragPosition.x
-      this.startY = clientY - this.dragPosition.y
+      // 初始化位置为元素当前位置
+      const initialRect = floatElement.getBoundingClientRect();
+      this.floatPosition = { 
+        x: initialRect.left, 
+        y: initialRect.top 
+      };
       
       
-      document.addEventListener('mousemove', this.onDrag)
-      document.addEventListener('touchmove', this.onDrag)
-      document.addEventListener('mouseup', this.stopDrag)
-      document.addEventListener('touchend', this.stopDrag)
-    },
-    onDrag(e) {
-      if (!this.dragging) return
-      const clientX = e.clientX || e.touches[0].clientX
-      const clientY = e.clientY || e.touches[0].clientY
+      const updatePosition = () => {
+        if (!this.isHovering && !this.dragging) {
+          // 获取窗口尺寸和元素尺寸
+          const windowWidth = window.innerWidth;
+          const windowHeight = window.innerHeight;
+          const elementRect = floatElement.getBoundingClientRect();
+          
+          // 更新位置
+          this.floatPosition.x += this.floatVelocity.x;
+          this.floatPosition.y += this.floatVelocity.y;
+          
+          // 检测边界碰撞并反弹 - 修正边界检测逻辑
+          if (this.floatPosition.x <= 0 || this.floatPosition.x >= windowWidth - elementRect.width) {
+            this.floatVelocity.x = -this.floatVelocity.x;
+            // 确保不会卡在边界
+            if (this.floatPosition.x <= 0) {
+              this.floatPosition.x = 1;
+            } else {
+              this.floatPosition.x = windowWidth - elementRect.width - 1;
+            }
+            // 添加一点随机性使运动更自然
+            this.floatVelocity.x += (Math.random() - 0.5) * 0.2;
+          }
+          
+          if (this.floatPosition.y <= 0 || this.floatPosition.y >= windowHeight - elementRect.height) {
+            this.floatVelocity.y = -this.floatVelocity.y;
+            // 确保不会卡在边界
+            if (this.floatPosition.y <= 0) {
+              this.floatPosition.y = 1;
+            } else {
+              this.floatPosition.y = windowHeight - elementRect.height - 1;
+            }
+            // 添加一点随机性使运动更自然
+            this.floatVelocity.y += (Math.random() - 0.5) * 0.2;
+          }
+          
+          // 控制速度在合理范围内
+          this.floatVelocity.x = Math.max(-1.5, Math.min(1.5, this.floatVelocity.x));
+          this.floatVelocity.y = Math.max(-1.5, Math.min(1.5, this.floatVelocity.y));
+          
+          // 应用位置 - 使用绝对定位而不是transform
+          floatElement.style.left = `${this.floatPosition.x}px`;
+          floatElement.style.top = `${this.floatPosition.y}px`;
+          floatElement.style.bottom = 'auto';
+          floatElement.style.right = 'auto';
+        }
+        
+        this.animationFrameId = requestAnimationFrame(updatePosition);
+      };
       
       
-      this.dragPosition.x = clientX - this.startX
-      this.dragPosition.y = clientY - this.startY
-      e.preventDefault()
-    },
-    stopDrag() {
-      this.dragging = false
-      document.removeEventListener('mousemove', this.onDrag)
-      document.removeEventListener('touchmove', this.onDrag)
+      // 设置初始样式
+      floatElement.style.transition = 'left 0.05s linear, top 0.05s linear';
+      
+      updatePosition();
     },
     },
     
     
+    stopFloating() {
+      if (this.animationFrameId) {
+        cancelAnimationFrame(this.animationFrameId);
+        this.animationFrameId = null;
+      }
+    }
+    
   },
   },
   mounted() {
   mounted() {
     this.initZpData(1);
     this.initZpData(1);
+     // 启动漂浮动画
+     this.startFloating();
+  },
+  beforeUnmount() {
+    // 清理动画
+    this.stopFloating();
   },
   },
- 
 }
 }
 </script>
 </script>
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 @import "@/styles/mixin.scss";
 @import "@/styles/mixin.scss";
 </style>
 </style>
 <style lang="scss" scoped>
 <style lang="scss" scoped>
-// ::v-deep .el-carousel__mask{
-//   opacity: 0!important;
-// }
 :deep(.el-carousel__mask){
 :deep(.el-carousel__mask){
   opacity: 0!important;
   opacity: 0!important;
 }
 }
 .fixed-chart {
 .fixed-chart {
-  position: fixed;
-  bottom: 10%;
-  right: 4%;
+  position: fixed; /* 保持fixed定位,但位置将由JS控制 */
+  bottom: auto; /* 初始值,会被JS覆盖 */
+  right: auto; /* 初始值,会被JS覆盖 */
   z-index: 1000;
   z-index: 1000;
-  width: 250px !important;  // 改为固定宽度
-  text-align: right;         // 新增文本右对齐
-  cursor: move; // 添加拖拽光标
-  user-select: none; // 防止选中文本
-  touch-action: none; // 禁用默认触控行为
+  width: 200px !important;
+  text-align: left;
+  cursor: pointer;
+  user-select: none;
+  touch-action: none;
+  transition: left 0.05s linear, top 0.05s linear; /* 修改过渡效果 */
   
   
   .chart-content {
   .chart-content {
-    width: 40% !important;  // 改为100%宽度
-    margin-left: auto;        // 新增右对齐关键属性
+    margin-left: auto;
     cursor: pointer;
     cursor: pointer;
+    
+    img {
+      width: 100%;
+      height: auto;
+    }
+  }
+  
+  &:hover {
+    transition-duration: 0.2s; /* 悬停时过渡效果更明显 */
   }
   }
 }
 }
 .main {
 .main {