架构型设计模式
一类框架结构,通过提供一些子系统,指定他们的职责,并将它们条理清晰的组织在一起
1.同步模块模式
模块化:将复杂的系统分解成高内聚、低耦合的模块,使系统开发变得可控、可维护、可拓展、复用率更高
同步模块模式(SMD),请求发出后,无论模块是否存在,立即执行后续的逻辑,对模块的立即引用
1.1排队开发
多人实现,某一处耦合了多人的实现代码,出现排队开发
1.2模块化开发
工程师独立的去开发自己的模块,模块之间也可相互调用
首先得有一个模块管理器,管理着模块的创建和调度
调度:同步模块调度 异步模块调度
1.3模块管理器
定义一个模块管理对象,再为其创建一个模块定义方法define
//定义模块管理器单体对象
var F = F || {};
//模块方法按理应该放在闭包中,这里为了更清晰明白
F.define = function(str, fn){
var parts = str.split('.'),
old = parent = this,
i = len = 0;
if(parts[0] === 'F'){
parts = parts.slice(1);
}
if(parts[0] == 'define' || parts[0] === 'module'){
return;
}
for(len = parts.length; i < len; i++){
if(typeof parent[parts[i]] === 'undefined'){
parent[parts[i]] = {};
}
old = parent;
parent = parent[parts[i]];
}
if(fn){
old[parts[--i]] = fn();
}
return this;
}
1.4模块调用方法
要使用模块,需要一个'使用'模块方法-module
F.module = function(){
var args = [].slice.call(arguments),
fn = args.pop(),
parts = args[0] && args[0] instanceof Array ? args[0] : args,
modules = [],
modIDs = '',
i = 0,
ilen = parts.length,
parent, j, jlen;
while(i < ilen){
if(typeof parts[i] === 'string'){
parent = this;
modIDs = parts[i].replace(/^F./, '').split('.');
for(j = 0, jlen = modIDs.length; j < jlen; j++){
parent = parent[modIDs[j]] || false;
}
modules.push(parent);
}else{
modules.push(parts[i]);
}
i++;
}
fn.apply(null, modules);
}
1.5调用模块
参数分为两部分,依赖模块与回调执行函数(最后一个参数)
首先遍历并获取所有的依赖模块,并一次保存在依赖模块列表
然后将这些依赖模块作为参数传入执行函数中执行
F.module(['dom', document], function(dom, doc){
dom('test').html('new add!');
doc.body.style.background = 'red';
});
2.异步模块模式
异步模块模式(AMD):请求发出后,继续其他业务逻辑,知道模块加载完成执行后续的逻辑
实现模块开发中对模块加载完成后的引用
2.1异步加载文件中的模块
浏览器中加载文件是异步加载的,也就是说文件开始加载,还可以继续做其他的事情
同步模块模式会立即引用这个模块,加载未完成,是引用不到该模块
2.2给定依赖模块,耐心等待所有模块加载完成再执行
3.Widget模式
一块可以在任意页面中执行的代码块
将页面分解成部件,针对部件开发,最终组合成为完整的页面
4.MVC模式
模型(model)-视图(view)-控制器(controller)
用一种将业务逻辑、数据、视图分离的方式组织架构代码
组件式架构开发,常常将视图、数据、业务逻辑写在一个模块内
组件内容过多会造成层次混乱,增加开发与维护的成本
4.1混乱
当看别人组件的时候,缺少注释,很难追踪数据,代码块不清晰
4.2MVC模式
分层:数据层、视图层、控制层
视图层可以调用数据层创建视图
控制器层可以调用数据层数据与视图层内视图创建页面增添逻辑
//页面加载后创建MVC对象
$(function(){
//初始化MVC对象
var MVC = MVC || {};
MVC.model = function(){};
MVC.view = function(){};
MVC.ctrl = function(){};
});
4.3数据层
每个对象是一个自动执行的函数
3个层次对象可被调用,声明的函数在执行之前不能被调用
执行一遍是为了为其他对象调用提供接口方法
MVC.model = function(){
var M = {};
M.data = {};
M.conf = {};
return {
getData : function(m){
return M.data[m];
},
getConf : function(c){
return M.conf[c]
},
setData : function(m, v){
M.data[m] = v;
return this;
}
setConf : function(c. v){
M.conf[c] = v;
return this;
}
}
}();
通过model接口对象返回的4个操作方法即可对model内部的服务器端数据与配置数据做
增删改查,这样我们就可以在视图对象和控制器对象内部轻松处理数据模型内部数据
4.4视图层
MVC.view = function(){
var M = MVC.model;
var V = {}
return function(v){
V[v]();
}
}();
4.5控制器
MVC.ctrl = function(){
var M = MVC.model;
var V = MVC.view;
var C = {};
}();
4.6侧边导航栏数据模型层
MVC.model = function(){
var M = {};
M.data = {
slideBar : [
{
text : 'xxx',
icon : 'left.png',
content : 'xxx',
img : 'xxx.png',
href : 'xxx.com'
}
]
}
M.conf = {
slideBarCloseAnimate : false
}
return {/*接口方法*//}
}();
4.7侧边导航栏视图层
4.8侧边导航栏控制器层
4.9执行控制器
5.MVP模式
模型(model)-视图(view)-管理器(presenter)
view层不直接引用model层内的数据,而是通过presenter来实现数据访问
所有层次的交互都发生在presenter中
在MVC中视图层因为渲染直接去数据层拿数据,而contrl常常不知道
5.1MVP模式
~(function(window){
var MVP = function(){};
MVP.model = function(){};
MVP.view = function(){};
MVP.presenter = function(){};
MVP.init = function(){}
window.MVP = MVP;
})(window)
5.2数据层
在数据层修改不大,在视图层大刀阔斧
5.3视图层
MVP.view = MVP.view = function(){
return function(str){
return html;
}
}();
5.4管理器
MVP.presenter = function(){
var V = MVP.view;
var M = MVP.model;
var C = {};
return {
init : function(){
for(var i in C){
C[i] && C[i](M, V, i);
}
}
};
}();
5.5将数据层与视图层完全解耦,互不影响
6.MVVM模式
模型(model)-视图(view)-视图模型(viewmodel)
为视图层量身定做一套视图模型,在视图模型中创建属性和方法
为视图层绑定数据并实现交互
6.1MVP需要创建管理器,一些开发者对JS了解的不是很深入,操作管理器成本太大
能否通过html来创建视图实现页面需求?
6.2视图层的思考
创建视图也就是创建页面内的视图,本质就是写HTML代码
如果将视图作用提升,通过直接书写HTML代码创建视图组件
让控制器或管理器去监听这些视图组件,并进行处理完成预期功能
这对那些只懂HTML代码的开发者,轻松完成功能需求
6.3视图模型层
//~屏蔽压缩报错
~(function(){
//在闭包中获取全局变量
var window = this || (0, eval)('this');
//获取页面字体大小,作为创建页面UI尺寸参照物
var FONTSIZE = function(){
//获取页面body元素字体大小并转换成整数
return parseInt(document.body.currentStyle ? document.body.currentStyle
['fontSize'] : getComputedStyle(document.body, false)['fontSize']);
}();
//视图模型对象
var VM = function(){
//组件创建策略对象
var Method = {
//进度条组件创建方法
progressbar : function(){},
slider : function(){}
}
}();
//将视图模型对象绑定在window上,供外部获取
window.VM = VM;
})();
6.4创建进度条
progressbar : function(dom, data){
//进度条进度完成容器
var progressbar = document.createElement('div'),
param = data.data;
progress.style.width = (param.position || 100) + '%';
dom.className += ' ui-progressbar';
dom.appendChild(progress);
}
6.5创建滑动条
slider : function(dom, data){
var bar = document.createElement('span'),
progress = document.createElement('div'),
totleText = null,
progressText = null,
param = data.data,
width = dom.clientWidth,
left = dom.offsetLeft,
realWidth = (param.position || 100) * width /100;
dom.innerHTML = '';
if(param.totle){
text = document.createElement('b');
progressText = document.createElement('em');
text.innerHTML = param.totle;
dom.appendChild(text);
dom.appendChild(progressText);
}
setStyle(realWidth);
dom.className += ' ui-slider';
dom.appendChild(progress);
dom.appendChild(bar);
function setStyle(w){
progress.style.width = w+ 'px';
bar.style.left = w - FONTSIZE / 2 + 'px';
if(progressText){
progressText.style.left = w - FONTSIZE / 2 * 2.4 + 'px';
progressText.innerHTML = parseFloat(w / width * 100).tofixed(2) + '%';
};
}
}
6.6让滑动条动起来
slider : function(dom, data){
bar.onmousedown = function(){
document.onmousemove = function(event){
var e = event || window.event;
var w = e.clientX - left
setStyle(w < width ? (w > 0 ? w : 0) : width);
}
document.onselectstart = function(){
return false;
}
}
document.onmouseup = function(){
document.onmousemove = null;
document.onselectstart = null;
}
}
6.7为组件添睛
获取数据的方法getBindData,通过元素中给定的数据映射标识获取对应数据来渲染我们的视图
//视图模型对象
var VM = function(){
//组件创建策略对象
var Method = {
//....
}
function getBindData(dom){
var data = dom.getAttribute('data-bind');
return !!data && (new Function("return ({" + data +"})");
}
}();
6.8查找组件
获取需要渲染的组件
//视图模型对象
var VM = function(){
//组件创建策略对象
var Method = {
//....
}
function getBindData(dom){}
return function(){
var doms = document.body.getElementsByTagName('*'),
ctx = null;
for(var i = 0; i < doms.length; i++){
ctx = getBindData(doms[i]);
ctx.type && Method[ctx.type] && Method[ctx.type](doms[i], ctx);
}
}
}();
6.9展现组件
var demo1 ={
position : 60,
totle : 200
},
demo2 = {
position : 20
},
demo3 = {position : 50};
window.onload = function(){
//渲染组件
VM();
}