版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuelian3015/article/details/89483679
指的是一类框架结构,通过提供一些子系统,指定它们的职责,并且将它们调理清晰组织在一起。主要包含了同步模块模式、异步模块模式、Widget模式、MVC模式、MVP模式、MVVM模式
模块化
把复杂的系统分解为高内聚、低耦合的模块,让系统开发变得可控、可维护、可拓展,提高模块的复用率。
同步模块模式(SMD)
请求发出以后,不论模式是否存在。立即执行后续的逻辑,实现模块开发中对模块的立即引用。
模块管理与创建方法
/***
* 同步模块模式
*/
//定义模块管理单体对象
var F = F || {};
/**
* 定义模块方法
* @param str 模块路由
* @param fn 模块方法
*/
F.define = function(str,fn){
//解析路由
var parts = str.split('.'),
old = parent = this, //old为当前模块的祖父模块。parent是当前模块的父模块
i =len = 0;
//第一个模式是模块管理器单体对象,则移除
if (parts[0]==="F") {
parts = parts.slice(1);
}
//屏蔽对define和Module模块方法的重写
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;
}
//创建模块
F.define("string",function(){
return {
trim:function(str){
return str.replace(/^\s+|\s+$/g,"")
}
}
});
//获取元素方法dom(),html()设置元素内容
F.define("dom",function(){
var $ = function(id){
$.dom = document.getElementById(id);
return $;
}
$.html = function(html){
if (html) {
this.dom.innerHTML = html;
return this;
}else{
return this.dom.innerHTML;
}
}
return $;
});
//添加addclass方法
F.dom.addClass = function(type,fn){
return function(className){
if (!~this.dom.className.indexOf(className)) {
this.dom.className += " " + className;
}
}
}();
//模块调用方法
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);
}
//测试
F.module(['dom',document],function( dom,doc){
dom('test').html("new addd");
doc.body.style.background = "red"
});
F.module("dom","string.trim",function(dom,trim){
var html = dom("test").html();
var str = trim(html);//除去字符串的空白部分
console.log(html+"****"+str)
})
F.dom('test').addClass("tghfgh");
F.dom('test').html(154654);
异步模块模式(AMD)
请求发出之后,继续其他业务逻辑,直到模块加载完成执行后续的逻辑,实现模块开发中对模块加载完成后的引用。
/***
* 异步模块
*/
//在闭包中传入模块管理器对象F
~(function(F){
//模块缓存器,存储已经创建的模块
var moduleCache = {}
})((function(){
return window.F = {};
})());
/***
* 创建或者调用模块方法
* @param url 参数为模块的url
* @param deps 参数为依赖模块
* @param callback 参数为模板主函数
*/
F.module = function(url,modDeps,modCallback){
//把参数转化为数组
var args =[].slice.call(argsuments),
//获取模块构造函数(参数数组中最后一个参数成员)
callback = args.pop(),
//获取依赖模块(紧邻回调函数参数,,且数据类型为数组)
deps =(args.length && args[args.length-1] instanceof Array) ? args.pop() :[],
//模块url(模块ID)
url = args.length ? args.pop() : null,
//依赖模块序列
params = [],
//未加载的依赖模块数量统计
depsCount = 0,
//依赖模块序列的索引
i = 0,
// 依赖模块序列的长度
len;
if (len = deps.length) {
//遍历依赖模块
while (i<len) {
//闭包保存i
(function(i){
//增加未加载的依赖模块
depsCount++;
loadModule(deps[i],function(mod){
//依赖模块序列中添加依赖模块接口引用
params[i] = mod;
//依赖模块加载完成,依赖模块数量统计减一
depsCount--;
//若依赖模块全部加载
if (depsCount===0) {
//在模块缓存器中矫正该模块,并且执行构造函数
setModule(url,params.callback);
}
});
})(i)
i++;
}
}else{
setModule(url,[],callback)
}
}
var moduleCache = {},
/***
* 异步加载依赖模块所在文件
* @param moduleName 模块;路径(ID)
* @param callback 模块加载完成回调函数
*/
loadModule = function(moduleName,callback){
var _module ;
if (moduleCache[moduleName]) {
_module = moduleCache[moduleName];
if (_module.status === "loaded") {
setTimeout(callback(_module.exports), 0);
}else{
_module.onload.push(callback);
}
}else{
moduleCache[moduleName] = {
moduleName : moduleName,
status:'loading',
exports:null,
onload:[callback]
};
loadScript(getUrl(moduleName));
}
},
//获取文件路径
getUrl = function(moduleName){
return String(moduleName).replace(/\.js$/g,"")+".js";
},
loadScript = function(src){
var _script = document.createElement("script");
_script.type = "text/script";
_script.charset = "utf-8";
_script.async = true;
_script.src = src;
document.getElementsByTagName("head")[0].appendChild(_script);
};
/**
* 设置模块并且执行模块构造函数
* @param moduleName 模块ID名称
* @param params 依赖模块
* @param callback 模块构造函数
*/
setModule = function(moduleName,params,callback){
var _module,fn;
if (moduleCache[moduleName]) {
_module = moduleCache[moduleName];
_module.status = "loaded";
_module.exports = callback ? callback.apply(_module,params) : null;
while (fn = _module.onload.shift()) {
fn(_module.exports);
}
}else{
callback && callback.apply(null,params);
}
}
//测试
F.module("lib/dom",function(){
return {
g:function(id){
return document.getElementById(id);
},
html:function(id,html){
if (html) {
this.g(id).innerHTML = html;
}else{
return this.g(id).innerHTML;
}
}
}
});
Widget模式
Web Widget:指的是一块可以在任意地方执行的代码块。Widget模式是借用Web Widget的思路把页面分解为组件,针对组件开发,最后合成最终完整的页面。
/****
* Widget 模式
* 视图模块化
*/
//模板引擎模板
F.module("lib/template",function(){
/**
* 模板引擎 处理数据与编译模板入口
* @param str 模板容器ID 模板字符串
* @param data 渲染数据
*/
var _TplEngine = function(str,data){
//
if (data instanceof Array) {
var html = "",
i = 0,
len = data.length;
for(;i<len;i++){
html += _getTpl(str)(data[i]);
}
return html;
}else{
return _getTpl(str)(data);
}
},
/**
* 获取模板
* @param str 模板容器ID,或者模板字符串
*/
_getTpl = function(str){
var ele = document.getElementById(str);
if (ele) {
//若是input或者textarea元素就获取该元素的value值,否则获取元素内容。
var html = /^(textarea | input)$/i.test(ele.nodeName) ? ele. value : ele.innerHTML;
//编译模板
return _compileTpl(html)
}else{
//编译模板
return _compileTpl(str);
}
},
//处理模板
_dealTpl = function(str){
//左右分隔符
var _left = '{%',
_right = '%}';
return String(str)
// 转义标签内的<,>
.replace(/</g,'<')
.replace(/>/g,">")
//过滤回车符、制表符和空格符
.replace(/[\r\t\n]/g,'')
//替换内容
.replace(new RegExp(_left+'=(.*?)'+_right,'g'),"',typeof($l)==='undefined'?'' : $l,'")
//替换左边分隔符
.replace(new RegExp(_left,'g'),"');")
//替换右边分隔符
.replace(new RegExp(_right,'g'),"template_array.push('");
},
/**
* 编译执行
* @param str 模板数据
*/
_compileTpl = function(str){
var fnBody= "var template_array = [];\n var fn = (function(data){\nvar template_key = '';\nfor(key in data){\ntemplate_key += ('var ' + key+'=data[\"'+key+'\"];');\n}\neval(template_key);\ntemplate_array.push('"+=_dealTpl(str)+"');\ntemplate_key = null;\n})(templateData);\nfn = null;\nreturn template_array.join('');";
return new Function("templateData",fnBody);
},
return _TplEngine;
});
MVC模式
就是模型(model)——视图(view)——控制器(controller),使用一种将 业务逻辑、数据、视图分离的方式组织架构代码。
/**
* MVC模式
*/
window.onload = function(){
//初始化MVC对象
var MVC = MVC || {};
// 初始化MVC数据模型层
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对应数据v
M.data[m] = v;
return this;
},
//设置配置数据(通常在页面中执行某些操作,为做记录而更配置数据)
setConf:function(c,v){
//配置数据字段c对应的配置数据V
M.conf[c] = v;
return this;
}
}
}();
//初始化MVC视图层
MVC.view = function(){
//模型数据层对象操作方法引用
var M = MVC.model;
//内部视图创建方法对象
var V = {};
//获取视图接口方法
return function(v){
//根据视图名称返回视图(由于获取的是一个方法,需要将该执行方法执行一遍以获取相应的视图)
V[v]()
}
}();
//初始化MVC控制器层
MVC.ctrl = function(){
//模型数据对象操作方法引用
var M = MVC.model;
//视图数据层对象操作方法引用
var V = MVC.view;
//控制器创建方法对象
var C = {};
}();
}
MVP 模式
模型(model)——视图(View)——管理器(Presenter);View层不能直接使用model层内的数据,通过Presenter层实现对Model层内的数据访问。所有的交互都在Presenter中进行。代码思路如下(仅供参考):
/**
* MVP模式
*/
~(function(window){
//MVP构造函数
var MVP = function(){};
//数据层
MVP.model = function(){
var M ={};
M.data = {};
var data = {};
var conf = {};
return {
getData:function(m){
return M.data[m];
},
/**
* 设置数据
* @param m 模块名称
* @param v 模块数据
*/
setData:function(m,v){
M.data[m] = v;
return v;
},
getConf:function(c){
return M.conf[c]
},
/**
* 设置配置
* @param c 配置项的名称
* @param v 配置项值
*/
setConf:function(c,v){
M.conf[c] = v;
return v;
}
}
}();
//视图层
MVP.view = function(){
var REPLACEKEY = '__REPLACEKEY__';
/**
* 获取完整模板
* @param {*} str 元素字符串
* @param {*} type 元素类型
*/
function getHTML(str,type){
//只处理字符串中第一个{}中的内容
return str.replace(/^(\w+)([^\{\}]*)?(\{([@\w]+)\})?(.*?)$/,function(match,$1,$2,$3,$4,$5){
$2 =$2 || ""; //元素属性参数容错处理
$3 = $3 ||""; //{元素内容}参数容错处理
$4 = $4 || ""; //元素内容参数容错处理
$5 = $5.replace(/\{([@\w]+)\}/g,''); //去除元素内容后面添加的元素属性中的{}内容
return type === "in"?
'<'+$1+$2+$5+'>'+$4+REPLACEKEY+'</'+$1+">" :
type === "add" ?
'<'+$1+$2+$5+">"+$4+"</"+$1+'>'+REPLACEKEY :
'<'+$1+$2+$5+">"+$4+"</"+$1+">";
}).replace(/#([@\-\w]+)/g,' id="$l"') //处理特殊标识 #--id
.replace(/#([@\-\s\w]+)/g,' class="$l"')//处理特殊标识 #--class
.replace(/\[(.+)\]/g,function(match,key){//处理其他属性组
var a = key
.replace(/'|"/g,'')//过滤其中的引号
.split(" "),//以空格分组
h = ""; //属性模板字符串
for(var j =0,len = a.length;j<len;j++){
//处理拼接每一个属性
h += ' ' + a[j].replace(/=(.*)/g,'="$l"');
}
//返回属性组模板字符串
return h;
})
//处理可以替换内容,
.replace(/@(\w+)/g,'{#$1#}');
}
/**
* 数组迭代
* @param arr 数组
* @param fn 回调函数
*/
function eachArray(arr,fn){
for(var i=0,len = arr.length;i<len;i++){
fn(i,arr[i],len);
}
}
/**
* 替换兄弟元素模板或者子元素模板
* @param str 原始字符串
* @param rep 兄弟元素模板或者子元素模板
*/
function formateItem(str,rep){
return str.replace(new RegExp(REPLACEKEY,"g"),rep);
}
/**
* 模板解析
*/
return function(str){
var part = str.replace(/^\s+|\s+$/g,"").replace(/^\s(>)\s+$/g,"$l").split(">"),
html = REPLACEKEY,
item,
nodeTpl;
eachArray(part,function(partIndex,partValue,partLen){
item = partValue.split("+");
nodeTpl = REPLACEKEY;
eachArray(item,function(itemIndex,itemValue,itemLen){
nodeTpl = formateItem(nodeTpl,getHTML(itemValue,itemIndex === itemLen - 1 ? (partIndex === partLen -1 ? "":"in"):"add"));
});
html = formateItem(html,nodeTpl);
})
return html;
}
}();
//管理器层
MVP.presenter = function(){
var V = MVP.view;
var M = MVP.model;
var C = {
/***
* 导航管理
* @param M 数据层对象
* @param V 视图对象
*/
nav:function(M,V){
var data = M.getData("nav");
data[0].choose = 'choose';
data[data.length-1].list = "last";
var tpl =V('li.@mode @choose @last[data-mode=@mode]>a#[email protected]@mode[href=url title=@text]>i.nav-icon-@mode+span{@text}');
$.create("ul",{
'class':"navigation",
"id":"nav"
}).html(
A.formateString(tpl,data)
).appendTo("container");
}
};
return {
init:function(){
for(var i in C){
C[i] && C[i](M,V,i)
}
}
}
}();
//MVP入口
MVP.init = function(){
this.presenter.init()
}
//暴露MVP对象。在外部可以访问MVP
window.MVP = MVP;
})(window);
window.onload = function(){
MVP.init();
}
MVVM模式
模型(model)——视图(view) ——视图模型(viewModel):给视图层定做视图模型,并且在视图模型中创建属性和方法。
/**
* MVVM模式
*/
~(function(){
var window = this || (0,eval)('this');
var FONTSIZE = function(){
return parseInt(document.body.currentStyle ? document.body.currentStyle["fontSize"] : getComputedStyle(document.body,false)["fontSize"]);
}();
var VM = function(){
var Method = {
/**
* 进度条
* @param {*} dom 进度条容器
* @param {*} data 进度条数据模型
*/
progressbar :function(dom,data){
var progress = document.createElement("div");
var param = data.data;
progress.style.width = (param.progress || 100)+"%";
dom.className += ' ui-progressbar';
dom.appendChild(progress);
},
/**
* @name 滑动条组创建方法
* @param dom 滑动条容器
* @param data 滑动条数据模型
*/
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)+"%"
};
}
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;
}
}
}
function getBindData(){}
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](dosm[i],ctx);
}
}
}();
window.VM = VM;
})();