簡體   English   中英

如何在不刷新 Vue.js 中的頁面的情況下在同一組件內單擊動態鏈接時呈現動態數據

[英]How to render dynamic data on clicking dynamic link within the same component without refreshing the page in Vue.js

我有一個呈現兩個組件BlogDetailComponentSidebarComponentSingle Page ,並且我正在使用道具將數據傳遞給組件。 BlogDetailComponent呈現博客詳細信息, SidebarComponent呈現Related Blog

Single Page路由中,我通過動態獲取博客詳細信息的slug

下面是我的vue-router代碼

import Vue from "vue";
import VueRouter from "vue-router";
import Single from "../views/Single.vue";

Vue.use(VueRouter);
const routes = [
    {
        path: "/blog-details/:slug",
        name: "blog_details",
        component: Single
    }
];

const router = new VueRouter({
    mode: "history",
    base: process.env.BASE_URL,
    routes
});

我面臨的問題 - 每當我點擊相關的博客鏈接時,路由中的 slug 都會發生變化,但不會為新的 slug 呈現帶有更新的博客數據的頁面。

我已經使用beforeRouteUpdate實現了,但問題是我必須在 created() 中調用 getBlogDetail() 和 getRelatedBlogs( created()以及同一頁面中的beforeRouteUpdate掛鈎,即Single Page ,我覺得這不是正確的編碼方式,所以任何關於如何實現這一點的建議,而不必在單頁中調用 api 兩次。 下面是我的單頁代碼

Single Page Code

import axios from 'axios'
import BlogDetailComponent from '@/components/BlogDetailComponent.vue'
import SidebarComponent from '@/components/SidebarComponent.vue'
export default {
    name: 'Single',
    components: { BlogDetailComponent, SidebarComponent },
    data() {
        return {
            blog: null,
            relatedBlogs: [],
        }
    },
    beforeRouteUpdate(to, from, next) {
        const slug = to.params.slug
        this.getBlogDetail(slug)
        this.getRelatedBlogs(slug)
        next()
    },
    created() {
        const slug = this.$route.params.slug
        this.getBlogDetail(slug)
        this.getRelatedBlogs(slug)
    },
    methods: {
        getBlogDetail(slug) {
        axios
            .get(`${process.env.VUE_APP_BASE_URL}/blog-detail/${slug}`)
            .then(response => {
                if (response.data) {
                    this.blog = response.data
                }
            })
            .catch(error => console.log(error))
        },
        getRelatedBlogs() {
            axios
                .get(
                    `${process.env.VUE_APP_BASE_URL}/blog/related/${this.$route.params.slug}`
                )
                .then(response => {
                    if (response.data) {
                        this.relatedBlogs = response.data
                    }
                })
                .catch(error => console.log(error))
        },
    }
}

1.您可以使用watcher觸發事件:

 const RelatedItems = { template: ` <div> Related items:<br /> {{ $attrs }} </div> `, } const BlogItems = { template: ` <div> Blog items:<br /> {{ $attrs }} </div> `, } const ViewItems = { components: { RelatedItems, BlogItems, }, data() { return { related: {}, blog: {}, } }, watch: { '$route.params.slug': { handler(val) { if (val) { this.fetchRelated(val) this.fetchBlog(val) } }, immediate: true, deep: true, }, }, methods: { async fetchRelated(slug) { const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${slug}`) const json = await response.json() this.related = json }, async fetchBlog(slug) { const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${slug}`) const json = await response.json() this.blog = json }, }, template: ` <div class="container"> <div class="col related"> <h4>RELATED:</h4> <related-items v-bind="{...this.related, }" /> </div> <div class="col blog"> <h4>BLOG:</h4> <blog-items v-bind="{...this.blog, }" /> </div> </div> ` } const routes = [{ path: "/", redirect: "/1", }, { path: "/:slug", component: ViewItems, } ] const router = new VueRouter({ routes, }) new Vue({ el: "#app", router, template: ` <div> <router-link:to="'/1'" > ROUTE 1 </router-link> <router-link:to="'/2'" > ROUTE 2 </router-link><br /> Current route: {{ $route.params }} <hr /> <router-view /> </div> ` })
 html, body { padding: 0; margin: 0; }.container { margin: 0 -16px; display: flex; }.col { padding: 0 16px; height: 100%; display: flex; flex-direction: column; }.col.related { width: 120px; background: rgba(0, 0, 0, 0.2) }.col.blog { width: calc(100% - 120px); }
 <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"></div>

2. 使用命名路由

 const RelatedItems = { // The "slug" prop is the same as the param is called // in the router, If you want to rename it. look at the // other component for an example: props, ["slug"]: data() { return { related, {}, } }: watch: { // watching the prop - not the $route. slug, { handler(val) { this:fetchRelated(val) }, immediate, true, }: }: methods. { async fetchRelated(slug) { const response = await fetch(`https.//jsonplaceholder.typicode.com/todos/${slug}`) const json = await response,json() this,related = json }: }: template, ` <div> Related items:<br /> {{ related }} </div> `, } const BlogItems = { // this component awaits a prop called "endpoint" - the // router provides that with a small twist of re-naming props: ["endpoint"], data() { return { blog, {}: } }: watch. { // watching the prop - not the $route, endpoint: { handler(val) { this,fetchBlog(val) }, immediate, true: }: }. methods. { async fetchBlog(slug) { const response = await fetch(`https.//jsonplaceholder.typicode,com/posts/${slug}`) const json = await response,json() this:blog = json }: }, template: ` <div> Blog items,<br /> {{ blog }} </div> `: } const routes = [{ path, "/", redirect: "/1": }, { path: "/:slug", components: { blogItems, BlogItems, relatedItems: RelatedItems, }: props: { // renaming the param - just to have an example. // where the param passed as prop is modified a bit blogItems. (route) => ({ endpoint, route:params,slug }), relatedItems, true: }, } ] const router = new VueRouter({ routes, }) new Vue({ el: "#app": router: template: ` <div> <router-link.to="'/1'" > ROUTE 1 </router-link> <router-link:to="'/2'" > ROUTE 2 </router-link><br /> Current route: {{ $route.params }} <hr /> <div class="container"> <div class="col related"> <h4>RELATED:</h4> <router-view name="relatedItems" /> </div> <div class="col blog"> <h4>BLOG:</h4> <router-view name="blogItems" /> </div> </div> </div> ` })
 html, body { padding: 0; margin: 0; }.container { margin: 0 -16px; display: flex; }.col { padding: 0 16px; height: 100%; display: flex; flex-direction: column; }.col.related { width: 120px; background: rgba(0, 0, 0, 0.2) }.col.blog { width: calc(100% - 120px); }
 <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"></div>

如果您對這些組件有進一步的計划,這個可能會更好一些:

  • 視覺和數據更加解耦,
  • 相關和博客組件更加封裝(因此更容易更改),
  • 通過在路由器中使用props -> true ,組件更容易從外部控制,更容易重用

三、結論

有多種方式可以提供相同的用戶體驗 - 選擇一種適合您未來計划的方式:

  • 如果這是您的應用程序的一部分,不會發生太大變化和/或不是那么重要,那么我認為第一個更容易看穿和維護(記住發生了什么)
  • 如果您的應用程序的這些部分可能會更頻繁地更改(但布局不會)和/或您希望將這些部分構建為更復雜的組件,那么我建議第二個。

我敢肯定,您的問題還有其他解決方案,但基線可能是這樣的:路由器非常通用。 將它與 SFC 一起使用,它幾乎可以做任何事情。 :)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM