[javascript核心-10] 解析params参数的多种方案

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

功能说明

queryUrlPramas()接收两个参数url,attr。如果不传第二个参数,那么返回解析url的对象,如果传入attr,则只返回attr对应的值。

实现方式一:字符串拆分

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askIndex = url.indexOf('?'),
        hashIndex = url.lastIndexOf('#'),
        askText = '',
        hashText = '',
        params = {};
    hashText = url.substring(hashIndex + 1);
    askText = url.substring(askIndex + 1, hashIndex)

    params['hash'] = hashText
    const askTextArr = askText.split('&')
    askTextArr.forEach(element => {
        let [key, val] = element.split('=')
        params[key] = val
    })
    return typeof attr !== 'undefined' ? params[attr] : params
}

const url = 'https://www.bilibili.com/video/eeee/?p=256&spm_id_from=333.7777.top_right_bar_window_history.content.click&vd_source=29aaaa68d14f71bbbb#video'

console.log(queryUrlPramas(url))
/*
{
  hash: 'video',
  p: '256',
  spm_id_from: '333.7777.top_right_bar_window_history.content.click',
  vd_source: '29aaaa68d14f71bbbb'
}
*/
console.log(queryUrlPramas(url, 'p')) // 256

问题:#?不存在时会索引计算会出现问题,导致解析出错;如果#出现在?前时,解析也会出现问题。

考虑各种情况:

  1. #不存在,?存在,?后的参数直接截取到末尾
  2. #存在,?不存在,#后的参数直接截取到末尾
  3. #?都不存在,不做任何处理
  4. #?后面,?后的参数从?截取到#,hash从#截取到末尾
  5. #?前面,hash从#截取到??后的参数直接截取到末尾

字符串解析考虑各种情况:

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askIndex = url.indexOf('?'),
        hashIndex = url.lastIndexOf('#'),
        askText = '',
        hashText = '',
        params = {};

    // 1. `#`不存在,`?`存在,`?`后的参数直接截取到末尾
    if(hashIndex === -1 && askIndex >= 0){
        askText = url.substring(askIndex + 1)
    }
    // 2. `#`存在,`?`不存在,`#`后的参数直接截取到末尾
    else if(hashIndex >= 0 && askIndex === -1){
        hashText = url.substring(hashIndex + 1)
    }
    else if(hashIndex >= 0 && askIndex >= 0){
        // 4. `#`在`?`后面,`?`后的参数从`?`截取到`#`,hash从`#`截取到末尾
        if(hashIndex > askIndex){
            askText = url.substring(askIndex + 1, hashIndex)
            hashText = url.substring(hashIndex + 1)
        }
        // 5. `#`在`?`前面,hash从`#`截取到`?`,`?`后的参数直接截取到末尾
        else {
            hashText = url.substring(hashIndex + 1, askIndex)
            askText = url.substring(askIndex + 1)
        }
    }
    hashText !== '' ? params['hash'] = hashText : null
    if(askText !== ''){
        const askTextArr = askText.split('&')
        askTextArr.forEach(element => {
            let [key, val] = element.split('=')
            params[key] = val
        })
    }
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在,`?`后的参数直接截取到末尾
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在,`#`后的参数直接截取到末尾
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在,不做任何处理
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面,`?`后的参数从`?`截取到`#`,hash从`#`截取到末尾
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面,hash从`#`截取到`?`,`?`后的参数直接截取到末尾
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // { hash: 'ccc', a: '1', b: '2' }

实现方式二:利用<a>标签

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let askText = '',
        hashText = '',
        params = {};
    let linkObj = document.createElement('a');
    linkObj.href = url;
    askText = linkObj.search.substring(1); // 去掉?
    hashText = linkObj.hash.substring(1); // 去掉#
    linkObj = null;

    // 解析参数
    params['hash'] = hashText
    const askTextArr = askText.split('&')
    askTextArr.forEach(element => {
        let [key, val] = element.split('=')
        params[key] = val
    })
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // {hash: 'ccc?a=1&b=2'}

会发现在第 5 中情况下,即#?前面的情况下,无法正常处理,需要手动进行判断修正。

另外可以使用ES6 提供的URLSearchParams类进行参数字符串处理,简化解析:

javascript 复制代码
new URLSearchParams('a=1&b=2').forEach((val, key)=> console.log(val,key)) // 1 a ; 2 b

因此可以用

javascript 复制代码
new URLSearchParams(askText).forEach((val, key)=> params[key] = val)

替换之前的代码:

javascript 复制代码
const askTextArr = askText.split('&')
askTextArr.forEach(element => {
    let [key, val] = element.split('=')
    params[key] = val
})

实现方式三:利用正则表达式

javascript 复制代码
const queryUrlPramas = function(url, attr){
    let params = {};
    url.replace(/#([^?=#&]+)/g,(_,hash)=>params['hash']=hash)
    url.replace(/([^?=#&]+)=([^?=#&]+)/g, (_,key,val)=>params[key]=val)
    return typeof attr !== 'undefined' ? params[attr] : params
}

测试不同情况下的结果:

javascript 复制代码
// 1. `#`不存在,`?`存在
const url1 = 'https://www.bilibili.com/video/eeee/?a=1&b=2'
console.log(queryUrlPramas(url1)) // { a: '1', b: '2' }

// 2. `#`存在,`?`不存在
const url2 = 'https://www.bilibili.com/video/eeee/#ccc'
console.log(queryUrlPramas(url2)) // { hash: 'ccc' }

// 3. `#`和`?`都不存在
const url3 = 'https://www.bilibili.com/video/eeee/'
console.log(queryUrlPramas(url3)) // {}

// 4. `#`在`?`后面
const url4 = 'https://www.bilibili.com/video/eeee/?a=1&b=2#ccc'
console.log(queryUrlPramas(url4)) // { hash: 'ccc', a: '1', b: '2' }
// 5. `#`在`?`前面
const url5 = 'https://www.bilibili.com/video/eeee/#ccc?a=1&b=2'
console.log(queryUrlPramas(url5)) // { hash: 'ccc', a: '1', b: '2' }

每种情况结果都正常。

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

相关推荐
王哲晓38 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
理想不理想v43 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
aPurpleBerry2 小时前
JS常用数组方法 reduce filter find forEach
javascript
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x2 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
我血条子呢3 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
半开半落3 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v4 小时前
vue经典前端面试题
前端·javascript·vue.js