# URL对象
URL是Web中的一个核心概念。它是浏览器用来检索web上公布的任何资源的机制。
URL 的名称实际为 统一资源定位符(Uniform Resource Locator)。
# 一个URL应该由什么组成
href一个完整的URL地址origin由协议(protocol),域名(hostname),端口(post) 组成的源, 他是一个只读属性- 对于
http和https协议的URL,返回值就是http://www.baidu.com:222 - 对于
file:协议的 URL, 返回值应浏览器而异 - 对于
blob:协议的 URL, 返回值是 blob: 后跟随的源地址. 例如"blob:https://www.baidu.com:222"将会返回"https://www.baidu.com:222"
- 对于
protocol协议, 常见的协议有httphttpsftp, 协议表示我们可以通过不同的规则访问一个URl,前提是服务器支持该协议hostname域名,或者说是主机名。port端口号, 一般http的端口为 80 ,而https的端口为 443pathname路径search路由参数 以?开头hash哈希值 以#开头如果存在 HTTP 身份验证,则这里可能还会有 user 和 password 属性
# 如何创建URL对象
new URL(url, [base])
url--- 完整的 URL,或者仅路径(如果设置了 base)base--- 可选参数,如果设置了两个参数,则会根据两参数生成一个完整的Url
以下两个都是一样的值:
const u1 = new URL('https://www.baidu.com/aa/bb')
const u2 = new URL('/aa/bb', 'https://www.baidu.com')
console.log(u1.href, u2.href)
// u1 -> https://www.baidu.com/aa/bb
// u2 -> https://www.baidu.com/aa/bb
2
3
4
5
看看url 有哪些属性值: 发现这个内置对象 可以取出一个URL 的所有属性,可以很方便的处理URL。
const u1 = new URL('https://www.baidu.com/aa/bb')
console.log(u1)
// {
// hash: ""
// host: "www.baidu.com"
// hostname: "www.baidu.com"
// href: "https://www.baidu.com/aa/bb"
// origin: "https://www.baidu.com"
// password: ""
// pathname: "/aa/bb"
// port: ""
// protocol: "https:"
// search: ""
// searchParams: URLSearchParams {}
// username: ""
// }
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 对于字符串的手动编码解码
提示
在某项标准中规定了URL只能包含某些字符,而那些不合规的字符将会被转义。一般这种情况是针对于我们所带的参数中不合规的字符。这样导致在页面接受参数的时候发现参数和原参数对不上,被转义了。
下面是个a链接,带了一个 a 参数,参数中有一个空格。
<!-- index.html -->
<a href="cli.html?a=VSA UIO">跳转页面</a>
2
发现在 cli.html 中取参数的时候, 空格变成了 %20, 那就有问题了,当我想拿参数进行处理的时候, 会发现对不上原始参数。
转义的规则是:根据操作系统的默认编码,将每个字节转为百分号(%)加上两个大写的十六进制字母。
<!-- cli.html -->
<script>
console.log(window.location.href)
// http://localhost:8082/cli.html?a=VSA%20UIO
</script>
2
3
4
5
所以我们需要将参数进行手动编码 encodeURI 。在进行编码之后, 取值的时候应该要进行解码 decodeURI,这样就得到了正确的值。
let encodeURI = encodeURI('cli.html?a=VSA UIO')
console.log(encodeURI)
// cli.html?a=VSA%20UIO
encodeURI = decodeURI(encodeURI)
console.log(encodeURI)
// cli.html?a=VSA UIO
2
3
4
5
6
除此之外, 还有 encodeURIComponent 和 decodeURIComponent 编码方式。
encodeURI编码整个 URLdecodeURI解码为编码前的状态encodeURIComponent编码 URL 组件,例如搜索参数,或者 hash,或者 pathnamedecodeURIComponent解码为编码前的状态
那两个编码方法有什么区别呢?
下面有一个全面的URL地址:
https://www.baidu.com:8080/path/page?p1=v1&p2=v2#hash
可以发现在URL中 : . / ? = & # 这类字符是被允许的。
合法字符分为两类:
URL元字符: 分号; 逗号, 斜杆/ 问好? 冒号: at符@ and符& 等于号= 加号+ 美元符$
语义字符: 井号# 连接符号- 下划线_ 点. 感叹号! 波浪号~ 星号* 单引号' 圆括号() 最后还有 大小写字母a-z A-Z 和 阿拉伯数字 0-9
为啥要分两类呢?encodeURI 方法只会转编码合法字符之外的其他字符, encodeURIComponent 则会编码URL元字符之外的字符。
如果你想传一个参数 12&123 怎么办, 它会把 & 当成参数分隔符。 和你的本意不同,这样, 我们就是使用 encodeURIComponent 进行参数编码。
下面的代码我们将 p1 参数取出, 并使用 decodeURIComponent 方法解码, 就得到了原来的值。
const params = encodeURIComponent('12&123')
const url = `https://www.baidu.com:8080/path/page?p1=${params}&a=1`
console.log(url)
// https://www.baidu.com:8080/path/page?p1=12%26123&a=1
const arr = url.match(/([^&?])+(=)([^&])+/g)
console.log(arr)
// ["p1=12%26123", "a=1"]
console.log(arr[0].split('='))
// ["p1", "12%26123"]
const p1 = arr[0].split('=')[1]
console.log(p1)
// 12%26123
console.log(decodeURIComponent(p1))
// 12&123
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 使用URL对象进行自动编码解码
上面我们使用 encodeURIComponent 和 decodeURIComponent 进行手动编码, 下面我们用 URL 对象进行自动编码。
URL 对象下面有个属性为 searchParams,使用它可以进行对参数的各种处理。
(提示: searchParams 其实是 URLSearchParams(window 下面的内置对象, 和URL对象一样) 的实例,两者的用法也是一样的。)
append方法:new URL(url).searchParams.append('p1', '12&123')往 url 里添加 属性名为 p1, 属性值为 12&123 的参数,对于 属性值 该方法会自动进行编码。get方法:new URL(url).searchParams.get('p1')从 url 里取出 属性名为 p1 的参数值, 该方法会自动进行解码delete方法:new URL(url).searchParams.delete('a')从 url 里删除 属性名为 p1 的参数has方法:new URL(url).searchParams.has('p1')url 中是否有 p1 参数, 返回true或falseset方法: 有两种功能,,分别是 添加新参数 和 替换旧参数new URL(url).searchParams.set('p2', '00000')往 url 里添加 属性名为 p2,属性值为 00000 的参数new URL(url).searchParams.set('p1', '11111')从 url 将属性名为 p1的属性值替换为 00000
getAll方法:new URL(url).searchParams.getAll('p1')
append 方法允许插入相同属性名甚至相同属性值参数, 但是使用 get 方法的时候只能取第一个 p1 的值。这个时候我们就需要 getAll 方法, 它会取出所有的 p1 的值。
const url = `https://www.baidu.com:8080/path/page`
let urlObj = new URL(url)
urlObj.searchParams.append('p1', '12&123')
urlObj.searchParams.append('p1', '12&123')
console.log(urlObj.search)
// ?p1=12%26123&p1=12%26123 一样的属性名 和 一样的属性值 是可行的
const url = `https://www.baidu.com:8080/path/page`
let urlObj = new URL(url)
urlObj.searchParams.append('p1', '12&123')
urlObj.searchParams.append('p1', '000000')
console.log(urlObj.search)
// ?p1=12%26123&p1=000000
console.log(urlObj.searchParams.get('p1'))
// 12&123 只会取第一个值
console.log(urlObj.searchParams.getAll('p1'))
// ["12&123", "000000"] 返回一个数组
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
keys方法:new URL(url).searchParams.keys()生成一个包含参数属性名的迭代器values方法:new URL(url).searchParams.values()生成一个包含参数属性值的迭代器
const url = `https://www.baidu.com:8080/path/page`
let urlObj = new URL(url)
urlObj.searchParams.append('p1', '213')
urlObj.searchParams.append('p2', '421')
for (let key of urlObj.searchParams.keys()) {
console.log(key)
// p1
// p2
}
2
3
4
5
6
7
8
9
new URL(url).searchParams本身就是一个迭代器,拥有forEach方法, 和数组的forEach方法一样的使用
# URL的方法
这两个静态方法是相辅相成的, 一个是在内存中创建 URL 对象, 一个是 在内存中释放 URL 对象。
# createObjectURL
使用方法 window.URL.createObjectURL(object), 用于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。
# revokeObjectURL
使用方法 window.URL.revokeObjectURL(objectURL), 用来释放一个之前已经存在的、通过调用 URL.createObjectURL() 创建的 URL 对象。
# 最后,看看兼容性吧
除了 IE 不支持, 其他的浏览器基本都支持, 可以放心在 移动端使用了。