Marcus Harting
Marcus Harting

Reputation: 75

Vue getting current dom element in style

I want to add a transform effect on only the hovered video or image. This effect is computed and can't be in a vue method but I can maybe change the target element for the useMouseInElement(). The WorkThumbnail.vue component is in a v-for loop and loads multiple videos/images.

How I can access in the :style the current DOM Element? $event is not the solution 😅

WorkThumbnail.vue

<template>
<div
    v-if="work.video === false"
    class="work_thumbnail"
    :style="{
    backgroundImage: 'url(' + require(`@/assets/img/works/${work.thumbnail}.jpg`) + ')',
    transition: 'transform 0.25s ease-out', transform: [currentWork === selectWork($event) ? { cardTransform } :  '']}"
    @mouseover="selectWork($event)"
    >
    <div class="WorkHeadline">{{work.name}}</div>
</div>

<div
    v-if="work.video === true"
    class="work_thumbnail"
    @click="showWork(work)"
    :style="{
    transform: [currentWork === selectWork($event) ? { cardTransform } :  ''],
    transition: 'transform 0.25s ease-out'
    }"
    @mouseover="selectWork($event)"
    >
    <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 } from 'vue'

var currentWork

const {
    elementX,
    elementY,
    elementHeight,
    elementWidth,
    isOutside
} = useMouseInElement(currentWork)

const cardTransform = computed(() => {

    const Max_Rotation = 40

    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 isOutside.value
        ? ''
        : `perspective(${elementWidth.value}px) rotateX(${rX}deg) rotateY(${rY}deg)`
})




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();
            }
        },
        selectWork(event) {
            currentWork = event.target
            return event.target
        },
    },
    setup() {
        return {
            cardTransform,
            elementX,
            elementY,
            elementHeight,
            elementWidth,
            currentWork
        }
    }
}


</script>

Parent Component (Explore.vue)

<template>
    <div class="Section Explore">^
        

        <div class="WorkList flex_c_h flex_wrap gap1">
            <WorkThumbnail v-for="(work, index) in works" :key="work" :work="work" :index="index"/>
        </div>

    </div>
</template>

<script>
import WorkThumbnail from '@/components/Explore/WorkThumbnail.vue'
export default {
    name: 'Explore',
    components: {
        WorkThumbnail
    },
    computed: {
        works() {
            return this.$store.state.works
        }
    },
        
    }
</script>

Upvotes: 0

Views: 902

Answers (1)

Ninowis
Ninowis

Reputation: 434

Looking at the docs for useMouseInElement, it seems you can pass the DOM element using Vue $ref attribute on your div, and just use the built-in isOutside property:

<div
  v-if="work.video === true"
  ref="target"
  class="work_thumbnail"
  :style="{
    transform: [!isOutside ? { cardTransform } :  ''],
    transition: 'transform 0.25s ease-out'
  }"
  @click="showWork(work)"
>
</div>

Note the use of ref() in your setup loop to make the properties reactive:

setup() {
  const target = ref(null)
  const {
    elementX,
    elementY,
    elementHeight,
    elementWidth,
    isOutside
  } = useMouseInElement(target)
    
  return {
    cardTransform,
    elementX,
    elementY,
    elementHeight,
    elementWidth,
    isOutside
  }
}

which you'll need to add to the import from Vue for the setup:

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

Upvotes: 1

Related Questions