web-dev-qa-db-fra.com

Composant de rechargement Vue-router

J'ai quelques itinéraires qui chargent chacun 3 composants. Deux des composants sont les mêmes sur tous les itinéraires. Lorsque je passe d’un itinéraire à l’autre, je souhaite transmettre de nouvelles données et lors de certains événements init du composant, je souhaite remplir les données de ce composant afin qu’il soit reflété sur le composant. UI. De plus, je veux relancer les animations bootstrap des composants en cours de chargement. Comment procéder pour le faire. Parce qu’à présent, je ne sais pas où dans le composant cycle de vie voudrais-je aller chercher les données et rendre le composant avec ces nouvelles données. Concrètement dans myapps/1 et/newapp/I, j'ai un composant de vue principal et un composant de barre latérale. Dans le/newapp/URL, je veux que toutes les icônes de la barre latérale soient rouges (rien dans la vue principale n'a été rempli) et que la vue principale doit être vide. Sur le myapps/1 Je veux charger les données du serveur dans la vue principale et si tout est rempli, je veux que les icônes de la barre latérale soient vertes. Ce qui se passe maintenant, je charge myapps/1, cliquez sur le deuxième élément de la barre latérale et la vue principale passe à la deuxième vue. Puis je router.Push ("/ newapp /); et la barre latérale reste sur le deuxième élément et la deuxième vue principale. Donc router.Push ("/myapps/"); ne recharge pas ma barre latérale et mon écran principal. vue.

MODIFIER:

Ici vous voyez mes routes, les barres latérales et les valeurs par défaut sont les mêmes.

 const routes = [
    {
        path: "/myapps/newproject",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsNewProject,
            "sidebar": SidebarProject
        }
    },
    {
        path: "/myapps/:id",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsCurrentProject,
            "sidebar": SidebarProject
        }
    },
    {
        path: "/myapps/newversion/:id",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsNewVersion,
            "sidebar": SidebarProject
        }
    }
];

C'est mon ProjectMain.vue

<template>
    <div class="wrapper wrapper-content">
        <component :is="currentProjectMain"></component>
    </div>
</template>

Voici ma vue de routeur dans index.html:

<router-view name="sidebar"></router-view>

Et j'en ai un autre dans index.html, celui par défaut:

<router-view></router-view>

Lorsque je clique sur un élément de la barre latérale, j’émet un événement vers ProjectMain pour permuter le composant. Donc, comme ceci: Dans la barre latérale:

eventBus.$emit("currentProjectMainChanged", "appOverview");

ou 

eventBus.$emit("currentProjectMainChanged", "appSettings");

Et que dans ProjectMain:

eventBus.$on("currentProjectMainChanged", function(data){
                if(data === "appOverview"){
                    self.currentProjectMain = CurrentProjectAppOverview;
                }else if(data === "appSettings"){
                    self.currentProjectMain = CurrentProjectSettings;
                }
            });

Si je suis arrivé à "/ myapps /: id". Il charge la barre latérale et ProjectMain et moi-même obtenons une petite animation de la barre latérale et de ProjectMain avec ces classes d'amorçage: <div class="animated fadeInUp"> et les deux composants ont traversé le cycle de vie complet.

Par défaut, appOverview est sélectionné dans la barre latérale et CurentProjectAppOverview.vue est chargé en tant que composant dans ProjectMain. Puis je clique sur appSettings dans la barre latérale et la classe est ajoutée à cet élément dans la barre latérale pour le marquer comme sélectionné et dans la fenêtre. ProjectMain CurrentProjectSettings.vue est chargé en tant que composant.

Mais ensuite, dans la chapelure, j'ai un bouton pour aller à "/myapps/newversion/:id"Here est le problème. Lorsque je clique pour aller à "/ myapps/newversion /: id" (router.Push("/myapps/newversion/" + id);), le deuxième élément de la barre latérale reste sélectionné (appSettings) et dans ProjectMain CurrentProjectSettings.vue reste chargé, et je ne reçois pas l'animation de démarrage de la barre latérale. ProjectMain et les composants ne passent pas par leur cycle de vie.

Ce que je veux ici quand je clique sur le bouton pour aller à "/ myapps/newversion /: id" est mon animation bootstrap (<div class="animated fadeInUp">), je veux que la barre latérale et ProjectMain suivent leur cycle de vie complet. Et je veux que l'élément par défaut soit sélectionné dans la barre latérale (donc appOverview) et que le composant par défaut soit chargé dans ProjectMain (donc CurentProjectAppOverview.vue).

Il y a des boutons de couleur pour chaque élément dans la barre latérale. Si je vais dans "/ myapps/newversion /: id" depuis "/ myapps /: id", je veux charger les données du serveur dans CurrentProjectAppOverview.vue et si toutes les données sont remplies, je souhaite que le bouton de la barre latérale soit vert et sinon, il devrait être rouge.

En bref, lorsque je passe d’un itinéraire à l’autre, je veux pouvoir charger des données et remplir les champs de mon choix. Je souhaite que l’animation bootstrap et les vues par défaut soient sélectionnées et chargées et qu’ils passent leur cycle de vie dans son intégralité. Maintenant, le routeur les réutilise comme ils sont.

Donc, quelque chose comme "ReloadComponent: true", ou détruire et recréer le composant.

Je pourrais dupliquer SidebarProject.vue et ProjectMain.vue et les renommer. Sur chaque route, charger une copie, mais cela voudrait dire que je devrais écrire le même code dans différents fichiers .vue.

Auparavant, il y avait une option pour définir YouComponent.route.canReuse sur false, ce qui ferait ce que je veux, je pense, mais il est supprimé dans la version la plus récente.

6
Dario Huzjak

En partie grâce à cela: https://forum.vuejs.org/t/vue-router-reload-component/4429

J'ai mis au point une solution qui fonctionne pour moi:

J'ai d'abord ajouté une nouvelle fonction à jQuery qui est utilisée pour relancer une animation bootstrap lors du chargement du composant.

$.fn.redraw = function(){
    return $(this).each(function(){
        var redraw = this.offsetHeight;
    });
};

En composant:

export default{
        created:function(){
            this.onCreated();
        },
        watch: {
            '$route' (to, from) {
                //on route change re run: onCreated
                this.onCreated();

                //and trigger animations again
                $("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
            }
        }
}

J'appelle la méthode onCreated(); lorsque le composant est chargé et lorsque l'itinéraire est rechargé ou que l'ID du même itinéraire change, mais que le composant reste le même. J'appelle simplement à nouveau la méthode. Cela prend en charge les nouvelles données.

En ce qui concerne le déclenchement des animations de démarrage, j'utilise la fonction redraw(); que j’ajoute à jQuery dès le début de l’application. et cela déclenche les animations sur le changement d'URL:

$("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
4
Dario Huzjak

On dirait que vous utilisez vue-router. 

Je n'ai pas votre code, mais je peux vous montrer comment j'ai géré cela. Voir les vues nommées .

Voici mon routeur-map de mon fichier bundle.js: 

const router = new VueRouter({
routes: [
    { path: '/',
      components: {
        default: dashboard,
        altside: altSide,
        toolbar: toolbar
      },
    },
    { path: '/create',
      components: {
        default: create,
        altside: altSide,
        toolbar: toolbar
      },
    },
    { path: '/event/:eventId', 
        name: 'eventDashboard',
        components: { 
            default: eventDashboard,
            altside: altSide,
            toolbar: eventToolbar,
        },
        children: [
            { path: '/', name: 'event', component: event },
            { path: 'tickets', name: 'tickets', component: tickets},
            { path: 'edit', name: 'edit', component: edit },
            { path: 'attendees', name: 'attendees', component: attendees},
            { path: 'orders', name: 'orders', component: orders},
            { path: 'uploadImage', name: 'upload', component: upload},
            { path: 'orderDetail', name: 'orderDetail', component: orderDetail},
            { path: 'checkin', name: 'checkin', component: checkin},
        ],
    }
]
})

J'ai nommé-vues de "défaut", "altside" et "barre d'outils" J'attribue un composant à la vue nommée pour chaque chemin. 

La deuxième moitié de ceci est dans votre composant parent où vous attribuez le nom 

<router-view  name="toolbar"></router-View>   

Voici mon modèle parent: 

<template>

    <router-view class="view altside" name="altside"></router-view>
    <router-view class="view toolbar" name="toolbar"></router-view>
    <router-view class="view default"></router-view>
</template>

Donc, ce que j'ai fait, c'est que j'ai dit au modèle parent de regarder la vue nommée de la vue routeur. Et en fonction du chemin, tirez le composant que j'ai désigné dans la carte de routage. 

Pour ma barre d’outils '/' == le composant barre d’outils mais dans la barre d’outils '/ create' = composant eventToolbar. 

Le composant par défaut est dynamique, ce qui me permet d’utiliser des composants enfants sans permuter les composants de la barre d’outils ou d’altside. 

3
retrograde

Je faisais face au même problème. Je citerai une réponse trouvée, qui est vraiment simple et géniale. La solution la plus simple consiste à ajouter un attribut: key à:

<router-view :key="$route.fullPath"></router-view>

En effet, Vue Router ne remarque aucun changement si le même composant est en cours d'adressage. Avec la clé, toute modification du chemin déclenchera un rechargement du composant avec les nouvelles données.

3
Gkiokan

voici ce que je suis venu avec:

import ProjectMain from './templates/ProjectMain.vue';
import SidebarProject from './templates/SidebarProject.vue';

// copie maintenant peu profonde les objets pour que les nouveaux objets soient traités comme des fichiers .vue séparés avec: $.extend({}, OriginalObject); // c'est pourquoi je n'ai pas à créer fondamentalement les mêmes fichiers .vue, mais Vue-router rechargera ces fichiers parce qu'ils sont différents

const ProjectMainA = $.extend({}, ProjectMain);
const ProjectMainB = $.extend({}, ProjectMain);
const ProjectMainC = $.extend({}, ProjectMain);
const SidebarProjectA = $.extend({}, SidebarProject);
const SidebarProjectB = $.extend({}, SidebarProject);
const SidebarProjectC = $.extend({}, SidebarProject);

const routes = [
{
path: "/myapps/newproject",
components: {
default: ProjectMainA,
"breadcrumbs": BreadcrumbsNewProject,
"sidebar": SidebarProjectA
}
},
{
path: "/myapps/:id",
components: {
default: ProjectMainB,
"breadcrumbs": BreadcrumbsCurrentProject,
"sidebar": SidebarProjectB
}
},
{
path: "/myapps/newversion/:id",
components: {
default: ProjectMainC,
"breadcrumbs": BreadcrumbsNewVersion,
"sidebar": SidebarProjectC
}
}
];

Ceci incite essentiellement le routeur à penser qu’il charge différents composants .vue, mais ils sont en fait les mêmes. Donc, je reçois tout ce que je veux: rechargement du composant, animation, cycle de vie, et je n’ai pas à écrire plusieurs composants similaires ou identiques. Qu'en pensez-vous, je ne suis pas sûr si cela est la meilleure pratique.

1
Dario Huzjak