Vue 全站緩存之 vue-router-then 實現原理

系列篇1:Vue 全站緩存之 keep-alive : 動態移除緩存javascript

系列篇2:Vue 全站緩存二:如何設計全站緩存html

系列篇3:Vue 全站緩存之 vue-router-then :先後頁數據傳遞vue

本篇爲系列篇4:Vue 全站緩存之 vue-router-then :實現原理java

前言

就效果而言,我很滿意v-model-link指令帶來的開發效率的提高,不過 vue-router-then 這個插件自己的代碼實現得有點粗暴,總以爲本身對 vue 的理解仍是比較膚淺,有時候看別人家的文章總有不明覺厲的感嘆,然而正如我在知乎專欄在博客的自我介紹裏所說,高樓大廈平地起,咱也想加上一塊磚,本身這三板斧該獻醜仍是獻醜,拋磚引玉也行的。node

活着纔有 DPS

從第一篇文章Vue 全站緩存之 keep-alive : 動態移除緩存開始,咱們就一直在強調如何去實現頁面緩存,vue-router-then 正是創建在頁面緩存成功的基礎之上的功能,若是你不能正確的使用頁面緩存功能,或者說頁面緩存被銷燬了,vue-router-then 也就沒有意義了。vue-router

實現原理

這個插件的原理說開了實現得很是粗暴,說白了就是一句話:在路由跳轉事件裏給新頁面組件綁事件。promise

返回一個 promise

在this.$router系列方法的基礎之上,包裝一個 promise ,並將 resolve 方法給存儲起來。緩存

const routerThen = {
        '$router':null,
        resolve:null,
        //跳到指定頁面,並返回promise
        request:function(requestType='push', location, onComplete=null, onAbort=null){
            if (!location || location=='')
            {
                throw new Error('location is missing');
            }
            return new Promise( (resolve, reject)=>{
                if (this.$router)
                {
                    console.log('this.$router',this.$router);
                    this.resolve = resolve;
                    switch (requestType)
                    {
                        case 'push':
                            this.$router.push(location, onComplete, onAbort);
                            break;
                        case 'replace':
                            this.$router.replace(location, onComplete, onAbort);
                            break;
                        case 'go':
                            this.$router.go(location);
                            break;
                        default:
                            reject('requestType error:'+requestType);
                            break;
                    }
                }
                else
                {
                    reject('$router missing');
                }
            }).catch(error=>{
                this.resolve = null;
                throw new Error(error);
            });
        },
複製代碼

在路由事件裏夾點私貨

上文裏,將 resolve 存好後,頁面就應該開始跳轉了,此時能夠捕捉路由事件,在新頁面載入後,將新頁面對象 vm回調給 promise 。post

Vue.mixin({
            // 在路由跳轉到下一個頁面以前,爲下一個頁面註冊回調事件。
            beforeRouteEnter:function(to, from, next){
                if (routerThen.resolve)
                {
                    next(vm=>{
                            routerThen.resolve(vm);
                            routerThen.resolve = null;
                    });
                }
                else
                {
                    next();
                }
            },
            beforeRouteUpdate:function(to, from, next){
                if (routerThen.resolve)
                {
                    routerThen.resolve(this);
                    routerThen.resolve = null;
                }
                next();
            },
        });
複製代碼

拿到頁面對象啥都好辦了

好比,modelLink方法,其實就是拿到 vm 對象給它塞了個 input 事件。ui

modelLink:function(link, el=null){
            return this.push(link).then(vm=>{
                vm.$once('input',value=>{
                    if (typeof el == 'function')
                    {
                        el(value);
                    }
                    else if (typeof el == 'object')
                    {
                        if (el.$emit)
                        {
                            el.$emit('input',value);
                        }
                        else if (el.tagName)
                        {
                            el.value = value;
                            const e = document.createEvent('HTMLEvents');
                            // e.initEvent(binding.modifiers.lazy?'change':'input', true, true);
                            e.initEvent('input', true, true);
                            el.dispatchEvent(e);
                        }
                    }
                });
                return vm;
            })
        },
複製代碼

v-model-link 只是一個語法糖

我很喜歡語法糖這個概念,複雜的事簡單化。

clickElFun:function(event){
            let link = this.getAttribute('model-link');
            if (link)
            {
                console.log(this);
                return routerThen.modelLink(link,this.vnode && this.vnode.componentInstance?this.vnode.componentInstance:this);
            }
            return Promise.resolve();
        },

    Vue.directive('model-link',  function (el, binding, vnode) {
            el.binding = binding;
            el.vnode   = vnode;
            el.setAttribute('model-link',binding.value);
            el.removeEventListener('click',routerThen.clickElFun);
            el.addEventListener('click',routerThen.clickElFun);
        });
複製代碼

後語

仍是那句話,這個代碼有點粗暴,做拋磚引玉,供你們參考。

我很喜歡全站緩存這個理念,在目前 vue 社區裏相似的文章不多看到,但願能有更多朋友參與進來,挖掘其中的亮點。

END

我最近還在研究全站緩存狀況下跨多級頁面的數據共用和更新的狀況,感受會頗有意思,敬請期待,此次時間須要久一點。

原文來自阿星的博客:wanyaxing.com/blog/201807…

相關文章
相關標籤/搜索