[javascript] 기록에 추가하지 않고 vue-router로 푸시하는 방법은 무엇입니까?

다음과 같은 순서로 진행됩니다.

  • 메인 화면

  • 로딩 화면

  • 결과 화면

홈페이지에서 누군가가 버튼을 클릭하면 다음을 통해 로딩 화면으로 보냅니다.

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사실이거나 resultsnull 인 경우 원하는 경우 가짜 데이터 세트를 만들어 골격 버전을 반복하고 만들 수 있습니다. 그렇지 않으면, 당신이 가진 그대로 물건을 유지할 수 있습니다.


답변

또 다른 옵션은 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에는 구현하기 쉬운 예제가 있습니다.


답변