If you’re using Vue as an HTML templating engine, i.e. you’re placing vue template items directly in your HTML, then you may have noticed that the raw template items display for a short time before the Vue instance loads, which can look pretty ugly.

Let’s say I have the following view model:

var vm = new Vue({
   el: '#app',
   data: {
     message: 'Hello Vue!'
   }
});

If I then do:

<div id="app">{{message}}</div>

The raw {{message}} will display until the page is loaded. The following JSFiddle simulates this effect: https://jsfiddle.net/3Ljbkzw5/

Fortunately, Vue already has a directive built in called v-cloak. To get it to work you simply need to create the css markup and add the v-cloak directive to the div you want to cloak:

CSS

[v-cloak] {
  display: none;
}

HTML

<div id="app" v-cloak>{{message}}</div>

Here’s the updated JSFiddle: https://jsfiddle.net/z6pyrmk9/

As you can see v-cloak has hidden the template until the entire vue instance has been rendered.

Digging a Little Deeper

While v-cloak may seem magic, you can actually get the same effect by using a completely empty directive, because the directive gets removed when the vue instance is rendered. This means that you can do all kinds of funky stuff in your css and name the appropriate effect with a simple empty custom directive, you just need to rename the attribute your css is targeting to the name of the directive.

In this example I’ve set up a little game, which takes a famous quote and flashes the (appropriately named) unloaded data property names at the user so they can try to guess the answer.

To do this I’ve defined an empty directive called “v-blink” and created the css for the blink effect targeting the v-blink attribute. I’m also using v-cloak to cloak part of the page I don’t want to display until the page is fully loaded. Obviously I’ll need to give a short delay to reveal the answers to our users, hence the show flag and a timeout in the created hook and I’m also delaying the mounting of the app by 3 seconds so we have time to look at the quote. In order to make this look a little better I’ve changed the delimiters to stars, which isn’t practical in real life but perfect for this example:

CSS:

[v-blink] {
  animation: blink 0.7s linear infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

[v-cloak] {
  display: none;
}

Vue:

Vue.directive('blink', {})

var vm = new Vue({
  delimiters: ['*', '*'],
  mounted() {
    setTimeout(() => {
      this.show = true;
    }, 2000)
  },
  data: {
    what: 'Failed',
    who: '~Thomas Edison',
    show: false
  }
});

setTimeout(() => {
  vm.$mount("#app");
}, 3000);

HTML

<div id="app">
  <div v-if="!show">
    I have not <strong v-blink>*what*</strong>. I've just found 10,000 ways that won't work.
    <p v-blink>
      <i>*who*</i></p>
  </div>
  <div v-else v-cloak>
    Did you get that right?
  </div>
</div>

Here’s the example on JSFiddle: https://jsfiddle.net/82o1jw7w/

Advertisements