《fun-widgets:简单却有趣的触点交互(TouchCard)》

Hi guys, 最近在用豆包的时候发现一个有意思的交互应用,下面我们一起来看下怎么实现

样例

为了更好得展示最终效果,直接使用豆包的界面作为样例

UI上可以看出:

  • 光标进入时PersonInfo模块会出现"下陷"效果
  • "下陷"效果延后触发
  • 右侧Memojis"悬浮"效果

分解开始

一、"下陷"效果复刻

通过肉眼观看,当光标移入时,整个卡片会出现下陷,这是一种视觉欺骗。

我们可以通过mousemove和csstransformrotateX&rotateY属性可以达到此效果。 逻辑通了,那就开始吧。

  • 使用vue&tailwindcss快速搭建一个组件。给予属性@mousemove函数handleMouseMove
HTML 复制代码
<template>
  <div
    class="w-screen h-screen flex justify-center items-center bg-neutral-200"
  >
    <div
        id="card"
      class="w-1/2 h-60 relative z-1 flex items-center"
    >
      <div
        ref="touchCardRef"
        class="w-full h-full backdrop-blur-[.58594rem] rounded-2xl border-1 border-white shadow-lg shadow-gray-400 flex flex-col justify-center card"
        @mousemove="handleMouseMove"
      >
        <div class="ml-20 text-4xl text-[#141413] font-bold">@小王饿了</div>
        <div class="ml-20 mt-6 text-xl text-sky-500 font-bold">
          #fun-widgets/TouchCard
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.card {
  backdrop-filter: blur(0.58594rem);
  background: linear-gradient(
    113deg,
    hsla(0, 0%, 100%, 0.72) 10.29%,
    hsla(0, 0%, 100%, 0) 100.35%
  );
}
</style>
  • handleMouseMoveFn
    @mousemove会返回一个MouseEvent类型(点击查看内容)。此类型有诸多关于光标在浏览器内坐标的参数,我们取光标在touchCardRef内的参数offsetX&offsetY 使用@vueuse/core/useElementSize函数获取touchCardRef节点的宽高,得到一个
    {x:[-width/2, width/2],y:[-height/2, height/2]}的坐标体
    由此可以推断:

    • 当光标所处区域为正y时,卡片向上倾斜,rotateX为正角,反之rotateX为负角

    • 当光标所处区域为正x时,卡片向右倾斜,rotateY为负角,反之rotateY为正角

    rotateXrotateY属性可以控制元素倾角

注意1: 最终为3d效果,添加transform-3d属性让transform支持此效果。

注意2: 在操控倾斜时倾斜会被视距所影响,perspective属性可以替我们解决这个问题。将视距设置为2000px,避免畸变。

CSS 属性 perspective 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定。

观察原型发现倾斜极值为[-6,6]。接下来就是一道简单的数学题:x与width如何得到[-6,6]区间值?

逻辑很简单:

  1. w/2为原点
  2. <math xmlns="http://www.w3.org/1998/Math/MathML"> x − w / 2 x-w/2 </math>x−w/2得到所处正负极
  3. <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x − w / 2 ) / ( w / 2 ) (x-w/2)/(w/2) </math>(x−w/2)/(w/2)得到所处坐标比例
  4. <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x − w / 2 ) / ( w / 2 ) ∗ 6 (x-w/2)/(w/2)*6 </math>(x−w/2)/(w/2)∗6得到[-6,6]区间
  5. 简化下公式就是 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( ( x / w / 2 ) − 1 ) ∗ 6 ((x/w/2)-1)*6 </math>((x/w/2)−1)∗6
js 复制代码
const touchTransform = (x: number, y: number): void => {
  const rotateX = -(y / (height.value / 2) - 1) * 6;
  const rotateY = (x / (width.value / 2) - 1) * 6;
  transform.value = `perspective(2000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
};

到此,"下陷"效果的最后一块拼图完成了。看下整体代码:

js 复制代码
<script lang="ts" setup>
import { ref } from "vue";
import { useElementSize } from "@vueuse/core";

const transform = ref<string>("");
const touchCardRef = ref<HTMLElement>();
const { width, height } = useElementSize(touchCardRef);

const touchTransform = (x: number, y: number): void => {
  const rotateX = -(y / (height.value / 2) - 1) * 10;
  const rotateY = (x / (width.value / 2) - 1) * 10;
  transform.value = `perspective(2000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
};

const handleMouseMove = (event: MouseEvent) => {
  const { offsetX: x, offsetX: y } = event;
  touchTransform(x, y);
};
</script>
<template>
  <div
    class="w-screen h-screen flex justify-center items-center bg-neutral-200"
  >
    <div
      class="w-1/2 h-60 relative z-1 flex items-center transform-3d"
      :style="{ transform }"
    >
      <div
        ref="touchCardRef"
        class="w-full h-full backdrop-blur-[.58594rem] rounded-2xl border-1 border-white shadow-lg shadow-gray-400 flex flex-col justify-center card"
        @mousemove="handleMouseMove"
      >
        <div class="ml-20 text-4xl text-[#141413] font-bold">@小王饿了</div>
        <div class="ml-20 mt-6 text-xl text-sky-500 font-bold">
          #fun-widgets/TouchCard
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.card {
  backdrop-filter: blur(0.58594rem);
  background: linear-gradient(
    113deg,
    hsla(0, 0%, 100%, 0.72) 10.29%,
    hsla(0, 0%, 100%, 0) 100.35%
  );
}
</style>

二、"下陷"效果延后触发

接着处理"下陷"效果的延后触发,这块很简单,添加transition属性就行。

css 复制代码
transition: transform 0.15s linear;

三、右侧Memojis"悬浮"效果

translate中有3个属性可以让节点偏移

  • transform: translateX(2em)
  • transform: translateY(3in)
  • transform: translateZ(2px)

想要实现浮于上层的效果,这里选择translateZ。借鉴写tailwind的图片,设置对应的参数可以让图片悬于上方。

  • 增加图片,添加translate-z-12属性,进化至完全体 。(BGM:Butterfly)
js 复制代码
<template>
  <div
    class="w-screen h-screen flex justify-center items-center bg-neutral-200"
  >
    <div
      class="w-1/2 h-60 relative z-1 transform-3d transition-transform flex items-center"
      :style="{ transform }"
    >
      <div
        ref="touchCardRef"
        class="w-full h-full backdrop-blur-[.58594rem] rounded-2xl border-1 border-white shadow-lg shadow-gray-400 flex flex-col justify-center card"
        @mousemove="handleMouseMove"
        @mouseout="handleMouseOut"
      >
        <div class="ml-20 text-4xl text-[#141413] font-bold">@小王饿了</div>
        <div class="ml-20 mt-6 text-xl text-sky-500 font-bold">
          #fun-widgets/TouchCard
        </div>
      </div>
      <img
        class="absolute pointer-events-none translate-z-12 w-1/4 -right-1/8 rounded-full border-1 border-white"
        src="https://p3-flow-imagex-sign.byteimg.com/user-avatar/f9e7748c4fea045de8a774d0836ad177~tplv-a9rns2rl98-image.jpeg?rk3s=98c978ad&x-expires=1743502443&x-signature=YLBy9quP5%2B3%2BsPEza3K4SfeRfNg%3D"
      />
    </div>
  </div>
</template>

题外话

  1. 欢迎分享更多有趣交互
  2. 动图制作by:kapwing
  3. 源码已传至Github:github.com/WZJvearyfun...

我是小王饿了 。一个前端开发,曾任职500强车企前端负责人、新零售互联网、事业单位。

好捣鼓点东西吃,有点手艺。爱看小说,爱旅游,人生不受限。

29岁的人和19岁的人其实没差别,除了体重...

相关推荐
LuckyLay24 分钟前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf30 分钟前
典籍知识问答重新生成和消息修改Bug修改
前端·bug
hj104331 分钟前
【fastadmin开发实战】在前端页面中使用bootstraptable以及表格中实现文件上传
前端
乌夷40 分钟前
axios结合AbortController取消文件上传
开发语言·前端·javascript
晓晓莺歌1 小时前
图片的require问题
前端
码农黛兮_462 小时前
CSS3 基础知识、原理及与CSS的区别
前端·css·css3
水银嘻嘻2 小时前
web 自动化之 Unittest 四大组件
运维·前端·自动化
(((φ(◎ロ◎;)φ)))牵丝戏安2 小时前
根据输入的数据渲染柱形图
前端·css·css3·js
wuyijysx2 小时前
JavaScript grammar
前端·javascript
溪饱鱼3 小时前
第6章: SEO与交互指标
服务器·前端·microsoft