Widget模式

Widget模式是指借用Web Widget思想将页面分解成组件,针对部件开发,最终组合成完整的页面,Web Widget指的是一块可以在任意页面中执行的代码块,Widget模式不属于一般定义的23种设计模式的范畴,而通常将其看作广义上的架构型设计模式。

描述

模块化开发使页面的功能细化,逐一实现每个功能模块来完成系统需求,这是一种很好的编程实践,在简单模板模式实现的模板引擎的帮助下可以非常方便的完成这个实例,这将更适合多人团队开发,降低相互之间因为功能或者视图创建的耦合影响概率,组件的多样化也能够组建更加丰富的页面,同样也会让组件的复用率提高。

实现

// dom.js
F.module("./dom", function() {
return {
g: function(id) {
return document.getElementById(id);
},
html: function(id, html) {
if (!html) return this.g(id).innerHTML;
else this.g(id).innerHTML = html;
}
}
});
// template.js
F.module("./template", function() { /***
* 模板引擎,处理数据的编译模板入口
* @param str 模块容器id或者模板字符串
* @param data 渲染数据
**/
var _TplEngine = function(str, data) {
// 如果数据是数组
if (data instanceof Array) {
// 缓存渲染模板结果
var html = "";
// 数据索引
var i = 0;
// 数据长度
var len = data.length;
// 遍历数据
for (; i < len; i++) {
// 缓存模板渲染结果,也可以写成
// html += arguments.callee(str, data[i]) ;
html += _getTpl(str)(data[i]);
}
// 返回模板渲染最终结果
return html;
} else {
// 返回模板渲染结果
return _getTpl(str)(data);
}
};
/***
* 获取模板
* @param str 模板容器id,或者模板字符串
**/
var _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);
}
};
// 处理模板
var _dealTpl = function(str) {
// 左分隔符
var _left = "{%";
// 右分隔符
var _right = "%}";
// 显示转化为字符串
return String(str)
// 转义标签内的<如:<div>{%if(a&lt;b)%}</div> -> <div>{%if(a<b)%}</div>
.replace(/&lt;/g, "<")
// 转义标签内的>
.replace(/&gt;/g, ">")
// 过滤回车符,制表符,回车符
.replace(/[\r\t\n]/g, "")
// 替换内容
.replace(new RegExp(_left + "=(.*?)" + _right, "g"), "',typeof($1) === 'undefined' ? '' : $1, '")
// 替换左分隔符
.replace(new RegExp(_left, "g"), "');")
// 替换右分隔符
.replace(new RegExp(_right, "g"), "template_array.push('"); };
/***
* 编译执行
* @param str 模板数据
**/
var _compileTpl = function(str) {
// 编译函数体
var fnBody = "var template_array=[];\nvar fn=(function(data){\nvar template_key='';\nfor(key in data){\ntemplate_key +=(''+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;
});
<!-- demo.html -->
<!DOCTYPE html>
<html> <head>
<title>Widget模式</title>
</head> <body>
<div id="app"></div>
</body>
<script type="text/javascript">
(function(F) {
const moduleCache = {}; function getUrl(moduleName) {
return String(moduleName).replace(/\.js$/g, "") + ".js"
} function loadScript(src) {
let _script = document.createElement("script");
_script.type = "text/javascript";
_script.charset = "UTF-8";
_script.async = true;
_script.src = src;
document.body.appendChild(_script);
} function setModule(moduleName, params, callback) {
let _module = null,
fn = null;
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);
}
} function loadModule(moduleName, callback) {
let _module = "";
if (moduleCache[moduleName]) {
_module = moduleCache[moduleName];
if (_module.status === "loaded") {
// 这个很重要,loadModule一定是异步的,effectiveJS 上的某一条建议有写,永远不要同步的调用异步函数,这非常重要
setTimeout(callback(_module.exports), 0);
} else {
// 加载完成的时候调用
_module.onload.push(callback);
}
} else {
// 第一次加载
moduleCache[moduleName] = {
moduleName: moduleName,
status: "loading",
exports: null,
onload: [callback]
};
loadScript(getUrl(moduleName));
}
} F.module = function(...args) {
// 获取模块构造函数(参数数组中最后一个参数成员)
let callback = args.pop();
// 获取依赖模块(紧邻回调函数参数,且数据类型为数组)
let deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [];
// 该模块url(模块ID)
let url = args.length ? args.pop() : null;
// 依赖模块序列
let params = [];
// 未加载的依赖模块数量统计
let depsCount = 0; if (deps.length) {
deps.forEach((v, i) => {
// 增加未加载依赖模块数量统计
depsCount++;
// 异步加载依赖模块
loadModule(deps[i], function(mod) {
// 依赖模块序列中添加依赖模块数量统一减一
depsCount--;
params[i] = mod;
// 如果依赖模块全部加载
if (depsCount === 0) {
// 在模块缓存器中矫正该模块,并执行构造函数
setModule(url, params, callback);
}
});
})
} else { // 无依赖模块,直接执行回调函数
// 在模块缓存器中矫正该模块,并执行构造函数
setModule(url, [], callback);
}
} })((() => window.F = ({}))());
</script>
<!-- srcpt模板内容 -->
<script type="text/template" id="tpl">
<div id="tag_cloud">
{% for(var i = 0; i < tagCloud.length; i++){
var ctx = tagCloud[i] ; %}
<a href="#" class="tag_item
{% if(ctx["is_selected"]){ %}
selected
{% } %}" title="{%=ctx["title"]%}">{%=ctx["text"]%}
</a>
{% } %}
</div>
</script>
<!-- 自定义模板 -->
<!--===============模板种类结束===========-->
<script type="text/javascript">
// 模拟数据
var data = {
tagCloud: [
{ is_selected: true, title: "Pattern", text: "设计模式" },
{ is_selected: false, title: "HTML", text: "HTML" },
{ is_selected: null, title: "CSS", text: "CSS" },
{ is_selected: "", title: "JavaScript", text: "JavaScript" },
]
} F.module(["./template", "./dom"], function(template, dom) {
// 服务器端获取到data数据逻辑
// 创建组件视图逻辑
var str = template("tpl", data);
dom.html("app", str);
// 组件其他交互逻辑
});
</script>
</html>

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://en.wikipedia.org/wiki/Web_widget
https://segmentfault.com/a/1190000019541819
https://blog.csdn.net/yuzhiboyouzhu/article/details/78998860

Widget模式的更多相关文章

  1. js设计模式总结5

    1.同步模块模式 随着页面功能的增加,系统的业务逻辑越来越复杂.多人开发的功能经常耦合在一起.有时分配任务给多人实现的时候,常常因为某一处功能耦合了很多人的代码,出现排队修改的现象,这很不利于团队开发 ...

  2. Flex 加载pdf

    如果想要在flex加载pdf,虽然pdf格式是开源的,但是自己去解析太麻烦了,pdf还要分页之类的,现在网上各种文档上传可以在线看很多都是pdf,当然也有word,excel之类,其实很多都是转了sw ...

  3. Sencha ExtJS 6 Widget Grid 入门

    最近由于业务需要,研究了一下Sencha ExtJS 6 ,虽然UI和性能上据相关资料说都有提升,但是用起来确实不太顺手,而且用Sencha cmd工具进行测试和发布,很多内部细节都是隐藏的,出了问题 ...

  4. Android开发之MVP模式的使用

    前几天发现,在Android项目代码里有一个Activity类行数居然有1000多行,而600行左右都是逻辑控制,真正和页面控件处理相关的代码不多,虽然可以用#region <>...#e ...

  5. MVP模式(Android)

    以前在写项目的时候,没有过多考虑架构模式的问题,因为之前一直做J2EE开发,而J2EE都是采用MVC模式进行开发的,所以在搭建公司项目的时候,也是使用类似MVC的架构(严格来讲,之前的项目还算不上MV ...

  6. Android Activity的加载的模式

    ---恢复内容开始--- 本文来自http://www.cnblogs.com/lwbqqyumidi/p/3771542.html launchMode在多个Activity跳转的过程中扮演着重要的 ...

  7. Android开发之---Activity启动模式

    在Android开发中,启动一个新的activity我们可以使用startActivity或startActivityForResult,Android系统使用栈的方式来管理一个APP的页面显示与保存 ...

  8. Handler+ExecutorService(线程池)+MessageQueue模式+缓存模式

    android线程池的理解,晚上在家无事 预习了一下android异步加载的例子,也学习到了一个很重要的东东 那就是线程池+缓存  下面看他们的理解.[size=1.8em]Handler+Runna ...

  9. 彻底弄懂Activity四大启动模式

    最近有几位朋友给我留言,让我谈一下对Activity启动模式的理解.我觉得对某个知识点的理解必须要动手操作才能印象深刻,所以今天写一篇博文,结合案例理解Activity启动模式.由于之前看过" ...

  10. Extjs MVC开发模式详解

    Extjs MVC开发模式详解   在JS的开发过程中,大规模的JS脚本难以组织和维护,这一直是困扰前端开发人员的头等问题.Extjs为了解决这种问题,在Extjs 4.x版本中引入了MVC开发模式, ...

随机推荐

  1. [转帖]ES集群开启X-pack认证

    https://www.cnblogs.com/jclty/p/12913996.html 1.下载 1 # wget https://artifacts.elastic.co/downloads/e ...

  2. [转帖]Nginx应用调优案例

    https://bbs.huaweicloud.com/blogs/146367 [摘要] 1 问题背景nginx的应用程序移植到TaiShan服务器上,发现业务吞吐量没有达到硬件预期,需要做相应调优 ...

  3. 虚拟化平台IO劣化分析

    虚拟化平台IO劣化分析 背景 最近同事让帮忙做几个虚拟机进行性能测试. 本来应该搭建CentOS/Winodws平台进行相关的测试工作. 但是为了环境一致性, 使用了ESXi6.7 进行虚拟化 然后这 ...

  4. [转帖]一文解决内核是如何给容器中的进程分配CPU资源的?

    https://zhuanlan.zhihu.com/p/615570804   现在很多公司的服务都是跑在容器下,我来问几个容器 CPU 相关的问题,看大家对天天在用的技术是否熟悉. 容器中的核是真 ...

  5. 《Javascript高级程序设计》读书笔记——函数与闭包

    函数与闭包 函数创建 创建函数有两种方式,第一种是函数声明.函数声明有一个很重要的特征就是函数声明提升(function declaration hoisting),意思是在执行代脚本前会先读取所有的 ...

  6. React中css的module

    处理css全局作用 现在有这样一个场景: A页面和B页面都有一个相同的类名 我们在A页面中有引入css. B页面没有css 在我们切换A和B页面的时候. A页面的css也作用在了B页面. 我们只希望A ...

  7. 用Unity3D做游戏开发在Android上的常用调试方法

    Hdg Remote Debug 远程调试 游戏运行在手机上,可以通过pc端的unity来随时修改当前场景中GameObject的变量,从而改变手机上运行时的表现.比如,我可以勾掉下图中的" ...

  8. 如何控制Tomcat的catalina.out的大小

    catalina.out文件,数据主要来源为:System.out 和 System.err 在控制台上直接输出的信息. 编码时应避免使用System.out.println()和e.printSta ...

  9. Yarp 与 Nginx性能大比拼不出所料它胜利了!

    Yarp 与 Nginx 性能大比拼 测试环境: Ubuntu 22.04.3 LTS (GNU/Linux 6.5.0-14-generic x86_64) Intel(R) Xeon(R) CPU ...

  10. 微软Bing正面对阵谷歌!竞标争夺Firefox默认搜索引擎

    在今早的谷歌I/O大会上,谷歌带来了全新的PaLM 2人工智能语言模型,并将用该模型升级Bard对话机器人以及谷歌搜索. 但面对来势汹汹的谷歌,微软似乎并不打算退却. 根据The Informatio ...