js设计模式在web前端开发中的实践——网站登录
Posted 恪愚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js设计模式在web前端开发中的实践——网站登录相关的知识,希望对你有一定的参考价值。
本文,笔者将以一个登录模块的开发流程,向各位说明穿插在其中的知识点 —— 【单例模式】和【发布-订阅模式】的使用。
OK,步入正题。
假如你是一个大型网站的前端开发人员,在经过激烈地讨论以后,决定让你负责登录模块的开发。
先说,这个网站很大,所以有很多模块,比如:header头部、nav导航、消息列表、购物车… 这些模块有一个共同的特点,就是必须先用ajax异步请求获取用户的登录信息 —— 这是正常的,比如header中就要显示用户的名字和头像。
所以你很重要。
你着手做了。你的构思是:仿Web QQ那样。比如当点击了左边导航栏里的“请登录”的头像时,就会弹出一个遮罩层 + 一个登录浮窗。很明显这个浮窗在页面中总是唯一的。
第一种解决方案是在页面加载完成以后便创建好这个div浮窗,他一开始是处于隐藏状态的,当用户点击时,才开始显示 —— 我想,用js控制的display切换会有帮助。
但你很快就会发现一个问题:也许用户进入这个页面只是随便逛逛、看看天气、or打打游戏,根本不想进行登录操作。这时,这个“总是一开始就被创建好的登录浮窗”就有可能成为白白浪费一些DOM节点的“元凶”。
你很快又有了想法,决定让用户点击对应区域时再去加载。你可能会写类似如下代码:
<body>
<button id="loginBtn">登录</button>
</body>
//js
<script>
var createLoginLayer=function()
var div=document.createElement('div');
div.innerhtml="我是登录浮窗";
div.style.display="none";
document.body.appendChild(div);
return div;
document.querySelector('#loginBtn').onclick=function()
var loginBtn=createLoginLayer();
loginBtn.style.display="block";
</script>
你突然发现,这样做虽然避免了每次页面打开时的DOM浪费,却产生看一个更大的问题:每次click时都会创建一个新的div!虽然我们可以在点击“关闭”时去销毁掉这个ElementNode,但这样频繁地创建和删除结点,在一个页面上,明显是不合理,也是不必要的。
于是你自然地想到了前几天看到的 惰性单例设计模式 ,可以用一个变量去判断是否已创建过相同的div。 于是,上面代码中的js部分就变成了这样:
var createLoginLayer=(function()
var div;
return function()
if(!div)
div=document.createElement('div');
div.innerHTML="我是登录浮窗";
div.style.display="none";
document.body.appendChild(div);
return div;
)();
document.querySelector('#loginBtn').onclick=function()
var loginBtn=createLoginLayer();
loginBtn.style.display="block";
OK,虽然它还有些许缺点(复用性差),但对于几个功能不冲突的页面来说还算“绰绰有余”,你心满意足地用了ajax/fetch/axios/vue-resource完成了登陆功能。
但现在麻烦又来了。正如前面所说,你所做工作关联性极大,但你不知道除了header、nav、消息列表、购物车之外,将来还有哪些模块需要用到这些用户信息。但如果他们和用户信息之间产生了强耦合性,就比如你按如下方式写了功能代码:
login.succ(function(data)
header.setAvatar(data.avatar);
nav.setAvatar(data.avatar);
message.refresh(); //刷新消息列表
cart.refresh(); //刷新购物车列表
);
现在虽然只有登录模块是你负责编写的,但你还要了解header里设置头像的方法叫setAvatar、购物车中刷新页面的方法叫refresh,,,这可不是个好消息 —— 这种耦合会使程序变得“僵硬”。
试想某一天,这个项目里又增加了一个“收货地址”管理模块。它不是你负责完成的,此时你正在外地度过你一年仅几天的可怜假期,但同事却给你打了一个电话:“Hello,登录后还要麻烦刷新下地址列表!” 于是你不得不打开电脑,找到了不知道几个月前写的那段login.succ
的代码片段,在此函数最后加了一句:
address.refresh(); //刷新地址列表
天哪!这是多可怜的一件事!
这时你终于想起重构这些代码:你又那么“恰好”的想起了翻看过的 发布-订阅设计模式 。你欣喜若狂。
我们就会越来越疲于应付一些突如其来的业务要求,正比如大量重复相同且没什么意义的代码。要么跳槽了事,要么必须学会重构。
使用发布—订阅模式重写之后,对用户信息感兴趣的业务模块将自行订阅登录成功的消息事件。 当登录成功时,登录模块只需要发布登录成功的消息,而业务方接受到消息之后,就会开始进行各自的业务处理,登录模块并不关心业务方究竟要做什么,也不想去了解它们的内部细节。
改善过后代码如下:
$.ajax('xxx?login',function(data)
login.trigger('loginSucc',data); //发布登录成功的消息
);
//各模块去监听消息
var header=(function()
login.listen('loginSucc',function(data)
header.setAvatar(data.avatar);
);
return
setAvatar:function(data)
console.log('设置header头像');
)();
//...
假如有一天,项目中增加了一个刷新收货地址列表的行为,那么只要在“收货地址”模块里加上监听消息的方法,即可。而这些你就完全不必操心了:
var address=(function()
login.listen('loginSucc',function(data)
address.refresh(data);
);
return
refresh:function(avatar)
console.log('正在刷新...');
)();
以上是关于js设计模式在web前端开发中的实践——网站登录的主要内容,如果未能解决你的问题,请参考以下文章