Agrejus
Agrejus

Reputation: 762

Vue + Asp.net rendering issue

I have a new asp.net mvc project (not .net core) and I am trying to incorporate Vue js into the project. I have everything working in a sample project using Webpack+Vue+Asp.Net Mvc, which was created following this article https://medium.com/corebuild-software/vue-js-and-net-mvc-b5cede228626.

The app works great, except for the split second before Vue renders. There is noticable flashing/popping of the Vue templated code before its rendered to html. Below is a gif of me refreshing the page and users are able to see the template before Vue renders it into html.

enter image description here

I know why this is happening, but I do not know any ways around it. Would Server Side Rendering fix this? Can SSR be done in a non .net core project?

Unfortunately, switching to asp.net core is not an option. The project will be using Umbraco 7, which cannot run on asp.net core (https://our.umbraco.com/forum/using-umbraco-and-getting-started/93640-net-core).

Below are my files

Index.cshtml

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="https://asp.net" class="btn btn-primary btn-lg">Learn more &raquo;</a></p>
</div>

<div id="app" controller-data="{ name: 'James' }">
    <h3>Test</h3>
    {{ vueMessage }}
    {{ controllerData }}
    <first-component v-bind:time="new Date()" data="@Model"></first-component>
    <button v-on:click="test">Test</button>
</div>

<div class="row">
    <div class="col-md-4">
        <h2>Getting started</h2>
        <p>
            ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
            enables a clean separation of concerns and gives you full control over markup
            for enjoyable, agile development.
        </p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301865">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Get more libraries</h2>
        <p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301866">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Web Hosting</h2>
        <p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
        <p><a class="btn btn-default" href="https://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a></p>
    </div>
</div>

@Scripts.Render("~/Scripts/bundle/home.js")

index.js (gets compiled to Scripts/bundle/home.js by webpack)

import Vue from 'vue';
import FirstComponent from './sub-components/first-component.vue'

new Vue({
    el: '#app',
    components: {
        FirstComponent
    },
    props: {
        controllerData: Object
    },
    methods: {
        test: function () {
            console.log(this);
        }
    },
    data: function () {
        return {
            vueMessage: 'Message from Vue'
        };
    }
})

first-component.vue

<template>
    <div class="time">
        {{ time }}
        {{ data }}
    </div>
</template>
<script>
    export default {
        props: {
            time: {
                type: Object,
                required: true,
            },
            data: Object
        }
    }
</script>
<style>
    .time {
        color: #F44336;
    }
</style>

Upvotes: 2

Views: 2180

Answers (2)

Anth12
Anth12

Reputation: 1897

Switching to .net core or any other server side technology would not help.

The issue is because the html is rendered by the browser as it downloads & before all the script resources have downloaded/parsed/run & rendered the html from the Vue component.

When dealing with mixed rendering (partially server side & partially client side) your best option is to hide the template by default & "show" it once the vue component is setup & ready.

For example in your server side view, hide <div id="app"> either with an attribute, style or class.

<style>#app.loading {display:none;}</style>
<div id="app" v-bind:class="{ loading: !isloaded }">

Then in your vue component mounted method set isLoaded to true. This is just one of many ways to hide the component before it's ready.

Upvotes: 0

Postlagerkarte
Postlagerkarte

Reputation: 7117

Make use of the v-cloak attribute.

<div id="app" v-cloak>
...
</div>

The attribute is automatically removed by vue when the framework has finished mounting.

The v-cloack attribute does not show or hide your elements - it is basically a marker that indicates if mounting is finished. You write a css selector to target v-cloack to hide the elements or show a loading indicatior.

<style>
    [v-cloak] > * { display:none }
    [v-cloak]::before { content: "Please wait…" } 
</style>

Upvotes: 4

Related Questions