單頁面應用中的路由緩存問題
通常我們在進行頁面前后退時,瀏覽器通常會幫我們記錄下之前滾動的位置,這使得我們不會在每次后退的時候都丟失之前的瀏覽器記錄定位。但是在現在愈發流行的SPA(single page application 單頁面應用)中,當我們從父級頁面打開子級頁面,或者從列表頁面進入詳情頁面,此時如果回退頁面,會發現之前我們瀏覽的滾動記錄沒有了,頁面被置頂到了最頂部,仿佛是第一次進入這個頁面一樣。這是因為在spa頁面中的url與路由容器頁面所對應,當頁面路徑與其發生不匹配時,該頁面組件就會被卸載,再次進入頁面時,整個組件的生命周期就會完全重新走一遍,包括一些數據的請求與渲染,所以之前的滾動位置和渲染的數據內容也都完全被重置了。
vue中的解決方式
vue.js最貼心的一點就是提供了非常多便捷的API,為開發者考慮到很多的應用場景。在vue中,如果想緩存路由,我們可以直接使用內置的keep-alive組件,當keep-alive包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。
內置組件keep alive
keep-alive是Vue.js的一個內置組件。它主要用于保留組件狀態或避免重新渲染。
使用方法如下:
<keep-alive :include="['a', 'b']"> <component :is="view"></component></keep-alive>
keep-alive組件會去匹配name名稱為 'a', 'b' 的子組件,在匹配到以后會幫助組件緩存優化該項組件,以達到組件不會被銷毀的目的。
實現原理
先簡要看下keep-alive組件內部實現代碼,具體代碼可以見Vue GitHub
created () { this.cache = Object.create(null) this.keys = []}在created生命周期中會用Object.create方法創建一個cache對象,用來作為緩存容器,保存vnode節點。Tip: Object.create(null)創建的對象沒有原型鏈更加純凈
render () { const slot = this.$slots.default const vnode: VNode = getFirstComponentChild(slot) const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions if (componentOptions) { // check pattern 檢查匹配是否為緩存組件,主要根據include傳入的name來對應 const name: ?string = getComponentName(componentOptions) const { include, exclude } = this if ( // not included 該判斷中判斷不被匹配,則直接返回當前的vnode(虛擬dom) (include && (!name || !matches(include, name))) || // excluded (exclude && name && matches(exclude, name)) ) { return vnode } const { cache, keys } = this const key: ?string = vnode.key == null // same constructor may get registered as different local components // so cid alone is not enough (#3269) ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '') : vnode.key if (cache[key]) { //查看cache對象中已經緩存了該組件,則vnode直接使用緩存中的組件實例 vnode.componentInstance = cache[key].componentInstance // make current key freshest remove(keys, key) keys.push(key) } else { //未緩存的則緩存實例 cache[key] = vnode keys.push(key) // prune oldest entry if (this.max && keys.length > parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode) } } vnode.data.keepAlive = true } return vnode || (slot && slot[0])}
新聞熱點
疑難解答
圖片精選