有一段時間沒寫過技術乾貨文了,這兩天恰好遇到一個之前沒太在乎的一個功能實現--前端獲取URL傳遞的參數前端
畢竟平時都是在後臺處理,掉了一堆頭髮後,想一想仍是寫出來跟大家分享一下,之後要是大家遇到了也有個參考正則表達式
要只是獲取一些常規字符串到沒什麼難的,關鍵還有些亂七八糟的需求,什麼同一個參數名傳遞了屢次啊,傳數組啊。搞來搞去就寫了一大堆數組
先說說思路吧,若是你看這文章是想要解決問題,拿着代碼直接用的話,就直接看最後面的Code實現以及使用方法吧瀏覽器
給你一個以下的URL:微信
將URL裏傳遞的參數轉換爲object
對象,這樣咱們在使用參數的時候也更爲方便函數
我曾屢次強調框架思惟,如今遇到這個問題了,咱們就拿框架思惟來分析一下,該怎樣才能快速解決學習
首先是要了解咱們的目的是什麼?目的很簡單,取得URL內傳遞的參數,而且解析成對象ui
接着再分析咱們如今知道些什麼?有一串URLurl
咱們再來分析,若是從URL中得到傳遞的參數,也就是爲了達到目的,咱們該作些什麼?
URL的特徵咱們大體都知道,就是第一個?
後面的字符串,都是傳遞的參數,可是有個特殊狀況請不要忘記了,URL後面有時候會帶上一個#
,而#
後面的內容,並非咱們要傳遞的參數,而是網頁位置的標識符
若是URL中包含了#
,咱們只須要解析?
到#
之間的字符串就能夠了,若是不包含,那麼第一個?
後全部的內容都是咱們須要解析的
你可能以爲我是在說廢話,這麼明顯的事情,只要不是白癡都能看得懂
我固然知道,只要不是白癡都能看得懂,但我爲何要強調呢?由於咱們想要快速的解決問題,必須具有框架思惟,也能夠說是工程思惟
你可能有會說,這麼簡單的問題須要這樣分析麼?咱們一看就知道了,鬧鬧你這是殺雞用牛刀
雖然說是殺雞用牛刀,可要想培養本身的工程思惟,那麼必須保持刻意訓練,直到隨手拈來
好了,分析完後,咱們按照上面的思路來逐步實現,實現的時候可能會遇到其它的問題,到時候再分析,再解決
畢竟再牛逼的工程師,也不會在動手前就想的面面俱到,只能是在動手實現前儘量的考慮周到,遇到問題時再快速的迭代更新
先用JS拿到URL,若是函數傳參了URL,那就用參數。若是沒傳參,就使用當前頁面的URL
var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
複製代碼
若是後面的字符串存在#
,咱們還得將#
後面的字符串去掉,由於#
後面的內容並非咱們須要獲取的參數,而是網頁位置的標識符
queryString = queryString.split('#')[0];
複製代碼
好了,把干擾的部分都移除後,咱們能夠開始安心的解析參數了,先將傳遞的參數分紅數組
var arr = queryString.split('&');
複製代碼
如今咱們能夠得到一個字符串數組
['product=shirt', 'color=blue', 'newuser', 'size=m']
複製代碼
將字符串拆分紅數組後,咱們經過建立一個對象,用來存儲咱們全部的參數
var obj = {};
複製代碼
咱們能夠經過遍歷數組arr
,將它拆分紅鍵值對。把這個字符串作成key:value
的對象
var a = arr[i].split('=');
複製代碼
接下來就是要爲每個變量key
分配對應的值value
,若是咱們獲得的value
不是一個正確的參數,咱們就用true
來表示這個參數名存在,固然了,你也能夠根據本身的實際狀況來作改變
var paramName = a[0];
var paramValue = typeof(a[1]) === 'undefined' ? true : a[1];
複製代碼
在這裏我只是對undefined
作了標記,若是是NaN
,我是直接拿它當字符串處理了
在這裏有一個小坑得提醒一下,咱們在調用函數,獲取對象取值的時候,若是URL傳遞的key
爲大寫,咱們取對象時寫的小寫,那麼結果就是爲undefined
好比URL爲http://NaoNao.com/?NamE=NaoNao
,若是不作大小寫的處理,調用對象取值時getAllUrlParams().NamE
才能取到值NaoNao
,若是作了處理,咱們使用時只須要所有寫成小寫/大寫便可,例如getAllUrlParams().name
我在這就所有轉爲小寫了,若是你對大小寫要求區分,那到時候把這段Code給去掉就行了
paramName = paramName.toLowerCase();
if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase();
複製代碼
接下來咱們就要去處理咱們接受到的paramValue
,這些參數多是索引數組,非索引數組,又或者是常規字符串
若是是索引數組,咱們須要將paramValue
轉換成數組,而且將索引對應的值,放入索引對應的位置
若是是非索引數組,咱們就要將paramValue
放到數組中
若是隻是常規的字符串,咱們就須要爲咱們的對象obj
建立一個常規的屬性,併爲其分配值。
若是這個key已經存在,那麼咱們就要將現有的paramValue
從key:value
轉換爲數組,並將它放到數組中
拿幾個實際案例,感覺一下咱們要作什麼吧
// 索引數組
getAllUrlParams('http://NaoNao.com/?colors[0]=red&colors[2]=green&colors[6]=blue');
// { "colors": [ "red", null, "green", null, null, null, "blue" ] }
// 非索引數組
getAllUrlParams('http://NaoNao.com/?colors[]=red&colors[]=green&colors[]=blue');
// { "colors": [ "red", "green", "blue" ] }
// 屢次傳遞同一個key
getAllUrlParams('http://NaoNao.com/?colors=red&colors=green&colors=blue');
// { "colors": [ "red", "green", "blue" ] }
// 傳遞了key,可是沒傳value
getAllUrlParams('http://NaoNao.com/?product=shirt&color=blue&newuser&size=m');
// { "product": "shirt", "color": "blue", "newuser": true, "size": "m" }
複製代碼
我作這寫判斷時用的是正則表達式,在這裏就不解釋正則了。。。畢竟解釋起來篇幅就太長了,能看懂就儘可能看吧
每一個正則要解析什麼,在註釋中都寫了例子,稍微瞭解點正則表達式的同窗,多半也能看懂的
對應的代碼實現以下:
// 若是paramName以方括號結束, e.g. colors[] or colors[2]
if (paramName.match(/\[(\d+)?\]$/)) {
// 若是paramName不存在,則建立key
var key = paramName.replace(/\[(\d+)?\]/, '');
if (!obj[key]) obj[key] = [];
// 若是是索引數組 e.g. colors[2]
if (paramName.match(/\[\d+\]$/)) {
// 獲取索引值並在對應的位置添加值
var index = /\[(\d+)\]/.exec(paramName)[1];
obj[key][index] = paramValue;
} else {
// 若是是其它的類型,也放到數組中
obj[key].push(paramValue);
}
} else {
// 處理字符串類型
if (!obj[paramName]) {
// 若是若是paramName不存在,則建立對象的屬性
obj[paramName] = paramValue;
} else if (obj[paramName] && typeof obj[paramName] === 'string') {
// 若是屬性存在,而且是個字符串,那麼就轉換爲數組
obj[paramName] = [obj[paramName]];
obj[paramName].push(paramValue);
} else {
// 若是是其它的類型,仍是往數組裏丟
obj[paramName].push(paramValue);
}
}
複製代碼
若是你的URL的傳參包含了一些特殊字符,好比空格。例如url="NaoNao.com/?name=Nao%20Nao"
,拿到對象值以後,是須要解碼後才能得到正確的值的
var original = getAllUrlParams().name; // 'Nao%20Nao'
var decode = decodeURIComponent(original); // 'Nao Nao'
複製代碼
下面是JS的具體的完整實現,大家複製回去就能夠用
function getAllUrlParams(url) {
// 用JS拿到URL,若是函數接收了URL,那就用函數的參數。若是沒傳參,就使用當前頁面的URL
var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
// 用來存儲咱們全部的參數
var obj = {};
// 若是沒有傳參,返回一個空對象
if (!queryString) {
return obj;
}
// stuff after # is not part of query string, so get rid of it
queryString = queryString.split('#')[0];
// 將參數分紅數組
var arr = queryString.split('&');
for (var i = 0; i < arr.length; i++) {
// 分離成key:value的形式
var a = arr[i].split('=');
// 將undefined標記爲true
var paramName = a[0];
var paramValue = typeof (a[1]) === 'undefined' ? true : a[1];
// 若是調用對象時要求大小寫區分,可刪除這兩行代碼
paramName = paramName.toLowerCase();
if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase();
// 若是paramName以方括號結束, e.g. colors[] or colors[2]
if (paramName.match(/\[(\d+)?\]$/)) {
// 若是paramName不存在,則建立key
var key = paramName.replace(/\[(\d+)?\]/, '');
if (!obj[key]) obj[key] = [];
// 若是是索引數組 e.g. colors[2]
if (paramName.match(/\[\d+\]$/)) {
// 獲取索引值並在對應的位置添加值
var index = /\[(\d+)\]/.exec(paramName)[1];
obj[key][index] = paramValue;
} else {
// 若是是其它的類型,也放到數組中
obj[key].push(paramValue);
}
} else {
// 處理字符串類型
if (!obj[paramName]) {
// 若是若是paramName不存在,則建立對象的屬性
obj[paramName] = paramValue;
} else if (obj[paramName] && typeof obj[paramName] === 'string') {
// 若是屬性存在,而且是個字符串,那麼就轉換爲數組
obj[paramName] = [obj[paramName]];
obj[paramName].push(paramValue);
} else {
// 若是是其它的類型,仍是往數組裏丟
obj[paramName].push(paramValue);
}
}
}
return obj;
}
複製代碼
這個函數該怎麼使用呢?
直接把URL參數當成對象調用就OK咯~
以文章開篇的URL爲例子
// http://NaoNao.com/?product=shirt&color=blue&newuser&size=m#Hello
getAllUrlParams().product; // 'shirt'
getAllUrlParams().color; // 'blue'
getAllUrlParams().newuser; // true
getAllUrlParams().NB; // undefined
getAllUrlParams('http://NaoNao.com/?NaoNao=shuai').NaoNao; // shuai
複製代碼
若是咱們不須要考慮IE這種妖嬈賤貨,以及一些很是老版本瀏覽器,就用瀏覽器內URLSearchParams
的接口吧。。。這個接口能夠直接拿取URL內的參數
// URL is http://NaoNao.com/?product=shirt&color=blue&newuser&size=m
const urlParams = new URLSearchParams(window.location.search);
// 判斷參數是否存在
console.log(urlParams.has('product')); // true
// 獲取參數對應的值
console.log(urlParams.get('product')); // "shirt"
複製代碼
這個接口還提供了更多成熟的方法,好比keys()
,Values()
,還有entries()
,這個接口該怎麼使用,直接去看官方文檔就行了,用起來仍是很虛浮的