I have an app that displays image arrays. Before the image is displayed I need to adjust cropping based upon the image dimensions. When I load the image in a vue child component, I use a computed function (arrow or regular) and in the browser's inspect vue extension the object value are there and correct. But when I attempt to use a computed object's parameter, the result are zero or Nan. I used both the standard computed function and the arrow computed function. Both results are the same.
script setup>
import { computed } from 'vue';
const prop = defineProps({
image: String,
numberOfImages: {
type: Number,
default: 0,
},
});
const getDimensions = computed(function () {
get: {
const newImg = new Image();
newImg.src = image_path(prop.image);
newImg.onload = function () {
}
// returning an object
return {
nHeight: newImg.naturalHeight,
nWidth: newImg.naturalWidth,
nAspect: newImg.naturalWidth / newImg.naturalHeight,
nPortrait: (newImg.naturalWidth > newImg.naturalHeight) ? false : true,
};
};
});
</script>
<template>
<div>
<span v-if="getDimensions.nPortrait">This is a portrait Image<br /></span>
<span v-else>This is a NOT portrait Image<br /></span>
<span>This Image Height:
{{ getDimensions.nHeight }}
</span>
<img class="w-full h-full
object-fill
object-center
rounded-lg"
:src="image_path(prop.image)" alt=""
>
</div>
</template>
The code seems to work fine until I add the span tags. Then the results are zero or Nan
I first tried it as an arrow function but no difference in result. I guess being a newbie - I just don't have a clue whats happening here to cause the NaN
You are accessing the properties of newImg
before it has loaded its src, so the dimensions are all empty. Note that the computed will update when prop.image
changes, but not when newImage
changes, as it is not a reactive reference.
To resolve the issue, turn the computed into a watcher and use the onload
to wait for the image:
const dimensions = ref({})
const loadImageDimensions = async (imageSrc) => {
if (!imageSrc){
return {}
}
const newImg = new Image()
newImg.src = imageSrc
await new Promise(resolve => newImg.onload = resolve)
return {
nHeight: newImg.naturalHeight,
nWidth: newImg.naturalWidth,
nAspect: newImg.naturalWidth / newImg.naturalHeight,
nPortrait: (newImg.naturalWidth <= newImg.naturalHeight),
}
}
watch(
() => props.image,
async () => dimensions.value = await loadImageDimensions(props.image),
{ immediate: true }
)
Note that you should not use a computed for dimensions
since it is set through an async function, and computed properties should not have side-effects.
Here it is in a playground