应用场景
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;
}
}
);