Solución:
Hay una manera perfecta de manejar esta situación.
Puede utilizar la protección en el componente para controlar la ruta en el nivel de gránulos
Realice los siguientes cambios en su código
En el componente de la pantalla principal
Agregue este beofreRouteLeave guard en las opciones del componente, antes de salir a la ‘pantalla de resultados’, está configurando la ruta para que pase solo por la pantalla de carga
beforeRouteLeave(to, from, next) {
if (to.path == "/result") {
next('/loading')
}
next();
},
En el componente de la pantalla de carga
Si la ruta vuelve del resultado a la carga, no debería aterrizar aquí y saltar directamente a la pantalla principal.
beforeRouteEnter(to, from, next) {
if (from.path == "/result") {
next('/main')
}
next();
},
En la pantalla de carga, el guardia beforeRouteEnter NO tiene acceso a esto, porque se llama al guardia antes de que se confirme la navegación, por lo que el nuevo componente de entrada aún no se ha creado. Entonces, aprovechando esto, no recibiré las llamadas infinitas disparado al enrutar desde la pantalla de resultados
En el componente de pantalla de resultados
si usa volver, entonces no debería aterrizar en la carga y saltar directamente a la pantalla principal
beforeRouteLeave(to, from, next) {
if (to.path == "/loading") {
next("https://foroayuda.es/")
}
next();
},
Acabo de crear una pequeña aplicación vue para reproducir el mismo problema. Funciona en mi local según su pregunta. Espero que resuelve tu problema así como.
Esta es una decisión difícil considerando lo poco que sabemos sobre lo que ocurre en su ruta de carga.
Pero…
Nunca tuve la necesidad de construir una ruta de carga, solo cargar componentes que se procesan en múltiples rutas durante la etapa de inicio / recopilación de datos.
Un argumento para no tener una ruta de carga sería que un usuario podría navegar directamente a esta URL (accidentalmente) y luego parece que no tendría suficiente contexto para saber dónde enviar al usuario o qué acción tomar. Aunque esto podría significar que se cae a una ruta de error en este punto. En general, no fue una gran experiencia.
Otra es que si simplifica sus rutas, la navegación entre rutas se vuelve mucho más simple y se comporta como se espera / desea sin el uso de $router.replace
.
Entiendo que esto no resuelve la pregunta de la forma en que lo hace. Pero sugiero repensar esta ruta de carga.
Aplicación
<shell>
<router-view></router-view>
</shell>
const routes = [
{ path: "https://newbedev.com/", component: Main },
{ path: '/results', component: Results }
]
const router = new VueRouter({
routes,
})
const app = new Vue({
router
}).$mount('#app')
Cascarón
<div>
<header>
<nav>...</nav>
</header>
<main>
<slot></slot>
</main>
</div>
Pagina principal
<section>
<form>...</form>
</section>
{
methods: {
onSubmit() {
// ...
this.$router.push('/results')
}
}
}
Página de resultados
<section>
<error v-if="error" :error="error" />
<results v-if="!error" :loading="loading" :results="results" />
<loading v-if="loading" :percentage="loadingPercentage" />
</section>
{
components: {
error: Error,
results: Results,
},
data() {
return {
loading: false,
error: null,
results: null,
}
},
created () {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
fetchData () {
this.error = this.results = null
this.loading = true
getResults((err, results) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.results = results
}
})
}
}
}
Componente de resultados
Básicamente, el mismo componente de resultados que ya tiene, pero si loading
es cierto, o si results
es nulo, como lo prefiera, puede crear un conjunto de datos falso para iterar y crear versiones de esqueleto, si lo desea. De lo contrario, puede mantener las cosas como las tiene.
creo router.replace
es el camino a seguir, pero aún hay algunas líneas de pensamiento (no probadas):
Básicamente en $router
cambiar renderiza el componente de carga hasta que emite load:stop
, luego hace que el router-view
import { Vue, Component, Watch, Prop } from "vue-property-decorator";
@Component<RouteLoader>({
render(h){
const rv = (this.$slots.default || [])
.find(
child => child.componentOptions
//@ts-ignore
&& child.componentOptions.Ctor.extendedOptions.name === "RouterView"
)
if(rv === undefined)
throw new Error("RouterView is missing - add <router-view> to default slot")
const loader = (this.$slots.default || [])
.find(
child => child.componentOptions
//@ts-ignore
&& child.componentOptions.Ctor.extendedOptions.name === this.loader
)
if(loader === undefined)
throw new Error("LoaderView is missing - add <loader-view> to default slot")
const _vm = this
const loaderNode = loader.componentOptions && h(
loader.componentOptions.Ctor,
{
on: {
// "load:start": () => this.loading = true,
"load:stop": () => _vm.loading = false
},
props: loader.componentOptions.propsData,
//@ts-ignore
attrs: loader.data.attrs
}
)
return this.loading && loaderNode || rv
}
})
export default class RouteLoader extends Vue {
loading: boolean = false
@Prop({default: "LoaderView"}) readonly loader!: string
@Watch("$route")
loads(nRoute: string, oRoute: string){
this.loading = true
}
}
@Component<Loader>({
name: "LoaderView",
async mounted(){
await console.log("async call")
this.$emit("load:stop")
// this.$destroy()
}
})
export class Loader extends Vue {}