简体   繁体   中英

Vue wait for render template and display it

I have a problem with rendering in vue.js. I made a simple login/registration app. When the user is logged in, the register link should be hidden. It works but when I reload page there is small delay. I try to use v-cloak but it's not working. How can I fix it? I recorded loading on gif.

在此处输入图片说明

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>michael-client</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
          integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
  </head>
  <body>
  <style type="text/css">
    [v-cloak] {
      display:none;
    }
  </style>
  <div class="container">
    <div class="col-lg-8">
      <div id="app">
      <!-- built files will be auto injected -->
      </div>
    </div>
  </body>
</html>

App.vue

<template>
  <div class="panel panel-default" v-cloak>
    <div class="panel-heading">
      <nav>
        <ul class="list-inline">
          <li>
            <router-link :to="{ name: 'home' }">Home</router-link>
          </li>
          <li v-if="!$auth.check()" class="pull-right">
            <router-link :to="{ name: 'login' }">Login</router-link>
          </li>
          <li v-if="!$auth.check()" class="pull-right" v-cloak>
            <router-link :to="{ name: 'register' }">Register</router-link>
          </li>
          <li v-if="$auth.check()" class="pull-right">
            <a href="#" @click.prevent="$auth.logout()">Logout</a>
          </li>
        </ul>
      </nav>
    </div>
    <div class="panel-body">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

and main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import Home from './components/Home'
import Login from './components/Login'
import Register from './components/Register'
import Dashboard from './components/Dashboard'
import VueRouter from 'vue-router'
import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.config.productionTip = false

/* eslint-disable no-new */


Vue.use(VueRouter);
Vue.use(VueAxios, axios);
axios.defaults.baseURL = 'http://127.0.0.1:8888/api';


const router = new VueRouter({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home
    },
    {
      path: '/login',
      name: 'login',
      component: Login,
      meta: {
        auth: false
      }

    },
    {
      path: '/register',
      name: 'register',
      component: Register,
      meta: {
        auth: false
      }
    }
  ]
});

Vue.router = router
Vue.use(require('@websanova/vue-auth'), {
  auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),
  http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),
  router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js'),
});
App.router = Vue.router

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',
  render: function(createElement) {
    return createElement(App);
  }
});

In which way are you guys waiting for page is read to display?

Instead of making Vue do the same work over and over, You could make use of the v-else directive, which may work better for you:

      <li v-if="!$auth.check()" class="pull-right" v-cloak>
        <router-link :to="{ name: 'register' }">Register</router-link>
      </li>
      <li v-else class="pull-right">
        <a href="#" @click.prevent="$auth.logout()">Logout</a>
      </li>

v-cloak is not helping because that gets taken away as soon as the Vue app is ready. Apparently there's a delay from when Vue is ready and when the $auth function returns a response. I'd recommend hiding all of the login/logout links until $auth returns something.

You'd have to hook into what $auth returns somehow, and use that hook to change the authCheckDone to true.

Vue {
  data: {
    authCheckDone: false
    ...
  }
}

<ul class="list-inline">
      <li>
        <router-link :to="{ name: 'home' }">Home</router-link>
      </li>
      <span v-if="authCheckDone">
         <li v-if="!$auth.check()" class="pull-right">
           <router-link :to="{ name: 'login' }">Login</router-link>
         </li>
         <li v-if="!$auth.check()" class="pull-right" v-cloak>
           <router-link :to="{ name: 'register' }">Register</router-link>
         </li>
         <li v-if="$auth.check()" class="pull-right">
           <a href="#" @click.prevent="$auth.logout()">Logout</a>
         </li>
      </span>
</ul>

You have to wait a bit until vue-auth is actually ready. From the docs :

ready

  • Get binded ready property to know when user is fully loaded and checked.
  • Can also set a single callback which will fire once (on refresh or entry).

 <div v-if="$auth.ready()"> <vue-router></vue-router> </div> <div v-if="!$auth.ready()"> Site loading... </div> 
 created() { this.$auth.ready(function () { console.log(this); // Will be proper context. }); } 

In other words, instead of v-cloak use:

<div class="panel panel-default" v-if="$auth.ready()">

Note: this can do some quick "flashing" of a white page. In that case you may want to add a loading image or something, like:

<div v-if="!$auth.ready()">
    <img src="loading.gif">
</div>

Naturally, if this div is close to the other v-else can be used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM