Tarihe eklemeden vue-router'a nasıl aktarılır?


12

Aşağıdaki sıraya giriyorum:

  • Ana ekran

  • Yükleme ekranı

  • Sonuçlar ekranı

Ana sayfada, birisi bir düğmeyi tıkladığında, yükleme ekranına gönderirim:

this.$router.push({path: "/loading"});

Görevleri bittiğinde, sonuçlar ekranına

this.$router.push({path: "/results/xxxx"});

Sorun, genellikle sonuçlardan ana ekrana geri dönmek isterler, ancak geri tıkladıklarında, tekrar yüklemeye gönderilirler, bu da onları sonuçlara geri gönderir, böylece sonsuz bir döngüye yapışırlar ve geri dönemezler ana ekrana dönün.

Bunu nasıl düzeltebileceğine dair bir fikrin var mı? İdeal olarak şöyle bir seçenek olsaydı:

this.$router.push({path: "/loading", addToHistory: false});

bu da onları tarihe eklemeden rotaya gönderir.


5
this.$router.replace({path: "/results/xxxx"})
Roland Starke

@RolandStarke Teşekkürler - bu geri düğmesinin çalışmasını sağlar ve ana menüye geri döner, ancak ileri düğmesini kaybederim ve tekrar ileri gidemem - herhangi bir fikir?
Oyla tıklayın

İşlem: Ana menü, Yükleniyor, Sonuçlar. Loading'den arıyorum $router.replace. Bu, şimdi Sonuçlar -> Ana sayfamdan geri dönmeme izin veriyor ancak sonuçlara ilerleyemiyorum.
Oyla tıklayın

Başka bir seçenek de bir yükleme rotasının olmamasıdır. Bunun yerine, doğrudan veri getirilen sonuç yoluna gidin ve tamamlanıncaya kadar bir yükleme görünümü oluşturur. Sonra yeniden yönlendirme ve geçmiş yoktur ve kullanıcı akışı $ router.replace olmadan sağlam kalmalıdır.
ArrayKnight

@ClickUpvote bu soruna herhangi bir çözüm buldunuz mu?
chans

Yanıtlar:


8

Bu durumu ele almanın mükemmel bir yolu var

Sen kullanabilirsiniz bekçi bileşenli içinde granül düzeyde rotayı kontrol etmek

Kodunuzda aşağıdaki değişiklikleri yapın

Ana ekran bileşeninde

Bu beofreRouteLeave korumasını bileşen seçeneklerine ekleyin, 'sonuç ekranına' ayrılmadan önce rotayı yalnızca yükleme ekranından geçecek şekilde ayarlıyorsunuz

beforeRouteLeave(to, from, next) {
   if (to.path == "/result") {
      next('/loading')
    }
    next();
  }, 

Yükleme ekranı bileşeninde

Rota sonuçtan yüklemeye geri dönerse, buraya inmemeli ve doğrudan ana ekrana atlamamalıdır

beforeRouteEnter(to, from, next) {
    if (from.path == "/result") {
      next('/main')
    }
     next();
  },

Yükleme ekranında, navigasyon onaylanmadan önce guard çağrıldığından, beforeRouteEnter korumasının buna erişimi YOK, bu nedenle yeni giriş bileşeni henüz oluşturulmadı. Bu nedenle, avantajdan yararlanarak, sonuç ekranından yönlendirirken sonsuz aramaları tetiklemezsiniz

Sonuç ekranı bileşeni

geri gitmek kullanırsanız o zaman yükleme inip doğrudan ana ekrana atlamamalıdır

beforeRouteLeave(to, from, next) {
    if (to.path == "/loading") {
      next('/')
    }
    next();
  },

Aynı sorunu yeniden oluşturmak için küçük bir vue uygulaması oluşturdum. Sorunuza göre yerelimde çalışıyor. Umarım sorununuzu da çözer .


2
Bu çözüm kırılgandır (bakım teknolojisi borcunu getirir) ve bu işlevselliğe ihtiyaç duyabileceğiniz olası her rota için giriş gerektirir.
ArrayKnight

Tamamen katılıyorum, ben bu çözümü hiç sevmiyorum
omarjebari

2

Sanırım router.replacegitmek için bir yol - ama yine de bazı düşünce hatları (denenmemiş):


Temel olarak $routerdeğişiklik üzerine yükleme bileşenini yayılana kadar load:stop, daha sonrarouter-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 {}

Bu, bahsettiğim bir tür uygulama olsa da, bir yükleme izleme sarmalayıcısı oluşturmak yerine yükleme bileşenimi doğrudan sayfa bileşenlerime uygulama eğilimindeyim. Nedeni: Kullanıcıya ne bekleyebileceğine dair görsel geri bildirim vermek ve daha sonra yükleme bileşenini (tüm eylemleri engellemesi gerekiyorsa) yerleştirmek veya satır içi ise, satır içi içerik bileşeninin yarı yüklü bir duruma yüklendiği iskelet yaklaşımını kullanmayı seviyorum. kullanıcı veri yüklerken kullanıcı arayüzünü kullanabilir. Her şey kullanıcının hız algısı ve istediklerini olabildiğince çabuk yapma yeteneklerinin engellenmesi ile ilgilidir.
ArrayKnight

@ArrayKnight düşünme soyut biri sadece yönlendirici görünümü bileşeni karşılık gelen rota bileşeni ile alışverişi yapabilirsiniz ve bir tür yükleyici sarıcı alır - ama ben yükleyici rotaya koyarak kabul kötü tasarım gibi geliyor
Estradiaz

2

Bu, yükleme rotanızda olup bitenler hakkında ne kadar az şey bildiğimizi düşünmek zor bir çağrı.

Fakat...

Bir yükleme rotası oluşturmaya hiç ihtiyacım olmadı, sadece init / veri toplama aşamasında birden fazla rotada işlenen bileşenler yükleniyor.

Bir yükleme rotasına sahip olmamanın bir argümanı, bir kullanıcının potansiyel olarak doğrudan bu URL'ye (yanlışlıkla) gidebileceği ve daha sonra kullanıcıyı nereye göndereceğini veya hangi işlemi yapacağını bilmek için yeterli içeriğe sahip olmayacağıdır. Bu, bu noktada bir hata yoluna düştüğü anlamına gelebilir. Genel olarak, büyük bir deneyim.

Bir diğeri, rotalarınızı basitleştirirseniz, rotalar arasında gezinmenin çok daha basit hale gelmesi ve kullanılmadan beklendiği / istendiği gibi davranmasıdır $router.replace.

Bunun soruyu sorduğunuz şekilde çözmediğini anlıyorum. Ancak bu yükleme rotasını yeniden düşünmenizi öneririm.

Uygulama

<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')

Kabuk

<div>
    <header>
        <nav>...</nav>
    </header>
    <main>
        <slot></slot>
    </main>
</div>

Ana Sayfa

<section>
    <form>...</form>
</section>

{
    methods: {
        onSubmit() {
            // ...

            this.$router.push('/results')
        }
    }
}

Sonuçlar Sayfası

<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
                }
            })
        }
    }
}

Sonuçlar Bileşeni

Temel olarak, zaten sahip olduğunuz sonuçlarla aynıdır, ancak loadingdoğruysa veya resultsnull ise, ancak tercih ederseniz, yinelemek için sahte bir veri kümesi oluşturabilir ve isterseniz iskelet sürümleri oluşturabilirsiniz. Aksi takdirde, işleri sahip olduğunuz şekilde tutabilirsiniz.


Sahip olduğum yükleme ekranı tüm ekranı kaplıyor, bu yüzden kendi rotası olmadan onu görüntülemenin bir yolunu düşünemiyorum. Canlı bir demo için naminator.io adresine bakın . Bunu yapmak için başka fikirlere açık.
Upvote

Sabah uygun bir şekilde bakacağım, ama ilk düşüncem, ekranı ele geçirmek için sabit pozisyonu kullanamamanın bir nedeni yok.
ArrayKnight

Tasarımınıza bakıldığında, birkaç seçenek var gibi görünüyor: yükleyiciyi sonuç içeriği yerine oluşturabilir ve ardından veriler getirildikten sonra geçiş yapabilirsiniz; veya sonuçlarınızın bir iskeletinin yükleyicisini kaplayabilir ve ardından sonuçları güncelleyip doldurabilir ve yükleyiciyi kaldırabilirsiniz. Yükleyicinin başlığı (site kabuğu) kapsamadığını göz önünde bulundurarak, sabit konuma ihtiyacınız olmamalıdır.
ArrayKnight

@ClickUpvote bu yaklaşım hakkında ne düşündüğünüzü bana bildirin.
ArrayKnight

@ ArrayKnight, soru zaten yolları uygulanmış ve beklendiği gibi çalışıyor, bu yükleme yaklaşımı buraya uygun olmayabilir, ben de aynı durumdan olmuştur. Yükleme yolunda ayrıca ödeme ağ geçidi veya bazı form gönderme işlemleri gibi bir form gönderme isteği olabilir. Bu senaryoda, bir rotayı kaldırmayı içeremeyiz. Ama hala vue yönlendirici seviyesinde korumalara girmeden önce sahip olabiliriz, Neden bu yaklaşımı önerdim, yükleme bileşeninin vue örneği henüz bu kancada oluşturulmadı ve bu rotaya girip girmeyeceğine karar vermenin avantajı
chans


0

Bu beforeEach, yönlendiricinin kancasıyla yapılabilir .

Yapmanız gereken şey, loadingveri yüklendiğinde ( resultsbileşene yeniden yönlendirmeden önce ) bir değişkeni bileşene global olarak veya localStorage'a kaydetmenizdir :

export default {
  name: "results",
  ...
  importantTask() {
    // do the important work...
    localStorage.setItem('DATA_LOADED', JSON.stringify(true));
    this.$router.push({path: "/results/xxxx"});
  }
}

Ve sonra beforeEach kancasında bu değişkeni kontrol etmeli ve doğru bileşene atlamalısınız:

// 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();
});

Ayrıca, mainsorgu düğmesi tıklatıldığında ( loadingbileşene yönlendirmeden önce ) değeri bileşeninizde false olarak sıfırlamayı unutmayın :

export default {
  name: "main",
  ...
  queryButtonClicked() {
    localStorage.setItem('DATA_LOADED', JSON.stringify(false));
    this.$router.push({path: "/loading"});
  }
}

Bu çözüm kırılgandır (bakım teknolojisi borcunu getirir) ve bu işlevselliğe ihtiyaç duyabileceğiniz olası her rota için giriş gerektirir.
ArrayKnight

0

Yükleme ekranınız vue-router tarafından hiç kontrol edilmemelidir. En iyi seçenek, yükleme ekranınız için javascript tarafından kontrol edilen bir mod / yer paylaşımı kullanmaktır. Vue için birçok örnek var. Bir şey bulamazsanız, vue-bootstrap uygulamak için bazı kolay örneklere sahiptir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.