JS 如何取得 URL 里的参数
上篇简单介绍了一下 Location
对象, 并封装了一个简单处理 URL
的方法, 本篇封装一个处理复杂 URL
的方法
要只是获取一些常规字符串倒没什么难的, 关键还有些乱七八糟的需求, 什么同一个参数名传递了多次啊, 传数组啊. 搞来搞去就写了一大堆
先说说思路吧, 如果你看这文章是想要解决问题, 拿着代码直接用的话, 就直接看最后面的 Code 实现以及使用方法吧
# 用框架思维分析问题
给你一个如下的 URL
:
http://example.com:1234/test/t.asp?a=aa&b=bb&c&d=dd#Hello
将 URL
里传递的参数转换为 object
对象, 这样我们在使用参数的时候也更为方便
我曾多次强调框架思维, 现在遇到这个问题了, 我们就拿框架思维来分析一下, 该怎样才能快速解决
首先是要了解我们的目的是什么? 目的很简单, 取得 URL
内传递的参数, 并且解析成对象
接着再分析我们现在知道些什么? 有一串 URL
我们再来分析, 如果从 URL
中获得传递的参数, 也就是为了达到目的, 我们该做些什么?
URL
的特征我们大致都知道, 就是第一个 ?
后面的字符串, 都是传递的参数, 但是有个特殊情况请不要忘记了, URL
后面有时候会带上一个 #
, 而 #
后面的内容, 并不是我们要传递的参数, 而是网页位置的标识符
如果 URL
中包含了 #
, 我们只需要解析 ?
到 #
之间的字符串就可以了, 如果不包含, 那么第一个 ?
后所有的内容都是我们需要解析的
好了, 分析完后, 我们按照上面的思路来逐步实现, 实现的时候可能会遇到其它的问题, 到时候再分析, 再解决
毕竟再牛逼的工程师, 也不会在动手前就想的面面俱到, 只能是在动手实现前尽可能的考虑周到, 遇到问题时再快速的迭代更新
# JS 获取 URL 参数的过程
先用 JS
拿到 URL
, 如果函数传参了 URL
, 那就用参数. 如果没传参, 就使用当前页面的 URL
url = url || window.location.href
var queryString = url.split('?')[1]
2
如果后面的字符串存在 #
, 我们还得将 #
后面的字符串去掉, 因为 #
后面的内容并不是我们需要获取的参数, 而是网页位置的标识符
queryString = queryString.split('#')[0]
好了, 把干扰的部分都移除后, 我们可以开始安心的解析参数了, 先将传递的参数分成数组
var arr = queryString.split('&')
现在我们可以获得一个字符串数组
;['a=aa', 'b=bb', 'c', 'd=dd']
将字符串拆分成数组后, 我们通过创建一个对象, 用来存储我们所有的参数
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]
2
在这里我只是对 undefined
做了标记, 如果是 NaN
, 我是直接拿它当字符串处理了
在这里有一个小坑得提醒一下, 我们在调用函数, 获取对象取值的时候, 如果 URL
传递的 key
为大写, 我们取对象时写的小写, 那么结果就是为 undefined
比如 URL
为 http://example.com:1234/test/t.asp?TeSt=TEst
, 如果不做大小写的处理, 调用对象取值时 getAllUrlParams().TeSt
才能取到值 TEst
, 如果做了处理, 我们使用时只需要全部写成小写/大写即可, 例如 getAllUrlParams().test
我在这就全部转为小写了, 如果你对大小写要求区分, 那到时候把这段 Code
给去掉就好了
paramName = paramName.toLowerCase()
接下来我们就要去处理我们接受到的 paramValue
, 这些参数可能是索引数组, 非索引数组, 又或者是常规字符串
如果是索引数组, 我们需要将
paramValue
转换成数组, 并且将索引对应的值, 放入索引对应的位置如果是非索引数组, 我们就要将
paramValue
放到数组中如果只是常规的字符串, 我们就需要为我们的对象
obj
创建一个常规的属性, 并为其分配值.如果这个 key 已经存在, 那么我们就要将现有的
paramValue
从key:value
转换为数组, 并将它放到数组中
拿几个实际案例, 感受一下我们要做什么吧
// 索引数组
getAllUrlParams('http://example.com/?colors[0]=red&colors[2]=green&colors[6]=blue')
// { "colors": [ "red", null, "green", null, null, null, "blue" ] }
// 非索引数组
getAllUrlParams('http://example.com/?colors[]=red&colors[]=green&colors[]=blue')
// { "colors": [ "red", "green", "blue" ] }
// 多次传递同一个key
getAllUrlParams('http://example.com/?colors=red&colors=green&colors=blue')
// { "colors": [ "red", "green", "blue" ] }
// 传递了key,但是没传value
getAllUrlParams('http://example.com/?product=shirt&color=blue&newuser&size=m')
// { "product": "shirt", "color": "blue", "newuser": true, "size": "m" }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
对应的代码实现如下:
// 如果 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)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
如果你的 URL
的传参包含了一些特殊字符, 比如空格. 例如 url="example.com/?name=na%20me"
, 拿到对象值之后, 是需要解码后才能获得正确的值的
var original = getAllUrlParams().name // 'na%20me'
var decode = decodeURIComponent(original) // 'na me'
2
# 具体实现以及使用方式
下面是 JS
的具体的完整实现, 你们复制回去就可以用
function getAllUrlParams(url) {
// 用 JS 拿到 URL,如果函数接收了 URL,那就用函数的参数。如果没传参,就使用当前页面的 URL
url = url || window.location.href
var queryString = url.split('?')[1]
// 用来存储我们所有的参数
var obj = {}
// 如果没有传参,返回一个空对象
if (!queryString) {
return obj
}
// # 后的内容不是我们需要的
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()
// 如果 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
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
这个函数该怎么使用呢?
直接把 URL
参数当成对象调用就 OK
咯~
以文章开篇的 URL
为例子
var url = 'http://example.com:1234/test/t.asp?a=aa&b=bb&c&d=dd#Hello'
var urlParams = getAllUrlParams(url)
urlParams.a // 'aa'
urlParams.b // 'bb'
urlParams.c // true
urlParams.NB // undefined
2
3
4
5
6
7
8
你可以在下面输入框中输入需要查询的 url
来体验一下!
# 不兼容 IE 的解决方案
如果我们不需要考虑 IE 这种妖娆贱货, 以及一些非常老版本浏览器, 就用浏览器内 URLSearchParams (opens new window) 的接口吧... 这个接口可以直接拿取 URL
内的参数
var a = document.createElement('a')
a.href = 'http://example.com:1234/test/t.asp?a=aa&b=bb&c&d=dd#Hello'
var urlParams = new URLSearchParams(a.search) // 使用 search 时注意 # 和 ? 的先后位置
// 判断参数是否存在
console.log(urlParams.has('a')) // true
// 获取参数对应的值
console.log(urlParams.get('a')) // 'aa'
2
3
4
5
6
7
8
9
这个接口还提供了更多成熟的方法, 比如 keys()
, Values()
, 还有 entries()
, 这个接口该怎么使用, 直接去看官方文档就好了, 用起来还是很虚浮的
- 01
- 搭配 Jenkins 实现自动化打包微前端多个项目09-15
- 02
- 自动化打包微前端多个项目09-15
- 03
- el-upload 直传阿里 oss 并且显示自带进度条和视频回显封面图06-05