194

maybe this is a trivial question.

so, when I run my vuejs application on browser with enables throttling download speed (sets to low connection). I got unfinished vue syntax output in browser.

Vue js syntax appear in browser

I know we can trick this out with showing loading image before entire page has loaded, but it's there any best solution to fix this?

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
antoniputra
  • 4,251
  • 6
  • 26
  • 31

12 Answers12

293

You can use the v-cloak directive, which will hide the Vue instance until the compilation finishes, if you combine it with the right CSS.

HTML:

<div v-cloak>{{ message }}</div>

CSS:

[v-cloak] { display: none; }
tony19
  • 125,647
  • 18
  • 229
  • 307
Gus
  • 4,437
  • 2
  • 24
  • 27
45

I attached the following codepen. You can see the difference with and without v-cloak.

<div id="js-app">
[regular]Hold it... <span>{{test}}</span><br/>
[cloak]Hold it... <span v-cloak>{{test}}</span>
</div>

http://codepen.io/gurghet/pen/PNLQwy

gurghet
  • 7,591
  • 4
  • 36
  • 63
  • 1
    yeah I got it... thanks, your codepen would be help for the new comers. – antoniputra May 11 '16 at 16:11
  • you still get the first {{test}} whilst vuejs is loading so its not a perfect answer – twigg Dec 09 '16 at 11:19
  • 13
    @twigg That's the point. The first one shows regular tag and the second shows cloaked tag using the `v-cloak` attribute. – kb. Jan 02 '17 at 20:19
41

As suggested by others using v-cloak is proper solution. However as @ DelightedD0D mentioned it IS clunky. Simple solution is to add some CSS in the pseudo selector ::before of v-cloak directive.

In your sass/less file something along the lines of

[v-cloak] > * { display:none; }
[v-cloak]::before {
  content: " ";
  display: block;
  position: absolute;
  width: 80px;
  height: 80px;
  background-image: url(/images/svg/loader.svg);
  background-size: cover;
  left: 50%;
  top: 50%;
}

Of course you'd need to provide a valid and accessible path to loader image. It will render something like.

enter image description here

Hope it helps.

tony19
  • 125,647
  • 18
  • 229
  • 307
schartz
  • 605
  • 7
  • 9
10

Using v-cloak directive you can hide un-compiled mustache bindings until vue instance is done compiling. You must use the CSS block to hide it until compiled.

HTML:

<div v-cloak>
  {{ vueVariable }}
</div>

CSS:

[v-cloak] {
  display: none;
}

This <div> will not be visible until the compilation is completed.

You can see this link Hide elements during loading using v-cloak for better understating.

Summonjoy
  • 489
  • 4
  • 5
8

Don't include any vuejs syntax in the HTML file:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>My Super app</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/app.js"></script>
  </body>
</html>

In your main JavaScript, you can:

import Vue from 'vue'
import App from './App'

new Vue({
  el: '#app',
  components: { App },
  template: '<App/>'
})

See the vuetify webpack template for reference.

Another solution is to use:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>My Super app</title>
  </head>
  <body>
    <div id="app" is="App"></div>
    <script src="/app.js"></script>
  </body>
</html>

With:

import Vue from 'vue'
import App from './App'
Vue.component("App", App);

const app = new Vue({});

window.addEventListener("load", async () => {    
  app.$mount("#app")
})
ysdx
  • 8,889
  • 1
  • 38
  • 51
7

Putting everything inside a <template> worked well for me.

The content is hidden until rendered by Vue.

<!-- index.html -->
<div id="app">
  <template>
    <span class="name">{{ name.first }} {{ name.last }}</span>
  </template>
</div>
/* index.js */
new Vue({
  el: '#app',
  data: {
    name: { first: 'David', last: 'Davidovich'}
  }
});
Arik
  • 5,266
  • 1
  • 27
  • 26
6
**html**
<div v-cloak>{{ message }}</div>

**css**
[v-cloak] { display: none; }
gotocartik
  • 157
  • 1
  • 8
5

Use <v-cloak> to hide your Vue code before binding data to relevant places. It's actually located in a place on Vue documentation that anyone might miss it unless you search for it or read thoroughly.

dakshinasd
  • 93
  • 1
  • 2
  • 8
3

You could move any rendering to a simple wrapper component. The VueJS initialisation e.g. new Vue(....) shouldn’t contain any HTML apart from that single wrapper component.

Depending on setup you could even have <app>Loading...</app> where app is the wrapper component with any loading HTML or text in between which is then replaced on load.

tony19
  • 125,647
  • 18
  • 229
  • 307
A. Hall
  • 71
  • 4
2

Yep, you can use v-cloak, I like use spinkit, is a great library with only CSS, check a simple example:

var vm = null;
    setTimeout(function() {
     vm = new Vue({
         el: '#app',
        data: {
          msg: 'Is great, using: ',
          url: 'http://tobiasahlin.com/spinkit/'
         }
      });
     }, 3000);
#app .sk-rotating-plane,
[v-cloak] > * { display:none }
body{
 background: #42b983;
 color: #35495e;
}
#app[v-cloak] .sk-rotating-plane {
 display:block;
 background-color: #35495e;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>

<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/tobiasahlin/SpinKit/master/css/spinkit.css">


<div id="app" v-cloak>
    <div class="sk-rotating-plane"></div>
    <h1>Vue with c-cloak</h1>
  <p>
    {{ msg }}
    <a :href='url'>{{ url }}</a>
  <p>
</div>

Link: - http://tobiasahlin.com/spinkit/

fitorec
  • 4,257
  • 2
  • 24
  • 18
0

For those who use v-cloak in a view with multiple Laravel Blade files and it's not working, try to use the v-cloak on the parent blade file rather than in any child blade file.

user8581607
  • 169
  • 1
  • 5
-1

I prefer using v-if with a computed property that checks if my data is ready, like this:

<template>
    <div v-if="shouldDisplay">
        {{ variableName }}
    </div>
    <div v-else>
      Here you can insert a loader
    </div>
</template>
<script>
export default {
    name: 'Test',
    data() {
        return {
            variableName: null,
        };
    },
    computed() {
        shouldDisplay() {
            return this.variableName !== null;
        }
    },
    mounted() {
        this.variableName = 'yes';
    },
};
</script>

In this way it's easier to show a loader only if the data is not ready (using v-else).

In this particular case v-if="variableName" would work as well, but there can be more complicated scenarios.

Giorgio Tempesta
  • 1,816
  • 24
  • 32
  • That works for after the page script is loaded and vue is mounted. This is also a pre-compiled component. The OP was referring to a page that is compiled at runtime, which the browser loads the page first. And if your script is slow to load, then for a brief moment you see the vue syntax. – John C Oct 08 '21 at 03:58