基於vue開發活動頁-路由相關

距離第一篇的發佈過了很久,由於此次真的踩了很多坑..之後仍是儘可能不要新立項目好了,就跟立了個flag同樣T Thtml

本篇主要內容有如下幾點--vue

  • 使用vue-router除了mode以外,可能還須要知道base屬性
  • 關於hash與history這兩種模式的選擇
  • 關於微信受權的處理方式
  • 域名限制下如何帶着鐐銬跳舞

使用vue-router除了mode以外,可能還須要知道base屬性

首先介紹一下項目的背景,脫離了背景談需求都在瞎逼逼,本次活動頁是獨立於主站項目(SPA)的新獨立項目,可是因爲對微信的強依賴,新項目仍是須要掛在主域名下。nginx

這有啥的,讓運維同事幫忙配個nginx把主站的某個路徑指向新項目目錄就好唄~事實上確實是的,一開始配的域名是m.kurisu.fm/my(對..這個是假域名)凡是這個路徑的都直接指向vue項目的目錄,很完美跑起來了,這個也是微信的安全域名因此登陸應該也是穩妥的。可是問題來了...它無法支付...這個域名並非可支付的域名,因此咱們必需要改動域名。vue-router

咱們的可支付路徑是m.kurisu.fm/pay/:id,只好再麻煩一下同事幫忙配個m.kurisu.fm/pay/my的路徑了,好啦,restart以後一看,涼了。白屏,靜態資源都加載出來了,#app也掛載上了,可是router-view那邊沒有顯示。這是啥玩意?看了下vue-router的文檔,發現了這個玩意--應用基路徑也就是說咱們應該將router的配置修改一下後端

let link = ''

if (window.location.host === 'm.kurisu.fm') {
  link = '/pay/my'
}

export default new Router({
  base: link, // 在此設定應用的基路徑
  /*在window.location.host === 'm.kurisu.fm'的狀況下,路由會將path爲'/'的路徑變爲'/pay/my',若是沒有這個配置的話router仍是會按'/'的路徑去匹配路由,這樣用戶將會沒法正常訪問到頁面*/
  routes: [
    {
      path: '/',
      name: 'JXGlobal',
      component: JXGlobal
    },
    {
      path: '/auth',
      component: Auth
    }
  ]
})
複製代碼

修改以後咱們就能夠愉快的進行下面的開發啦~並且還能夠悄咪咪的在線上跑微信的各個功能[冷漠]api

關於hash與history這兩種模式的選擇

說到了router就必然少不了對mode的討論了,這裏兩種模式我都想說一說,由於實際開發中都TM用到了,最後我得出的結論是--強烈建議使用hash路由緩存

雖然最後我仍是用了history的模式因爲項目的歷史緣由,這次開發仍是使用了history的模式,具體緣由會在下闡述。安全

Hash模式路由

vue-router 默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,因而當 URL 改變時,頁面不會從新加載。bash

使用這種模式的時候,你們會發現url會出現一個很奇葩的'#',可是這個模式除了醜了點,真的沒有啥問題。特別是在微信上面跑單頁應用的時候,簡直是良心之選。微信

可是爲何最後我沒有采用這個模式呢?下面我仍是想結合一下項目的實際,說說我選擇的緣由--

根本緣由支付受權目錄限制是最多隻能配置3個,超過3個將沒法配置,而且路徑深度不能大於2層用了hash以後咱們的url後面都會有'#/'這樣就致使微信支付時匹配的目錄有問題。通過測試,微信貌似以後根據'/'來判斷路徑層級的,因此若是使用了'#/'就表明自然少了一層路徑,權衡以後仍是放棄了使用hash模式

History模式路由

關於History模式路由的介紹也已經爛大街了,它主要是依靠HTML5新增的API--history.pushState來實現的,具體實現就不在這裏囉嗦了,往後爭取出一篇router的詳解。

因爲種種緣由(詳情見上方Hash部分)我選擇了history模式跑這個項目,在這期間也是遇到了一些坑的地方。

由於項目主要是跑在微信上的,總的來講坑的地方就是微信JSSDK對單頁應用的兼容差強人意

  • 在安卓與iOS上使用JSSDK會發現有些地方在兩個系統內的表現會莫名的不太同樣,好比對初始location的判斷、支付時同一url會有不一樣的結果...
    • iOS上微信不會根據history.pushState來更改當前的href這致使的問題可很多,複製連接是錯誤的、受權可能會不成功、支付會有問題;在安卓上則一點問題都沒有。解決方案仍是比較粗暴的,在iOS系統中,斷定到須要和微信JSSDK交互的頁面就強行刷新一下以保證交互的正常進行。

    • 測試支付的時候發現一個頗有趣的現象,在iOS跑得妥妥的支付調起,到安卓就掛了。在安卓系統中,支付調起了,可是最終付款的彈窗卻沒出現。對比了兩端的支付參數也是如出一轍,問題出在哪呢?掙扎了許久,仍是在網上找到了坑友們的回答--安卓調起支付的url不容許'/'結尾,不然支付將會沒法正常調起

微信受權處理方式

因爲router有兩種模式,因此處理起來也有些許差別,不過總的來講仍是一致的。

首先,咱們最好有一個獨立的頁面(組件)來處理受權相關的事件,由於實際開發的狀況是可能同時存在多種不一樣途徑的受權,有一個獨立頁面有助於咱們很好的與主業務解耦。

而後就是看看微信的文檔把受權的連接拼起來,這裏須要注意的是redirect_uri必需要設定過白名單的域名,不然是無法正常發起受權的。

能正常的重定向到指定的url以後,恭喜你,你已經完成了受權處理的1%一大步啦。重定向的url會帶有code(&state...),咱們只須要拿着這個code向後端請求登陸數據便可。

在這一步,兩種路由模式的處理方式就有些許不一樣了。

  • history模式下,咱們能夠直接經過$route.query來拿到相關的參數,而後能夠繼續後面的請求。這是沒有將受權分離的作法,可是在此次的項目中,我仍是分離出了一個單獨的受權頁面,這也給本身埋了很多坑。首先是router.push的用法,一開始測試的時候能夠順利的從微信受權的頁面回來,可是回來就不動了,即不請求登陸接口,也不重定向回原頁面。後面發現是code被沖掉了,罪魁禍首就是我本身router.push,在push的時候沒將參數帶上。另一個須要注意的是受權完成以後最好使用window.location.href來進行原頁面的回跳,能夠避開一些在iOS系統下jssdk的坑。

  • hash模式下,咱們則不須要像history模式那樣到處避坑,可是這裏咱們會發現沒法用$route.query拿到想要的參數,那是由於從微信跳回來以後咱們的url變成了這樣-- m.kurisu.fm/?code=1234#/ 發現問題了嗎?'#/'加到了最後,致使$route無法拿到'#/'以前的code,這裏只須要本身寫個解析window.location.search的工具類就能夠輕鬆解決啦。

function urlQuery2Object (search) {
  let result = {}
  search.split('?')[1].split('&').forEach(function (part) {
    let item = part.split('=')
    result[item[0]] = decodeURIComponent(item[1])
  })
  return result
}
複製代碼

域名限制的情形下如何帶着鐐銬跳舞

因爲發起支付的路徑有所限制,活動頁的二級頁面甚至是主頁都不能獨佔一層路由,這該怎麼解決呢?最快捷的解決方案就是經過route.query和watch對route的監聽來實現頁面切換。

最後敲定的url是這樣的m.kurisu.fm/pay/my?:id&:sid其中id是此次活動的id(可能會同時有多個活動使用同一套頁面),sid則是每一個活動下的子活動頁面。

<div class="container__content" v-if="activity_init">
    <keep-alive>
        <jx-index :f_content="init_data" v-if="!$route.query.sid"></jx-index>
        <jx-subpage v-else></jx-subpage>
    </keep-alive>
</div>
複製代碼

在頁面展現上咱們只需判斷頁面是否存在sid就能夠知道應該展現哪一個template,而後對$route的監聽則只須要在子活動頁面的template中進行。

watch: {
    //監聽$route的變更
    '$route' (to, from) {
        if (to.query.sid && (to.query.sid !== from.query.sid)) {
            //對子活動頁的緩存,如有緩存則優先使用緩存數據,並靜默(無loading toast)請求新數據,優化頁面體驗
            if (window.sessionStorage.getItem(String(to.query.id) + String(to.query.sid))) {
                let data = window.sessionStorage.getItem(String(to.query.id) + String(to.query.sid))
                this.column = JSON.parse(data)
                this.page_init = true
                this.GetData(false)
            } else {
                this.GetData(true)
            }
        }
    }
}
複製代碼

總結

本系列文章主要仍是記錄實際開發過程當中的一些解決方案,本篇主要是圍繞在路由相關的問題以及微信在其中的兼容問題,但願能幫助你們和我規避往後的坑。

往期文章

相關文章
相關標籤/搜索