Vue JS 3 中如何在图片上使用过渡效果?

huangapple go评论55阅读模式
英文:

How do transitions work on Images in Vue JS 3?

问题

I have been unable to apply a fade in transition to an image using Vue JS 3. The transition works fine with text, but the image just loads and renders as it would normally without a transition applied.

I have been trying to create an image loader, which will show a loading spinner until the image is loaded, then fade the loading spinner out and the image in once the image loads. Currently the loading spinner fades out as expected, but the image does not fade in.

Here is what I have in the image element:

<script setup>
  import FadeTransition from '../transitions/fade-transition.vue';
  import { reactive } from 'vue';

  const props = defineProps({
    imgUrl: String,
    route: String
  });

  let getURL = function () {
    return new URL(props.imgUrl, import.meta.url);
  };

  let show = reactive({showing: false});
  let showImg = function () {
    show.showing = true;
  };
</script>

<template>
  <div class="frame">
    <FadeTransition><div v-show="!show.showing" class="loader"></div></FadeTransition>
    <RouterLink :to="props.route"><FadeTransition><img v-show="show.showing" class="image" :src="getURL()" @load="showImg()"/></FadeTransition></RouterLink>
  </div>
</template>

<style scoped>
  .frame {
    width: 33.3333%;
    aspect-ratio: 1/1;
    margin: 0px;
    /*inline-block leaves space for descenders (e.g: letter y or g) so space between rows is wrong*/
    display: inline-flex;
    position: relative;
    padding: 6px;
  }

  .image {
    width: calc(100% - 12px);
    height: calc(100% - 12px);
    position: absolute;
  }

  .loader {
    border: 4px solid var(--grey);
    border-top: 4px solid var(--darkGrey);
    border-radius: 50%;
    width: 30px;
    height: 30px;
    animation: spin 5s linear infinite;
    position: absolute;
    left: calc(50% - 15px);
    top: calc(50% - 15px);
  }

  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
</style>

and the FadeTransition component is:

<script>
</script>

<template>
  <Transition name="fade">
    <slot></slot> 
  </Transition>
</template>

<style>
  .fade-enter-active, 
  .fade-leave-active {
    transition: opacity 0.5s ease;
  }

  .fade-enter-from, 
  .fade-leave-to {
    opacity: 0;
  }
</style>

I have tried swapping the image for a text block, which works correctly, leading me to conclude that the problem I have is that the transition is not being correctly applied to the image.

How can I get the transition to apply correctly to the image?

英文:

I have been unable to apply a fade in transition to an image using Vue JS 3. The transition works fine with text, but the image just loads and renders as it would normally without a transition applied.

I have been trying to create an image loader, which will show a loading spinner until the image is loaded, then fade the loading spinner out and the image in once the image loads. Currently the loading spinner fades out as expected, but the image does not fade in.

Here is what I have in the image element:

&lt;script setup&gt;
import FadeTransition from &#39;../transitions/fade-transition.vue&#39;;
import { reactive } from &#39;vue&#39;
const props = defineProps({
imgUrl: String,
route: String
})
let getURL = function () {
return new URL(props.imgUrl, import.meta.url);
}
let show = reactive({showing: false});
let showImg = function () {
show.showing = true;
}
&lt;/script&gt;
&lt;template&gt;
&lt;div class=&quot;frame&quot;&gt;
&lt;FadeTransition&gt;&lt;div v-show=&quot;!show.showing&quot; class=&quot;loader&quot;&gt;&lt;/div&gt;&lt;/FadeTransition&gt;
&lt;RouterLink :to=&quot;props.route&quot;&gt;&lt;FadeTransition&gt;&lt;img v-show=&quot;show.showing&quot; class=&quot;image&quot; :src=&quot;getURL()&quot; @load=&quot;showImg()&quot;/&gt;&lt;/FadeTransition&gt;&lt;/RouterLink&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;style scoped&gt;
.frame {
width: 33.3333%;
aspect-ratio: 1/1;
margin: 0px;
/*inline-block leaves space for descenders (e.g: letter y or g) so space between rows is wrong*/
display: inline-flex;
position: relative;
padding: 6px;
}
.image {
width: calc(100% - 12px);
height: calc(100% - 12px);
position: absolute;
}
.loader {
border: 4px solid var(--grey);
border-top: 4px solid var(--darkGrey);
border-radius: 50%;
width: 30px;
height: 30px;
animation: spin 5s linear infinite;
position: absolute;
left: calc(50% - 15px);
top: calc(50% - 15px);
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
&lt;/style&gt;

and the FadeTransition component is:

&lt;script&gt;
&lt;/script&gt;
&lt;template&gt;
&lt;Transition name=&quot;fade&quot;&gt;
&lt;slot&gt;&lt;/slot&gt; 
&lt;/Transition&gt;
&lt;/template&gt;
&lt;style&gt;
.fade-enter-active, 
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from, 
.fade-leave-to {
opacity: 0;
}
&lt;/style&gt;

I have tried swapping the image for a text block, which works correctly, leading me to conclude that the problem I have is that the transition is not being correctly applied to the image.

How can I get the transition to apply correctly to the image?

答案1

得分: 1

如果 imgUrl 是一个属性(prop),我会添加一个监视器(watcher),当URL发生变化时重新设置组件:

watch(
  () => props.imgUrl,
  () => {
    show.showing = false
  },
  { immediate: true }
)

否则,在初始加载后,当URL变化时不会触发加载动画和淡出效果。

其余部分看起来都完全正常。

如果我漏掉了什么,请告诉我。

英文:

Hmm, all I can tell you is that it seems to work perfectly in the playground

If imgUrl is a prop, I would add a watcher that resets the component when the URL changes:

watch(
() =&gt; props.imgUrl,
() =&gt; {
show.showing = false
},
{immediate: true}
)

Otherwise, the loading animation and the fade will not be triggered when the URL changes after the initial load.

The rest looks perfectly fine.

Please let me know if I am missing something.

huangapple
  • 本文由 发表于 2023年5月11日 00:33:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76220747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定