1
votes

I am using Vuetify to create a login form for an application.

This form is similar to Google's login form which first asks for an email address then for a password on the next screen. The purpose of doing this is to look up the user's email address to see whether to perform local authentication or to redirect the user to a Single-Sign-On provider.

Here is the relevant part of the code of the login component:

<template>
    <v-app id="sm-login">
        <v-content>
            <v-container class="fill-height" fluid>
                <v-card class="mx-auto px-10 pb-9" width="450px" :loading="loading">
                    <v-card-title class="justify-center pt-12"><img src="../../images/logo.png"></v-card-title>
                    <v-card-subtitle class="text-center py-6 headline">Sign In</v-card-subtitle>
                    <v-card-text>
                        <v-form v-if="!showPassword" v-on:submit.prevent="lookupEmail">
                            <v-text-field v-model.trim="email" label="Email" name="email" type="email" outlined />
                        </v-form>
                        <v-form v-if="showPassword" v-on:submit.prevent="login">
                            <v-chip outlined class="mb-6" close @click:close="showPassword = false"><v-avatar left><v-icon>mdi-account-circle</v-icon></v-avatar> {{email}}</v-chip>
                            <v-text-field v-model="password" label="Password" name="password" type="password" outlined />
                        </v-form>
                    </v-card-text>
                    <v-card-actions>
                        <v-btn text>Forgot Password?</v-btn>
                        <v-spacer />
                        <v-btn color="primary" v-on:click="clickButton">Log In</v-btn>
                    </v-card-actions>
                </v-card>
            </v-container>
        </v-content>
    </v-app>
</template>

<script>
export default {
    data() {
        return {
            loading: false,
            email: '',
            password: '',
            showPassword: false,
        };
    },
    methods: {
        lookupEmail() {
            this.loading = true;
            // Replaced an API call with a timeout for demonstration purposes
            setTimeout(() => {
                this.loading = false;
                this.showPassword = true;
            }, 2000);
        },
        login() {
            // DO LOGIN HERE ...
        },
        clickButton() {
            if (this.showPassword) {
                this.login();
            } else {
                this.lookupEmail();
            }
        }
    }
};
</script>

The problem here is the logo in the v-card-title section. Every time the loading property is toggled on or off, the entire card jumps slightly up and then down again. I figured out that adding the logo's explicit height and width fixes the jumping, and it does, but the image still flickers every time.

Using the DevTools' Network tab, I discovered that the logo is reloaded from the server every time the loading bar appears or disappears. Needless to say, this is not the desired or expected behavior.

Why is the logo reloading every time, and what can I do about it?

2

2 Answers

1
votes

This was a bug in how the <v-card> element is rendered.

Rendering the initial <v-card> creates div elements with the following classes: v-card__title, v-card__subtitle, v-card__text, and v-card__actions.

What should happen when loading is set to true is that a new div with class v-card__progress is created above the v-card__title element.

Instead, what is happening is that the title element is being modified to turn it into v-card__progress and a new div is created for the v-card__title. The new img tag in this new div is what causes the reload.

Again, when turning off loading, you would think this should just remove the v-card__progress element, but it doesn't. Instead, it removes the v-card__title element and modifies the v-card_progress to turn it into the title. Again, the new img tag here causes the reload.

I filed a bug report, which was fixed in v2.2.16.


NOTE: In general use, this is not typically noticeable in the browser. The only reason I saw it is because I had the DevTools open with "Disable Cache" checked.

0
votes

It's weird, could you delete the <v-content> and try it again? just like:

<template>
  <v-app id="sm-login">
    <v-container class="fill-height" fluid>
      ...