vue:微信單頁(yè)應(yīng)用多入口處理

趕時(shí)間的可以跳到最后看源代碼,看不懂為什么這樣寫(xiě)的回頭來(lái)重新看。

事情要從上個(gè)月說(shuō)起,公司接了個(gè)項(xiàng)目,需要做一個(gè)微信端的應(yīng)用,時(shí)間是兩個(gè)月。

由于之前做過(guò)一個(gè)簡(jiǎn)單的微信商城,非常鄙視微信頁(yè)面跳轉(zhuǎn)時(shí)的拖沓,所以決定做單頁(yè)應(yīng)用,使用vue框架來(lái)開(kāi)發(fā)。

vue是個(gè)不錯(cuò)的框架,加上源碼豐富,一路做來(lái)還算順利,沒(méi)遇到什么特別難的地方。

滿以為下周可以順利上線了,直到要放到微信端的時(shí)候出問(wèn)題了。

客戶需要在公眾號(hào)做一個(gè)這樣的菜單:

QQ圖片20170726001921.png

菜單的入口鏈接到單頁(yè)應(yīng)用的不同頁(yè)面。

而單頁(yè)應(yīng)用的內(nèi)部地址是通過(guò)#后面的內(nèi)容指引router跳轉(zhuǎn)的:
例如跳轉(zhuǎn)到關(guān)于我們的頁(yè)面
http://xxxx.xxx.com/#/about?appid=1&cpid=1

其中appid和cpid是必須的參數(shù),傳給單頁(yè)應(yīng)用后會(huì)賦值給vuex作為全局變量。

但是代碼打包發(fā)布之后,通過(guò)這個(gè)地址死活進(jìn)不去該進(jìn)的頁(yè)面,一律進(jìn)到根目錄下。據(jù)后端人員反映,經(jīng)過(guò)微信瀏覽器傳到服務(wù)器的頁(yè)面地址,#號(hào)連同后面的參數(shù)一并丟失。

不是吧


Paste_Image.png

這是個(gè)重大bug,如果下周在上線時(shí)客戶那邊不能忽悠過(guò)去,他們一定不肯支付尾款,公司可能會(huì)炒我魷魚(yú),老婆發(fā)現(xiàn)下個(gè)月工資卡沒(méi)錢(qián)到賬,會(huì)把家里電腦里的cpu拆了讓我跪,我受苦不要緊,可憐了cpu呀!

遂百度之。

十分鐘之后,我放棄了。找不到合適的解決方案

也有提出類似問(wèn)題的

http://www.cnblogs.com/mingxinice/p/mingxin.html

但也沒(méi)有好的解決方案

還看到一個(gè)類似的但是看了半天他也不知道自己怎么解決的。
http://m.itdecent.cn/p/a1a31f9da272

或者是可以解決,將router模式改為history,但需要后端做一大堆事的,可這不就違背了前后端分離的真諦了嗎?

哎,為了平復(fù)我忐忑的心,我心中不禁念起了大悲咒:“南無(wú)·喝啰怛那·哆啰夜耶...”

...在電光火石之間,我的心中閃過(guò)了一個(gè)念頭,得到了一個(gè)解決辦法。

這個(gè)辦法也許隱世的前端高手也正在使用,但除了這里,你很難百度到,如果對(duì)你有幫助,請(qǐng)打賞一下。

如上所述,微信跳轉(zhuǎn)時(shí),瀏覽器會(huì)把#后面的hash值給搞掉,據(jù)說(shuō)在ios中還會(huì)在前面加點(diǎn)東西。但是在#之前加的get參數(shù)是不會(huì)丟失的。

那么我們?yōu)槭裁床荒馨褏?shù)前移呢?像這樣:

http://xxxx.xxx.com/?appid=1&cpid=1

頁(yè)面跳轉(zhuǎn)怎么辦?我可以加一個(gè)page參數(shù)呀

http://xxxx.xxx.com/?appid=1&cpid=1&page=/about

這樣寫(xiě)就完全丟棄了#

然后我們通過(guò)一個(gè)js方法獲取鏈接的參數(shù)

getQueryString(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]);
        return null;
    }

我把這個(gè)方法放到了一個(gè)文件中,并作為全局對(duì)象引入,當(dāng)然,你也可以直接放到main.js里

在main.js里,router.beforeEach這個(gè)鉤子之前,將獲得的參數(shù)賦值給一個(gè)全局對(duì)象。

global.browserQuery = {
    appid: getQueryString('appid'),
    cpid: getQueryString('cpid'),
    page: getQueryString('page')
}

在router.beforeEach的鉤子里這樣寫(xiě):

router.beforeEach(({ meta, path, query }, from, next) => {
    if (browserQuery.appid && browserQuery.cpid) {
        store.commit('appid', browserQuery.appid);
        store.commit('cpid', browserQuery.cpid);
        let p=browserQuery.page;
        browserQuery={};
        return next(p);
    }
    ///其它代碼
})

解釋一下,如果browserQuery不是空對(duì)象,說(shuō)明是從外面的鏈接點(diǎn)擊首次進(jìn)入的,這時(shí)候?qū)⑺枰膮?shù)寫(xiě)進(jìn)store中,剩下的page是要跳轉(zhuǎn)到的路由,賦值給p變量,然后清空browserQuery對(duì)象,使下次跳轉(zhuǎn)不再進(jìn)入這個(gè)條件代碼段,然后用return next(p)跳轉(zhuǎn)到該去的頁(yè)面。

可是一測(cè)試,問(wèn)題又來(lái)了。在本地測(cè)試(沒(méi)發(fā)布到微信)

鏈接:http://xxxx.xxx.com/?appid=1&cpid=1&page=/about

還是跳轉(zhuǎn)到根目錄,但后面加#/卻能正確跳轉(zhuǎn)到about頁(yè)面

http://xxxx.xxx.com/?appid=1&cpid=1&page=/about#/

為什么呢?唯一的解釋是,沒(méi)有hash值,router沒(méi)有準(zhǔn)備好,所以默認(rèn)跳轉(zhuǎn)到根目錄。但#/會(huì)被微信丟掉呀,加了也沒(méi)用,這不矛盾嗎?

能不能跳轉(zhuǎn)兩次?先跳到#/,這時(shí)router加載了,再跳轉(zhuǎn)到#/about

所以我寫(xiě)成這樣

router.beforeEach(({ meta, path, query }, from, next) => {
    if (browserQuery.appid && browserQuery.cpid) {
        store.commit('appid', browserQuery.appid);
        store.commit('cpid', browserQuery.cpid);
        delete browserQuery.appid;
        return next('/');
    }else if(browserQuery.page){
       let p=browserQuery.page;
       browserQuery={};
       return next(p);
    }
    ///其它代碼
})

頁(yè)面進(jìn)來(lái)后,刪掉appid,并讓它先跳轉(zhuǎn)到根目錄'/',這時(shí)appid已經(jīng)不在,所以不會(huì)進(jìn)入條件一,而會(huì)進(jìn)入else,因?yàn)閜age還在,清空browserQuery,并跳轉(zhuǎn)到該去的頁(yè)面about,因?yàn)樘D(zhuǎn)前為根目錄'/',hash值已在,應(yīng)當(dāng)不會(huì)出現(xiàn)上述問(wèn)題。

但一測(cè)試,還是不行。

我猜想這個(gè)router.beforeEach鉤子是不支持這樣瞬間跳轉(zhuǎn)兩次的。也就是在return next('/') 之后,不會(huì)立即執(zhí)行下一個(gè)beforeEach的鉤子。

能不能放在router.afterEach里呢?試試!

router.beforeEach(({ meta, path, query }, from, next) => {
    if (browserQuery.appid && browserQuery.cpid) {
        store.commit('appid', browserQuery.appid);
        store.commit('cpid', browserQuery.cpid);
        delete browserQuery.appid;
        return next('/');
    }
      ///其它代碼
})
router.afterEach(route => {
        if (browserQuery.page) {
            let p = browserQuery.page;
            browserQuery = {};
            router.push(p);//因?yàn)闆](méi)有next對(duì)象,直接調(diào)用router跳轉(zhuǎn)
        }
    })

當(dāng)router導(dǎo)航到根目錄'/'之后,馬上跳轉(zhuǎn)到about頁(yè)面,這時(shí)雖然是路由成功,但根目錄頁(yè)面還沒(méi)有渲染,其實(shí)看不出有什么差別。成功了。

對(duì)!就這么解決了困擾單頁(yè)的多入口問(wèn)題了。

如果你要將其中一個(gè)頁(yè)面分享出去,可以這樣組織鏈接,例如
http://xxxx.xxx.com/?appid=1&cpid=1&page=/detail/1

當(dāng)其他人點(diǎn)擊鏈接后,會(huì)被導(dǎo)航到
http://xxxx.xxx.com/#/detail/1頁(yè)面

從此你可以告別#的困擾,單頁(yè)應(yīng)用從此不再受微信的歧視。

吸了一口維他奶,感嘆啊。業(yè)界難題被我輕而易舉解決了,如果我不當(dāng)程序員,真實(shí)IT界的損失呀。嘻嘻嘻嘻(笑)

全部代碼如下:

getQueryString(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        var r = window.location.search.substr(1).match(reg);
        if (r != null) return unescape(r[2]);
        return null;
    }
global.browserQuery = {
    appid: getQueryString('appid'),
    cpid: getQueryString('cpid'),
    page: getQueryString('page')
}
router.beforeEach(({ meta, path, query }, from, next) => {
    if (browserQuery.appid && browserQuery.cpid) {
        store.commit('appid', browserQuery.appid);
        store.commit('cpid', browserQuery.cpid);
        delete browserQuery.appid;
        return next('/');
    }
      ///其它代碼
})
router.afterEach(route => {
        if (browserQuery.page) {
            let p = browserQuery.page;
            browserQuery = {};
            router.push(p);//因?yàn)闆](méi)有next對(duì)象,直接調(diào)用router跳轉(zhuǎn)
        }
    })
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容