【原生JS】如何优雅地读、改location.search(queryString或GET参数)

应用场景

location.search完全由JS脚本管理,并且需要不刷新页面地修改其内容。例如在Oauth2授权中,如果是前端取参提交给后端API向平台方请求accessToken,需要及时删除GET参数中的code,以防用户刷新浏览器导致用失效的code处理登录。

实现思路

将queryString转为对象并用ES6的Proxy代理,在set、delete钩子中调用history.replaceState更新地址,将代理对象添到window上。这样业务代码中就能像PHP中访问全局变量$_GET一样读和改地址栏的GET参数了。

代码

// 定义被代理对象,如果需要响应用户操作引起的更新,只更新这个原对象即可,Proxy中的target是浅显拷贝,修改原对象会影响到代理对象
const GET_TARGET=location.search?Object.fromEntries(location.search.substring(1).split('&').map(part=>part.split('='))):{};
// 添加toString,便于对其直接使用字符串相关运算
Object.defineProperty(
  GET_TARGET,
  'toString',
  {
    value(){
      const entries=Object.entries(this);
      if(!entries.length) return '';
      entries.sort(([pre],[cur])=>pre.localeCompare(cur));
      return '?'+entries.map(([k,v])=>k+'='+v).join('&');
    }
  }
);
// 代理对象
window.$_GET=new Proxy(
  GET_TARGET,
  {
    set(target,prop,val){
      if(target[prop]!==val){
        target[prop]=val;
        // 这里的 String + target + String 依赖给原对象添加的toString方法
        window.history.replaceState(null,'',location.pathname+target+location.hash);
      }
      return true;
    },
    deleteProperty(target,prop){
      if(prop in target){
        delete target[prop];
        window.history.replaceState(null,'',location.pathname+target+location.hash);
      }
      return true;
    }
  }
);

你可能感兴趣的:(前端,javascript,开发语言,ecmascript)