다음과 같은 순서로 진행됩니다.
-
메인 화면
-
로딩 화면
-
결과 화면
홈페이지에서 누군가가 버튼을 클릭하면 다음을 통해 로딩 화면으로 보냅니다.
this.$router.push({path: "/loading"});
작업이 완료되면 다음을 통해 결과 화면으로 전송됩니다.
this.$router.push({path: "/results/xxxx"});
문제는 일반적으로 결과에서 기본 화면으로 돌아가고 싶지만 다시 클릭하면 다시로드로 전송되어 결과로 다시 전송되므로 무한 루프에 빠지고 갈 수 없습니다 메인 화면으로 돌아갑니다.
이 문제를 해결하는 방법에 대한 아이디어가 있습니까? 다음과 같은 옵션이 있다면 이상적으로 싶습니다.
this.$router.push({path: "/loading", addToHistory: false});
역사에 추가하지 않고 경로로 보낼 것입니다.
답변
이 상황을 처리하는 완벽한 방법이 있습니다
부품 내 가드 를 사용하여 과립 수준에서 경로를 제어 할 수 있습니다.
코드를 다음과 같이 변경하십시오.
메인 화면 구성 요소
구성 요소 옵션에이 beofreRouteLeave guard를 추가하십시오.
beforeRouteLeave(to, from, next) {
if (to.path == "/result") {
next('/loading')
}
next();
},
화면 구성 요소로드 중
경로가 결과에서로드로 되돌아가는 경우 여기에 착륙해서는 안되고 직접 메인 화면으로 이동하면 안됩니다
beforeRouteEnter(to, from, next) {
if (from.path == "/result") {
next('/main')
}
next();
},
로딩 화면에서 beforeRouteEnter 가드에는이 액세스 권한이 없습니다. 내비게이션이 확인되기 전에 가드가 호출되어 새 입력 구성 요소가 아직 작성되지 않았기 때문입니다. 따라서이를 활용하면 결과 화면에서 라우팅 할 때 무한 호출이 발생 하지 않습니다.
결과 화면 구성 요소
뒤로 이동을 사용하면 로딩 중에 착륙하지 않고 직접 메인 화면으로 이동해야합니다
beforeRouteLeave(to, from, next) {
if (to.path == "/loading") {
next('/')
}
next();
},
동일한 문제를 재현하기 위해 작은 vue 응용 프로그램을 만들었습니다. 귀하의 질문에 따라 현지에서 작동합니다. 희망은 당신의 문제를 해결 뿐만 아니라.
답변
나는 router.replace
갈 길이라고 생각하지만 여전히 몇 가지 생각의 줄 (unested) :
기본적으로 $router
변경되면 로딩 구성 요소가 방출 될 때까지 load:stop
렌더링 한 다음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 {}
답변
로딩 경로에서 무슨 일이 일어나고 있는지에 대해 우리가 아는 것이 거의 없다는 점을 고려하면 힘든 전화입니다.
그러나…
로드 / 라우팅을 구축 할 필요가 없었으며, 초기화 / 데이터 수집 단계에서 여러 경로에서 렌더링되는 구성 요소 만로드했습니다.
로딩 경로가 없다는 한 가지 주장은 사용자가 잠재적으로이 URL로 직접 이동할 수 있다는 것입니다. 그러면 사용자를 어디로 보낼지 또는 어떤 조치를 취할지 알 수있는 컨텍스트가 충분하지 않은 것 같습니다. 이 시점에서 오류 경로로 넘어가는 것을 의미 할 수 있습니다. 전반적으로 좋은 경험은 아닙니다.
또 다른 방법은 경로를 단순화하면 경로 간 탐색이 훨씬 단순 해지고를 사용하지 않고 예상대로 작동하는 것입니다 $router.replace
.
나는 이것이 당신이 요구하는 방식으로 질문을 해결하지 못한다는 것을 이해합니다. 그러나이로드 경로를 다시 생각하는 것이 좋습니다.
앱
<shell>
<router-view></router-view>
</shell>
const routes = [
{ path: '/', component: Main },
{ path: '/results', component: Results }
]
const router = new VueRouter({
routes,
})
const app = new Vue({
router
}).$mount('#app')
껍질
<div>
<header>
<nav>...</nav>
</header>
<main>
<slot></slot>
</main>
</div>
메인 페이지
<section>
<form>...</form>
</section>
{
methods: {
onSubmit() {
// ...
this.$router.push('/results')
}
}
}
결과 페이지
<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
}
})
}
}
}
결과 구성 요소
기본적으로 이미 가지고있는 것과 동일한 결과 구성 요소이지만 loading
사실이거나 results
null 인 경우 원하는 경우 가짜 데이터 세트를 만들어 골격 버전을 반복하고 만들 수 있습니다. 그렇지 않으면, 당신이 가진 그대로 물건을 유지할 수 있습니다.
답변
또 다른 옵션은 History API 를 사용하는 것 입니다.
결과 화면에 있으면 ReplaceState 를 사용 하여 브라우저 기록에서 URL을 바꿀 수 있습니다 .
답변
이것은 beforeEach
라우터 의 후크 로 수행 할 수 있습니다 .
loading
데이터를로드 할 때 ( results
구성 요소로 리디렉션하기 전에) 구성 요소의 전역 또는 localStorage에 변수를 저장해야합니다 .
export default {
name: "results",
...
importantTask() {
// do the important work...
localStorage.setItem('DATA_LOADED', JSON.stringify(true));
this.$router.push({path: "/results/xxxx"});
}
}
그런 다음 beforeEach 후크에서이 변수를 확인하고 올바른 구성 요소로 건너 뛰십시오.
// router.js...
router.beforeEach((to, from, next) => {
const dataLoaded = JSON.parse(localStorage.getItem('DATA_LOADED'));
if (to.name === "loading" && dataLoaded)
{
if (from.name === "results")
{
next({ name: "main"} );
}
if (from.name === "main")
{
next({ name: "results"} );
}
}
next();
});
또한 main
구성 요소로 라우팅하기 전에 쿼리 버튼을 클릭 할 때 구성 요소 에서 값을 false로 다시 설정해야합니다 loading
.
export default {
name: "main",
...
queryButtonClicked() {
localStorage.setItem('DATA_LOADED', JSON.stringify(false));
this.$router.push({path: "/loading"});
}
}
답변
로딩 화면은 vue-router로 전혀 제어해서는 안됩니다. 가장 좋은 옵션은 자바 스크립트로 제어되는 로딩 화면에 모달 / 오버레이를 사용하는 것입니다. vue에 대한 많은 예제가 있습니다. 아무것도 찾을 수 없다면 vue-bootstrap에는 구현하기 쉬운 예제가 있습니다.