本篇繼續(xù)介紹vue-router,我們需要要完成這樣個demo:《分頁顯示文章列表》;這里我們以博客園首頁列表為例簡化處理:
按照上圖框選所示,簡單分為藍(lán)色部分文章組件(ArticleItemComponent),橙色框選部分列表組件(ArticleListComponent);分頁部分我們就簡單通過router-link指令構(gòu)建滿足演示即可,我們的代碼實(shí)現(xiàn)邏輯:
1、列表組件初始化數(shù)據(jù),傳遞給文章組件進(jìn)行渲染
2、路由改變時重新初始化列表組件,更新數(shù)據(jù)
請看我們的第一版代碼:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo2</title> <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script> <script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.js"></script> <style> .active{ color: red; } </style></head><body> <div id="app"> <router-link v-for="n in [1,2,3,4,5,6,7,8]" :to="{name:'page',params:{num:n}}" :key="n"> {{n}} </router-link> <div> <router-view> </router-view> </div> </div> <script> var fakeData = []; (function () { for (var i = 0; i < 45; i++) { fakeData.push({ id: i + 1, title: `一步一步學(xué)習(xí)Vue (${i})`, desc: `一步一步學(xué)習(xí)Vue---正文部分 (${i})---正文結(jié)束`, readcount: parseInt(Math.random() * 1000) }) } })(); var ArticleItemComponent = { template: ` <ul class="article-item"> <li>{{item.readcount}}</li> <li>{{item.title}}</li> <li>{{item.desc}}</li> </ul> `, props: ['item'] } var ArticleListComponent = { template: ` <div class="article-list"> <article-item v-for="item in articleList" :item="item" :key="item.id"></article-item> </div> `, data: function () { return { articleList: [] } }, created: function () { this.activePagedData(); }, methods: { activePagedData: function () { var index = this.$route.params.num; //假定每頁五條數(shù)據(jù) var start = (index - 1) * 5, end = index * 5; this.articleList = fakeData.slice(start, end); } }, components: { 'article-item': ArticleItemComponent } } var router = new VueRouter({ linkActiveClass:'active', routes: [ { name: 'page', path: '/page/:num', component: ArticleListComponent } ] }); var app = new Vue({ router: router }).$mount("#app"); </script></body></html>
路由的配置方式上一篇文章中已經(jīng)做過介紹,這里陌生的部分在于ArticleListComponent中的created的使用,一個vue實(shí)例被生成后調(diào)用這個函數(shù)。vue實(shí)例被生成后還要綁定到某個html元素上,之后還要進(jìn)行編譯,然后再插入到document中。每一個階段都會有一個鉤子函數(shù),方便開發(fā)者在不同階段處理不同邏輯;其它鉤子函數(shù)我們在使用的時候會繼續(xù)介紹。一般可以在created函數(shù)中調(diào)用ajax等來獲取頁面初始化所需的數(shù)據(jù)。
雙擊運(yùn)行,效果如下圖所示:
我們發(fā)現(xiàn),就在第一次初始化的時候,文章列表正常顯示出來了,但是后面路由的切換操作,并沒有引起組件的更新或者說數(shù)據(jù)的更新?這是什么原因呢?其實(shí)在vue-router會最大的限度的重用組件,也就是說當(dāng)page/1 and page/2這兩個路徑之間切換的時候,vue-router發(fā)現(xiàn)映射的是同一個組件,那么vue-router就會重用該組件,而不會重新創(chuàng)建它,因?yàn)楸绕痄N毀再創(chuàng)建,復(fù)用則顯得更加高效,所以組件的created鉤子函數(shù)就不會被執(zhí)行,導(dǎo)致數(shù)據(jù)不會更新,從而出現(xiàn)上圖的結(jié)果;對于上述現(xiàn)象vue-router也給我們提供了解決方式,上文提到了在vue-router啟用之后,$route會被注入到任何組件,那么我們就可以監(jiān)聽$roue組件的變化來實(shí)現(xiàn)組件更新,基于此,請看我們的第二版代碼(請看綠色部分)
//....省略其它代碼 var ArticleListComponent = { template: ` <div class="article-list"> <article-item v-for="item in articleList" :item="item" :key="item.id"></article-item> </div> `, data: function () { return { articleList: [] } }, created: function () { this.activePagedData(); }, methods: { activePagedData: function () { var index = this.$route.params.num; //假定每頁五條數(shù)據(jù) var start = (index - 1) * 5, end = index * 5; this.articleList = fakeData.slice(start, end); } }, watch: { '$route': function () { this.activePagedData(); } }, components: { 'article-item': ArticleItemComponent } }//......省略其它
保存后刷新,效果應(yīng)該是這樣的:
這個是一個不大不小的坑,而且這種使用場景我們在實(shí)際生產(chǎn)中也很常見,當(dāng)你發(fā)現(xiàn)路由變化的時候,組件數(shù)據(jù)未更新,可以考慮由于組件重用導(dǎo)致的生命周期鉤子未執(zhí)行的情況,當(dāng)然解決方式也不止這一種,在vue-router 2.2+中也增加了鉤子函數(shù)同樣能解決問題。而且通過watch方式有點(diǎn)侵入,感覺和在angular中使用watch類似,個人不推薦這種寫法;我們簡單修改下我們程序,作為本篇代碼的最后一版本:
var ArticleListComponent = { template: ` <div class="article-list"> <article-item v-for="item in articleList" :item="item" :key="item.id"></article-item> </div> `, data: function () { return { articleList: [] } }, created: function () { this.activePagedData(); }, methods: { activePagedData: function () { var index = this.$route.params.num; //假定每頁五條數(shù)據(jù) var start = (index - 1) * 5, end = index * 5; this.articleList = fakeData.slice(start, end); } }, // watch: { // '$route': function () { // this.activePagedData(); // } // }, beforeRouteUpdate: function (to, from, next) { this.activePagedData(); next(); }, components: { 'article-item': ArticleItemComponent } }
保存后刷新頁面,可以發(fā)現(xiàn)效果和上圖一致。
小結(jié):今天就到這里吧,主要講了一個知識點(diǎn),如何處理vue'-router導(dǎo)致的組件重用問題,組件重用很多場景下提供了很好的性能指標(biāo),畢竟操作dom的代價是很大的,但是總要解決類似上述場景的問題,雖然是一個很小的知識點(diǎn),但值得單獨(dú)放一篇著重說明一下,下一篇會講述生命周期(牽扯到組件生命周期和路由生命周期),敬請期待。
本篇繼續(xù)介紹vue-router,我們需要要完成這樣個demo:《分頁顯示文章列表》;這里我們以博客園首頁列表為例簡化處理:
按照上圖框選所示,簡單分為藍(lán)色部分文章組件(ArticleItemComponent),橙色框選部分列表組件(ArticleListComponent);分頁部分我們就簡單通過router-link指令構(gòu)建滿足演示即可,我們的代碼實(shí)現(xiàn)邏輯:
1、列表組件初始化數(shù)據(jù),傳遞給文章組件進(jìn)行渲染
2、路由改變時重新初始化列表組件,更新數(shù)據(jù)
請看我們的第一版代碼:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>demo2</title> <script src="https://cdn.bootcss.com/vue/2.4.1/vue.js"></script> <script src="https://cdn.bootcss.com/vue-router/2.7.0/vue-router.js"></script> <style> .active{ color: red; } </style></head><body> <div id="app"> <router-link v-for="n in [1,2,3,4,5,6,7,8]" :to="{name:'page',params:{num:n}}" :key="n"> {{n}} </router-link> <div> <router-view> </router-view> </div> </div> <script> var fakeData = []; (function () { for (var i = 0; i < 45; i++) { fakeData.push({ id: i + 1, title: `一步一步學(xué)習(xí)Vue (${i})`, desc: `一步一步學(xué)習(xí)Vue---正文部分 (${i})---正文結(jié)束`, readcount: parseInt(Math.random() * 1000) }) } })(); var ArticleItemComponent = { template: ` <ul class="article-item"> <li>{{item.readcount}}</li> <li>{{item.title}}</li> <li>{{item.desc}}</li> </ul> `, props: ['item'] } var ArticleListComponent = { template: ` <div class="article-list"> <article-item v-for="item in articleList" :item="item" :key="item.id"></article-item> </div> `, data: function () { return { articleList: [] } }, created: function () { this.activePagedData(); }, methods: { activePagedData: function () { var index = this.$route.params.num; //假定每頁五條數(shù)據(jù) var start = (index - 1) * 5, end = index * 5; this.articleList = fakeData.slice(start, end); } }, components: { 'article-item': ArticleItemComponent } } var router = new VueRouter({ linkActiveClass:'active', routes: [ { name: 'page', path: '/page/:num', component: ArticleListComponent } ] }); var app = new Vue({ router: router }).$mount("#app"); </script></body></html>
路由的配置方式上一篇文章中已經(jīng)做過介紹,這里陌生的部分在于ArticleListComponent中的created的使用,一個vue實(shí)例被生成后調(diào)用這個函數(shù)。vue實(shí)例被生成后還要綁定到某個html元素上,之后還要進(jìn)行編譯,然后再插入到document中。每一個階段都會有一個鉤子函數(shù),方便開發(fā)者在不同階段處理不同邏輯;其它鉤子函數(shù)我們在使用的時候會繼續(xù)介紹。一般可以在created函數(shù)中調(diào)用ajax等來獲取頁面初始化所需的數(shù)據(jù)。
雙擊運(yùn)行,效果如下圖所示:
我們發(fā)現(xiàn),就在第一次初始化的時候,文章列表正常顯示出來了,但是后面路由的切換操作,并沒有引起組件的更新或者說數(shù)據(jù)的更新?這是什么原因呢?其實(shí)在vue-router會最大的限度的重用組件,也就是說當(dāng)page/1 and page/2這兩個路徑之間切換的時候,vue-router發(fā)現(xiàn)映射的是同一個組件,那么vue-router就會重用該組件,而不會重新創(chuàng)建它,因?yàn)楸绕痄N毀再創(chuàng)建,復(fù)用則顯得更加高效,所以組件的created鉤子函數(shù)就不會被執(zhí)行,導(dǎo)致數(shù)據(jù)不會更新,從而出現(xiàn)上圖的結(jié)果;對于上述現(xiàn)象vue-router也給我們提供了解決方式,上文提到了在vue-router啟用之后,$route會被注入到任何組件,那么我們就可以監(jiān)聽$roue組件的變化來實(shí)現(xiàn)組件更新,基于此,請看我們的第二版代碼(請看綠色部分)
//....省略其它代碼 var ArticleListCompon
http://www.cnblogs.com/Johnzhang/p/7237065.html