[英]How to render dynamic data on clicking dynamic link within the same component without refreshing the page in Vue.js
我有一個呈現兩個組件BlogDetailComponent
和SidebarComponent
的Single 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))
},
}
}
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>
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.