本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-12-15
Web Widget指的是一块可以在任意页面中执行的代码块,Widget模式是指借用Web Widget思想将页面分解成部件,针对部件开发,最终组合成完整的页面。
Widget模式是一种页面视图开发模式,它将页面粒度化,分解成一个个组件,当然一个组件也对应着一个模块,一个完整的组件包含该模块的完整的视图和一套完整的功能。
所以Widget模式开发中一个组件就要对应一个文件了,而不是某个功能或者某个视图,因此在这个组件文件中你要做两件事,第一创建视图,第二添加相应的功能。
而创建视图就要有一个模板渲染方法,才能使开发更高效。
以下就是一个模块引擎的实现:
// lib/template.js
// F.module 参照上一章 异步模块模式
// 模块引擎模块
F.module('lib/template', function() {
var _TplEngine = function(str, data) {
// 如果数据是数组,则遍历数组逐一渲染。如果是对象则直接渲染,将返回的字符串拼接然后返回
if (data instanceof Array) {
var html = '';
for (var i = 0; i < data.length; i++) {
html += _getTpl(str)(data[i]);
}
return html;
} else {
return _getTpl(str)(data);
}
}
// 获取模板
// 如果str是一个id且元素存在,则判断是input或textarea表单元素,是则获取该元素的value,反之获取元素的innerHTML
// 如果不是,则将str看作模板字符串
var _getTpl = function(str) {
var el = document.getElementById(str);
if (el) {
var html = /^(textarea|input)$/i.test(el.nodeName) ? el.value : el.innerHTML;
return _compileTpl(html);
}
return _compileTpl(str);
};
// 处理模板 <a>{%=test%}</a> 转换成 如下js语句字符串
// template_array.push('<a>',typeof(test) === 'undefined' ? '' : test,'</a>')
var _dealTpl = function(str) {
var _left = '{%';
var _right = '%}';
var s = String(str)
// 转译标签内的<和> 比如 <p> m<n </p> 转换成 <p> m<n </p>
.replace(/</g, '<')
.replace(/>/g, '>')
// 过滤回车、换行、制表符
.replace(/[\r|\n|\t]/g, '')
// {%= %}会优先替换dom中使用的变量
.replace(new RegExp(_left + '=(.*?)' + _right, 'g'), `',typeof($1) === 'undefined' ? '' : $1,'`)
// 所有的写在js中的语句都使用 {% %} 包裹,包括 {} 大括号
// 所有写在html中的语句不需要包裹
// 将 {% 替换为 '); 是因为最后会在前面拼接一个template_array.push(' 所以 {% 其实是每个js语句的结尾,将dom内容使用js语句push进去
.replace(new RegExp(_left, 'g'), `');`)
// 将 %} 替换为 template_array.push(', 是因为最后会在后面拼接 ') 所以 %} 其实是每个js语句的开始 将dom内容使用js语句push进去
.replace(new RegExp(_right, 'g'), `template_array.push('`);
return `template_array.push('${s}')`; // 返回都是一个能够直接eval的js字符串
};
// 编译执行
var _compileTpl = function(str) {
return function(templateData) {
var template_array = [];
// 自执行
(function(data) {
var template_key = '';
for (var key in data) {
template_key += `var ${key} = data['${key}'];`;
}
eval(template_key);
eval(_dealTpl(str));
template_key = null;
})(templateData);
return template_array.join('');
}
};
return _TplEngine;
})
这样使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="test"></div>
<!-- 参照上一张 异步模块模式的main.js -->
<script src="main.js"></script>
<script type="text/template" id="demo_script">
<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>
var data = {
tagCloud: [{
is_selected: true,
title: '这是一本设计模式书',
text: '设计模式'
},
{
is_selected: false,
title: '这是一本HTML',
text: 'HTML'
},
{
is_selected: null,
title: '这是一本CSS',
text: 'CSS'
},
{
is_selected: '',
title: '这是一本javascript',
text: 'javascript'
},
],
test: 'abc',
is_selected: false
}
// dom模块的实现 参照上一章 异步模块模式
F.module(['lib/template', 'lib/dom'], function (template, dom) {
var str = template('demo_script', data);
dom.html('test', str);
})
// F.module(['lib/template', 'lib/dom'], function (template, dom) {
// var str = template('{% if (is_selected) { %} <a>{%=test%}</a> {% } else { %} <a>test2</a> {%}%}', data);
// dom.html('test', str);
// })
</script>
</body>
</html>
在上面的使用中,就结合 template 实现的模板引擎功能,完成了一个标签云组件模块。
Widget架构模式是页面开发模式,不仅仅是页面功能,甚至页面的每个组件模块都可以独立地开发,这更适合团队中多人开发。并且降低相互之间因功能或者视图创建的耦合影响概率。一个组件即一个文件,也让我们更好地管理一个页面,当然组件的多样化也会组建一个更丰富的页面,同样也会让组件的复用率提高。