You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue中如何在:style中获取当前DOM元素实现hover变换效果

问题解决:循环组件中实现鼠标悬停的transform变换

需求是给循环生成的每个作品缩略图(图片/视频)添加鼠标悬停时的3D旋转效果,通过VueUse的useMouseInElement计算变换值,但原代码存在共用状态、元素绑定错误的问题,导致效果无法正常生效。

修改思路

  1. 每个组件独立维护状态:原代码中所有组件共用同一个currentWork变量,导致悬停一个元素会影响所有组件,改为每个组件用ref绑定自己的根元素,独立使用useMouseInElement实例。
  2. 直接绑定目标元素:通过ref获取当前组件的根div,传给useMouseInElement,无需通过mouseover事件手动设置目标元素,避免事件绑定和状态同步的问题。
  3. 简化样式绑定:cardTransform计算属性会自动根据鼠标是否在元素内返回对应的变换值,直接绑定到transform样式即可。

修改后的WorkThumbnail.vue代码

<template>
  <!-- 图片类型缩略图 -->
  <div
    v-if="work.video === false"
    class="work_thumbnail"
    ref="targetRef"
    :style="{
      backgroundImage: `url(${require(`@/assets/img/works/${work.thumbnail}.jpg`)})`,
      transition: 'transform 0.25s ease-out',
      transform: cardTransform
    }"
  >
    <div class="WorkHeadline">{{ work.name }}</div>
  </div>

  <!-- 视频类型缩略图 -->
  <div
    v-if="work.video === true"
    class="work_thumbnail"
    ref="targetRef"
    @click="showWork(work)"
    :style="{
      transition: 'transform 0.25s ease-out',
      transform: cardTransform
    }"
  >
    <div class="WorkHeadline">{{ work.name }}</div>
    <video :poster="require(`@/assets/img/works/${work.vidPreview}.jpg`)" autoplay loop>
      <source
        :src="require(`@/assets/img/works/${work.thumbnail}.mp4`)"
        type="video/mp4"
      >
    </video>
  </div>
</template>

<script>
import { useMouseInElement } from '@vueuse/core'
import { computed, ref } from 'vue'

export default {
  props: {
    work: {
      type: Object,
      required: true
    },
    index: {
      type: Number,
      required: true
    }
  },
  methods: {
    showWork(work) {
      if (work.direct === true) {
        window.open(work.link, '_blank').focus();
      }
    }
  },
  setup() {
    // 每个组件独立维护自己的目标元素ref
    const targetRef = ref(null)

    // 绑定当前组件的目标元素
    const {
      elementX,
      elementY,
      elementHeight,
      elementWidth,
      isOutside
    } = useMouseInElement(targetRef)

    // 计算当前元素的transform值
    const cardTransform = computed(() => {
      const Max_Rotation = 40

      if (isOutside.value || !elementHeight.value || !elementWidth.value) {
        return ''
      }

      const rX = (Max_Rotation / 2 - (elementY.value / elementHeight.value) * Max_Rotation).toFixed(2)
      const rY = ((elementX.value / elementWidth.value) * Max_Rotation - Max_Rotation / 2).toFixed(2)

      return `perspective(${elementWidth.value}px) rotateX(${rX}deg) rotateY(${rY}deg)`
    })

    return {
      targetRef,
      cardTransform
    }
  }
}
</script>

父组件(Explore.vue)无需修改

原父组件的循环逻辑保持不变,每个WorkThumbnail组件现在会独立处理自己的鼠标悬停状态和变换效果。

关键修改点说明

  • 移除了全局的currentWork变量,改用组件内的targetRef绑定当前元素,确保每个组件状态独立。
  • useMouseInElement直接绑定到targetRef,自动监听鼠标在当前元素内的位置和进出状态,无需手动处理mouseover事件。
  • 优化了cardTransform的判断逻辑,避免元素尺寸未加载时出现计算错误。
  • 简化了样式绑定,直接将cardTransform赋值给transform样式,无需额外的条件判断。

内容的提问来源于stack exchange,提问作者Marcus Harting

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 15:50:50