skip to Main Content

I’m using Vue 3 and I try to implement a skeleton loader for a placeholder when the data is loading and I can see it works if I turn on throttling in the Network tab of the browser. However, when the data loads too quick, I can also see how the skeleton loader blinks.

Here I tried using a setTimeout and inside I put the isLoaded ref which value is set to true when the image is fully loaded. But what the delay does is it prolongs time, and I need to skeleton loader be not visible when the data loads fast. I want it only be visible, when the data loads slowly.

onMounted(() => {
    const img = new Image(getSrc('.jpg'));
    img.onload = () => {
        setTimeout(() => {
            isLoaded.value = true;
        }, 300);
    };
    img.src = getSrc('.jpg');
});

Please, give a solution.

2

Answers


  1. I need to skeleton loader be not visible when the data loads fast. I want it only be visible, when the data loads slowly.

    Sounds like you need a timeout on displaying the skeleton instead. Cancel it when the data is loaded.

    For example, display the skeleton after a suitable minimum delay, eg 100ms. If the data loads first, don’t display it at all.

    const showPlaceholder = ref(false);
    
    // ...
    
    onMounted(async () => {
      // wait 100ms to show the placeholder
      const placeholderTimer = setTimeout(() => {
        showPlaceholder.value = true;
      }, 100);
    
      const img = new Image(); // the constructor only accepts dimensions, not src
      img.src = getSrc('.jpg');
      await img.decode(); // much easier to use than onload
      clearTimeout(placeholderTimer);
      showPlaceholder.value = false;
      isLoaded.value = true;
    });
    

    Then use the showPlaceholder ref value to conditionally render the skeleton.

    Login or Signup to reply.
  2. I would leave the skeleton logic alone, just fade it in after some time, avoiding the jump in content if you delay displaying the skeleton (as discussed in @Phil’s answer)

    The example below, there’s no skeleton visible for 1000ms, then the skeleton will fade in for 1000ms – the times are probably longer than you want, I just wrote it this way to see it actually working – so, just adjust the animation-duration (and animation-timing-function if you want) as appropriate to your needs

    <style scoped>
    @keyframes skeletonAnimate {
        0% {
            opacity:0;
        }
        50% {
            opacity:0;
        }
        100% {
            opacity:1;
        }
    }
    .skeleton {
        opacity:0;
        animation-name: skeletonAnimate;
        animation-duration: 2000ms;
        animation-direction: forward;
        animation-delay: 0;
        animation-iteration-count: 1;
        animation-fill-mode: forwards;
        animation-timing-function: ease-out;
    }
    </style>
    

    Not sure how your skeleton is done, but here’s a non-vue demo in action

    @keyframes skeletonAnimate {
      0% {
        opacity: 0;
      }
      50% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }
    
    .skeleton-content {
      opacity: 0;
      animation-name: skeletonAnimate;
      animation-duration: 2000ms;
      animation-direction: forward;
      animation-delay: 0;
      animation-iteration-count: 1;
      animation-fill-mode: forwards;
      animation-timing-function: ease-out;
    }
    
    @keyframes bgAnimate {
      0% {
        background-position: 50% 0;
      }
      100% {
        background-position: -150% 0;
      }
    }
    
    .skeleton {
      height: 100px;
      width: 200px;
      background-image: linear-gradient( to right, hsla(210, 2%, 54%, 20%) 0%, hsla(210, 4%, 89%, 20%) 10%, hsla(210, 2%, 54%, 20%) 40%, hsla(210, 2%, 54%, 20%) 100%);
      background-repeat: repeat-x;
      background-size: 200% 100%;
      box-shadow: 0 4px 6px -1px hsla(0, 0%, 0%, 0.1), 0 2px 4px -2px hsla(0, 0%, 0%, 0.1);
      animation: bgAnimate 2s linear infinite;
    }
    <div class="skeleton-content">
    <div class="skeleton"></div>
    </div>
    Other content
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search