Vue中如何在:style中获取当前DOM元素实现hover变换效果
问题解决:循环组件中实现鼠标悬停的transform变换
需求是给循环生成的每个作品缩略图(图片/视频)添加鼠标悬停时的3D旋转效果,通过VueUse的useMouseInElement计算变换值,但原代码存在共用状态、元素绑定错误的问题,导致效果无法正常生效。
修改思路
- 每个组件独立维护状态:原代码中所有组件共用同一个
currentWork变量,导致悬停一个元素会影响所有组件,改为每个组件用ref绑定自己的根元素,独立使用useMouseInElement实例。 - 直接绑定目标元素:通过
ref获取当前组件的根div,传给useMouseInElement,无需通过mouseover事件手动设置目标元素,避免事件绑定和状态同步的问题。 - 简化样式绑定:
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
相关产品推荐
相关产品推荐

