[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 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士

相关推荐
十一吖i14 分钟前
vue3表格显示隐藏列全屏拖动功能
前端·javascript·vue.js
徐同保2 小时前
tailwindcss暗色主题切换
开发语言·前端·javascript
生莫甲鲁浪戴2 小时前
Android Studio新手开发第二十七天
前端·javascript·android studio
细节控菜鸡4 小时前
【2025最新】ArcGIS for JS 实现随着时间变化而变化的热力图
开发语言·javascript·arcgis
拉不动的猪5 小时前
h5后台切换检测利用visibilitychange的缺点分析
前端·javascript·面试
桃子不吃李子5 小时前
nextTick的使用
前端·javascript·vue.js
Devil枫7 小时前
HarmonyOS鸿蒙应用:仓颉语言与JavaScript核心差异深度解析
开发语言·javascript·ecmascript
惺忪97987 小时前
回调函数的概念
开发语言·前端·javascript
前端 贾公子7 小时前
Element Plus组件v-loading在el-dialog组件上使用无效
前端·javascript·vue.js
天外飞雨道沧桑7 小时前
JS/CSS实现元素样式隔离
前端·javascript·css·人工智能·ai