Vue3实战:纯CSS+JS实现高级透视效果

0 阅读6分钟

近日浏览小米MiMo官网时,被其顶部的透视跟随动画深深吸引——鼠标移动时,文字矩阵伴随遮罩动态变化,营造出极强的视觉层次感和交互趣味性。出于技术探索目的,我基于Vue3复刻了这一效果,下文将从组件结构、核心算法、性能优化三方面,拆解完整实现逻辑,助力大家快速落地到项目中。

效果演示

效果图.gif

1. 功能概述

本组件是一款聚焦视觉交互的顶部区组件,核心实现「鼠标透视跟随」效果:通过双层文字矩阵叠加+动态CSS遮罩,让上层内容随鼠标轨迹弹性形变,模拟现实中的透视景深,打破传统静态标题的沉闷感。

2. 组件结构与DOM设计

2.1 模板结构

采用「静态底层+动态上层」的双层视觉结构,通过CSS绝对定位实现图层叠加,既保证初始状态的视觉完整性,又能让交互效果精准作用于上层,不干扰底层基础展示。两层分工明确,具体如下:

图层类名内容功能
底层.z-1中文标题 "你好,世界!" 和灰色 "HELLO" 文字矩阵静态背景展示
上层.z-2英文标题 "Hello , World!" 和白色 "HELLO" 文字矩阵鼠标交互时的动态效果层

2.2 核心 DOM 结构

<div class="container" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave" @mousemove="onMouseMove">
  <!-- 底层内容 -->
  <div class="z-1">
    <div class="line" v-for="line in 13">
      <span class="line-item" v-for="item in 13">HELLO</span>
    </div>
  </div>
  <h1 class="title-1">你好,世界!</h1>
  
  <!-- 上层交互内容 -->
  <div class="z-2" :style="{ 'clip-path': circleClipPath }">
    <div class="hidden-div">
      <div class="line" v-for="line in 13">
        <span class="line-item" v-for="item in 13">HELLO</span>
      </div>
    </div>
    <h1 class="title-2">Hello , World!</h1>
  </div>
</div>

关键说明:hidden-div用于包裹上层文字矩阵,配合.z-2的定位规则,确保遮罩效果精准覆盖;两层文字矩阵尺寸一致,保证视觉对齐,增强透视沉浸感。

3. 技术实现

3.1 核心功能模块

3.1.1 轨迹点系统

轨迹点系统是实现平滑鼠标跟随效果的核心,通过维护6个轨迹点的位置信息,创建出具有弹性延迟的跟随动画。

// 轨迹点系统 
const trailSystem = ref({
  targetX: 0,
  targetY: 0,
  trailPoints: Array(6).fill(null).map(() => ({ x: 0, y: 0 })),
  animationId: 0,
  isInside: false
});

设计思路:6个轨迹点是兼顾流畅度与性能的平衡值——点太少则拖尾效果不明显,点太多则增加计算开销,配合递减阻尼系数,实现“头快尾慢”的自然跟随。

3.1.2 动态 Clip-Path 计算

通过计算鼠标位置和轨迹点的关系,动态生成 clip-path CSS 属性值,实现跟随鼠标的圆形/椭圆形遮罩效果。

// 计算clip-path值,使用参考算法实现弹性动画
const circleClipPath = computed(() => {
  if (!showCircle.value) {
    return 'circle(0px at -300px -300px)'; // 完全隐藏状态
  }

  // 复制轨迹系统数据进行计算
  const system = JSON.parse(JSON.stringify(trailSystem.value));
  
  // 更新轨迹点
  for (let t = 0; t < 6; t++) {
    const prevX = t === 0 ? system.targetX : system.trailPoints[t - 1].x;
    const prevY = t === 0 ? system.targetY : system.trailPoints[t - 1].y;
    const damping = 0.7 - 0.04 * t; // 阻尼系数,后面的点移动更慢
    
    const deltaX = prevX - system.trailPoints[t].x;
    const deltaY = prevY - system.trailPoints[t].y;
    
    // 平滑插值
    system.trailPoints[t].x += deltaX * damping;
    system.trailPoints[t].y += deltaY * damping;
  }
  
  // 获取第一个点(头部)和最后一个点(尾部)
  const head = system.trailPoints[0];
  const tail = system.trailPoints[5];
  
  const diffX = head.x - tail.x;
  const diffY = head.y - tail.y;
  const distance = Math.sqrt(diffX * diffX + diffY * diffY);
  
  let clipPathValue = '';
  
  if (distance < 10) { // 如果距离很近,显示圆形
    clipPathValue = `circle(200px at ${head.x}px ${head.y}px)`;
  } else {
    // 创建椭圆形的polygon,连接头尾两点
    const angle = Math.atan2(diffY, diffX); // 连接角度
    const points = [];
    
    // 从头部开始,画半个椭圆
    for (let i = 0; i <= 30; i++) {
      const theta = angle - Math.PI / 2 + Math.PI * i / 30;
      const x = head.x + 200 * Math.cos(theta);
      const y = head.y + 200 * Math.sin(theta);
      points.push(`${x}px ${y}px`);
    }
    
    // 从尾部开始,画另半个椭圆
    for (let i = 0; i <= 30; i++) {
      const theta = angle + Math.PI / 2 + Math.PI * i / 30;
      const x = tail.x + 200 * Math.cos(theta);
      const y = tail.y + 200 * Math.sin(theta);
      points.push(`${x}px ${y}px`);
    }
    
    clipPathValue = `polygon(${points.join(', ')})`;
  }
  
  return clipPathValue;
});

3.1.3 鼠标事件处理

实现了完整的鼠标交互逻辑,包括鼠标进入、离开和移动时的状态管理和动画控制。

事件处理函数功能
mouseenteronMouseEnter激活交互效果,初始化轨迹点
mouseleaveonMouseLeave停用交互效果,重置轨迹点
mousemoveonMouseMove更新目标点位置,驱动动画

4. 技术亮点

4.1 轨迹点系统算法

核心原理:使用6个轨迹点,每个点跟随前一个点移动,并应用不同的阻尼系数,实现平滑的拖尾效果。

技术优势

  • 实现了自然的物理运动效果,比简单的线性跟随更具视觉吸引力
  • 通过阻尼系数的递减,创建出层次感和深度感
  • 算法复杂度低,性能消耗小,适合实时交互场景

4.2 动态 Clip-Path 技术

核心原理:利用CSS clip-path属性的动态特性,结合轨迹点位置计算,实时生成不规则遮罩,替代Canvas/SVG的图形绘制方案,用更轻量化的方式实现复杂视觉效果。

技术优势

  • 无依赖轻量化:无需引入任何图形库,纯CSS+JS即可实现,减少项目依赖体积,降低集成成本
  • 平滑过渡无卡顿:通过数值插值计算,实现圆形与椭圆形遮罩的无缝切换,无帧断裂感,视觉连贯性强
  • 渲染性能优化:配合 will-change: clip-path 提示浏览器,提前分配渲染资源,减少重排重绘,提升动画流畅度

5. 性能优化

  1. 渲染性能

    • 使用 will-change: clip-path 提示浏览器优化渲染
    • 合理使用 Vue 的响应式系统,避免不必要的重计算
  2. 事件处理

    • 仅在鼠标在容器内时更新目标点位置,减少计算量
    • 鼠标离开时停止动画,释放资源
  3. 动画性能

    • 使用 requestAnimationFrame 实现流畅的动画效果
    • 鼠标离开时取消动画帧请求,避免内存泄漏

6. 总结与扩展

本次复刻的小米MiMo透视动画,核心价值在于“用简单技术组合实现高级视觉效果”——无需复杂图形库,仅依托Vue3响应式能力与CSS clip-path属性,就能打造出兼具质感与性能的交互组件。其核心亮点可概括为三点:

  • 交互创新:轨迹点系统与动态clip-path结合,打破传统静态标题的交互边界,带来自然流畅的鼠标跟随体验
  • 视觉精致:双层文字矩阵的分层设计,配合遮罩形变,营造出兼具深度感与品牌性的视觉效果
  • 性能可控:轻量化技术方案+多维度优化策略,在保证视觉效果的同时,兼顾页面性能与可维护性

扩展方向

该组件的实现思路可灵活迁移至其他场景:

  • 弹窗过渡动画:将clip-path遮罩用于弹窗进入/退出效果,实现不规则形状的过渡动画。
  • 滚动动效:结合滚动事件替换鼠标事件,实现页面滚动时的元素透视跟随效果。
  • 移动端适配:增加触摸事件支持,将鼠标交互替换为触摸滑动,适配移动端场景。

欢迎大家留言交流更多优化思路~