同源页面通信在网页登录方面的应用
为什么一个“普普通通”的网页登录要和“看似高大上”的同源页面通信联系了起来?
可能你没有发现:往往如果你的登录页是从主页通过 window.open() 或 js-href 或 另打开的一个tab,在你登录成功后,要么是重新打开一个主页的tab,要么就要你回到原主页tab刷新一下才可。
可是这简简单单的“刷新”或“关闭原主页tab”带来的却是“用户体验”的低水平。如果我们能在登录后返回主页面时“自动同步信息”,会不会更好一点?事实上,比如「字节跳动(招聘)官网」就是这么做的!
还有不少网页干脆把两个页面设置为“同tab跳转”(非PWA框架)
那么要完成这么一件事,要怎么做呢?
① Page Visibility(页面可见性)API
众所周知,CSS中有一个很讨人喜欢的属性:visibility: hidden/visible; ,巧的是:hidden 和visible 同样是此 API 的两个状态值。它的属性和事件如下:
document.hidden:true/false,表示当前页面不可见/可见;document.visibilityState:当前页面可见状态 —— hidden / visible / prerender / preview ;visibilitychange:可见状态变化时触发的事件
这个 API 只负责“切换”,那和“登录同步”又有什么关系?其实它主要利用了“ 同源页面间localStorage共享 ”的原理。代码如下:
主页
<p id="loginInfo">p>
这里由于涉及到不同浏览器之间的差异性以及使用的不同,建议使用时直接引入张鑫旭大神封装好的在线js文件:
// 引入
<script src="https://www.zhangxinxu.com/study/201211/pageVisibility.js"></script>
<script type="text/javascript">(function() {if (typeof pageVisibility.hidden !== "undefined") { // 张大神的源码中这里表现为是否支持visibility APIvar eleLoginInfo = document.querySelector("#loginInfo");var funLoginInfo = function() {var username = localStorage.username || sessionStorage.username;if (username) {eleLoginInfo.innerHTML = '欢迎回来,' + username + '';sessionStorage.username = username;} else {eleLoginInfo.innerHTML = '您尚未登录,请登录';} }// 触发事件pageVisibility.visibilitychange(function() {if (!this.hidden) funLoginInfo();});funLoginInfo();// 页面关闭清除localStoragewindow.addEventListener("unload", function() {localStorage.removeItem("username");})} else {alert("你的这个浏览器不支持Page Visibility API的啦!"); }})();
</script>
登录页
<div class="boxs"><form id="loginForm" action="" method="post"><p>用户名:<input type="text" name="username" required />p><p>密码:<input type="password" name="password" required />p><p><input type="submit" />p>form>
div>
(function() {if (typeof window.screenX === "number") {var eleLoginForm = document.querySelector("#loginForm");eleLoginForm.addEventListener("submit", function(e) {localStorage.username = document.querySelector("input[name='username']").value;alert("登录成功!现在可以回到刚才的页面了!");this.reset();e.preventDefault();}, false);} else {alert("抱歉!您的浏览器连H5表单都不支持!"); }
})();

目前来说,这个API尤其在移动端实际效果太差,使用与否,就看各自需求了…
② BroadCast Channel
你可以认为它对 postMessage 做了封装。它可以帮我们创建一个用于广播的通信频道,当几个页面都监听了同一个频道的消息时,其中某一个页面通过此 API 发送的消息就会被其它页面收到。
它的使用方式你可能会感到熟悉:
// 创建带有标识的频道
const bc=new BroadCastChannel('yxm')
它甚至可以接收一个 DOMString 作为name标识,在其它页面可用通过传入相同的name(bc.name)使用同一个广播频道。
// 发送消息
bc.postMessage(这里可以是字符串,也可以是变量名)
↑ 你完全可以在登录成功后的回调中将用户名传入
// 监听消息
bc.onmessage=function(e){// 通过 e.data 取数据
}
bc.onmessageerror=function(e){// 通过 e 捕获错误
}
除此之外,你当然也可以用 addEventListener 添加 message 监听。
// 关闭
bc.close()
除了上面说的两种,在“原生API”下还有比如 websocket 、server sent 这样的API:他们可以和服务器建立通道,一定程度上避免了“轮询”带来的消耗,非常nice!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
