今天發現了一個線上問題,我們的APP跳轉內嵌H5時會預設
query
帶一些引數,比如city
之類的,但是有時運營人員配置頁面連結地址時在不太瞭解的情況下,會手動加上city
這些引數,恰巧你請求介面的時候需要這個引數,使用this.$route.query.city
獲取,form
提交就會成為下圖,會報400引數不規範,
這樣重複query
傳引數顯然是不規範的,這樣使用this.$route.query.city
獲取回來是一個陣列
解決該問題需要兩點:
- 根源上配置的時候不要重複配置
- 前端對URL
query
傳參進行過濾
那麼過濾引數怎樣才能一勞永逸呢,避免每次取引數時判斷是不是陣列這中重複的程式碼。我們使用nuxt
這中服務端渲染的框架,開始想當然的想到在middleware
中過濾,每次請求過來後執行middleware
,過濾引數
先寫個filterQuery
的測試middleware
測試覆蓋原來city,跑起來看看效果吧
控制檯列印結果沒啥問題
在頁面裡取一下試試,但結果不盡人意,this.$route.query.city
依然是陣列多個值
看到這裡,才發現自己太想當然了,nuxt
是一套vue ssr
的架構,服務端渲染的專案,**每當一個新路由過來時,都會建立一個新的vue
例項,包括router
, store
,**這樣是為了避免交叉請求狀態的汙染,頁面中vue
生命週期裡this.$route
是vue
例項上的;改動middleware
的route
只在服務端比如asyncData
或fetch
時獲取生效
測試一下
頁面中asyncData
獲取一下引數
果然這裡變了
那現在就是對router
的query
做處理,其實vue-router
為我們提供這樣的函式 parseQuery/stringQuery
(提供自定義查詢字串的解析/反解析函式。覆蓋預設行為)
nuxt
是對vue
進行了封裝,路由生成都是自動通過掃頁面路徑自動生成的,那我們去nuxt
的原始碼裡探個究竟,生成的核心是一個模板檔案,lib/app/router.js
檔案,建立新router
例項的工廠函式也在這個檔案裡
export function createRouter () {
return new Router({
mode: '<%= router.mode %>',
base: '<%= router.base %>',
linkActiveClass: '<%= router.linkActiveClass %>',
linkExactActiveClass: '<%= router.linkExactActiveClass %>',
scrollBehavior,
routes: [
<%= _routes %>
],
<% if (router.parseQuery) { %>parseQuery: <%= serialize(router.parseQuery).replace('parseQuery(', 'function(') %>,<% } %>
<% if (router.stringifyQuery) { %>stringifyQuery: <%= serialize(router.stringifyQuery).replace('stringifyQuery(', 'function(') %>,<% } %>
fallback: <%= router.fallback %>
})
}
複製程式碼
在這裡找到了需要的parseQuery
函式,這裡的router.parseQuery
是在 lib/common/options.js
中配置的
router: {
mode: 'history',
base: '/',
routes: [],
middleware: [],
linkActiveClass: 'nuxt-link-active',
linkExactActiveClass: 'nuxt-link-exact-active',
extendRoutes: null,
scrollBehavior: null,
parseQuery: false,
stringifyQuery: false,
fallback: false
},
複製程式碼
無論本地啟動還是nuxt build
的時候這個options.js
都會與根目錄下的nuxt.config.js
配置項進行合併,所以也就一目瞭然了,加到nuxt.config.js
的router
下就好了,明確了就開幹試試吧
nuxt.config.js
加了如下程式碼
parseQuery: function (querystring) {
let d = function (str) {
try {
return str && window.decodeURIComponent(str)
} catch (e) {
return str
}
}
if (d(querystring).includes('?')) querystring = d(querystring).replace(/\?/g, '&')
querystring = querystring.split('&')
let params = {}
let pair
// march and parse
for (let i = querystring.length - 1; i >= 0; i--) {
pair = querystring[i].split('=')
params[d(pair[0])] = d(pair[1])
}
return params
}
複製程式碼
不僅對重複的key過濾,也對url
混入多個?
做了合併過濾
結果就是 this.$router.query.city
進行了過濾,這裡預設取第一個值
~本文完,有任何表述不清或者表達錯誤的,請大家指正~