之前我写过一个插件 Json2html 用于把json数据填充进html模板。但实际使用时有一个情况让我感觉相当蛋疼:amdjs规范的模块没办法把html模板和js同时加载。也就是说,如果一个一步模块带界面,那么必须再走一个获取界面的ajax请求,增加异步逻辑复杂度,而事实上这两块并没必要分开加载。
所以这次我写了一个插件用于解决合并html和js的问题,这个插件名为jsh。
原理
让js支持 <b>多行字符串</b>,我仿照了php的多行字符串语法,避免了需要增加额外引号的麻烦。比如有一个多行字符串:
test line "cdsacac" 这里有双引号
cmwefnieurgn 'dqdwdwed' 这里有单引号
gvererferfffffwefqwef /dcsdcsdc/ 这里有正则标记
那么原生js要这样写:
var a="test line \"cdsacac\" 这里有双引号\n"+
"cmwefnieurgn 'dqdwdwed' 这里有单引号\n"+
"gvererferfffffwefqwef /dcsdcsdc/ 这里有正则标记";
// ****************
//
//
// 其他表示方法不列举了,仅说做法
// 1. 用单引号括起来然后转义单引号,和上述方法原理相同
// 2. 用正则标记括起来然后转义各种相关符号,此方法比较蛋疼用的人很少
// 3. 用一个function包裹注释段,然后提取注释内容,这种方法用的还是挺多的,但是毕竟属于黑魔法,不建议正式项目用
//
//
换成我的新语法则可以这样写:
var a=<<<str
test line "cdsacac" 这里有双引号
cmwefnieurgn 'dqdwdwed' 这里有单引号
gvererferfffffwefqwef /dcsdcsdc/ 这里有正则标记
str;
这样写看上去非常简介,完全没有多余的描述符干扰视线,而且再也不用为了转义里面的字符串浪费时间了。
设计思想
jsh插件仅支持两个接口:
string parse(jsh,data,justParse)
用于把带html的jsh字符串解析成正常的js,返回结果或执行。参数jsh为原始js字符串,data为需要使用的json数据,justParse为true时仅解析不执行
string parseHTML(jshtml,data,justParse)
用于把带jsh标记的html字符串解析成正常html,第一个参数是原始html,后面的和parse方法里的一样
jsh内部提供3种额外语法
多行字符串 <<<t ... \nt
和php里的差不多,不做解释了
echo方法
用于输出到插件的返回值
${变量}
用于多行字符串内直接取上下文的变量,省去了用引号隔开字符串和变量的步骤
实例
<script type="text/javascript">
/*!
* jsh library v1.0
* https://xdelve.com/
* author: treemonster
* email: <admin@xdelve.com>
*
* Copyright treemonster
* Released under the MIT license
*
* Date: 2016-12-13T19:56Z
*/
function Jsh(global){
function _jsh2js(str,data,justParse){
str='(function(){\n\
/* global is allowed here*/\n\
var echo=function(str){\n\
echo._str+=str;\n\
};\n\
echo._str="";echo._res=function(){'+
(function(){
var ret=[];
for(var k in data) ret.push(' var '+k+'='+JSON.stringify(data[k])+';');
if(justParse)
ret.unshift('\n/** when using justParse , data here is not effective \n * please replace this block before use'),
ret.push(' */');
ret.unshift(''),ret.concat('');
return ret.concat('').join('\n');
})()+
str.replace(/\<\<\<([a-z\d]+)(?:(\n[\s\S]+?|.*?))\n[\x20\x09]*\1\b/gi,function(){
var a=arguments;
var html=a[2].substr(1);
var er='"'+html.replace(/\$\{([^\}]+)\}|"|\n/g,function(){
var a=arguments;
switch(true){
case a[0]==='"': return '\\"';
case a[0]==='\n': return '\\n';
case !!a[1]: return '"+'+a[1]+'+"';
}
})+'"';
return er;
})+
';}();return echo._res && typeof echo._res.then==="function" ? echo._res.then(function(a){return echo._str+(a||"");}) :echo._str;})()';
return str;
}
this.parse=function(jsh,data,justParse){
var res=_jsh2js(jsh,data,justParse);
try{
return justParse?res:eval(res);
}catch(e){
return e;
}
};
this.parseHTML=function(jshtml,data,justParse){
if(typeof Promise==='undefined' || typeof JSON==='undefined')
throw new Error('the javascript environment must support `Promise` and `JSON`');
var _parse=this.parse;
var htm=jshtml.split(/\<\?jshtml[\s\S]+?(?:\?\>|$)/g);
var par=function(str){
return justParse?JSON.stringify(str):str;
};
var jshs=[];
jshtml.replace(/\<\?jshtml([\s\S]+?)(?:\?\>|$)/g,function(){
jshs.push(par(htm.shift()),_parse(arguments[1],data,justParse));
});
jshs=jshs.concat(htm.map(par));
return Promise.all(jshs).then(function(res){
return justParse?'Promise.all(['+res.join(',')+']).then(function(res){return res.join("");})':res.join('');
});
};
}
// for amd
if(typeof define!=='undefined' && define.amd)
define('Jsh',function(){return Jsh;});
// for nodejs
else if(typeof module!=='undefined')
module.exports=Jsh;
</script>
<!-- jsh demo -->
<script type="text/jsh" id='a'>
// print multiLine html
echo(<<<tpl
<ul>
<li>aaaa</li>
<li>bbbb</li>
<li>cccc</li>
</ul>
tpl);
// print extern data
echo("code by "+ author +"\n");
// you can also write this way
var list=['x','y','zzz'];
for(var i=0;i<list.length;i++){
echo(<<<tpl
<div>${list[i]}</div>
tpl);
}
</script>
<script type="text/javascript">
console.log(_jsh.parse(a.innerText.trim(),{author:'treemonster'}));
</script>
<!-- jshtml demo -->
<script type="text/jshtml" id='b'>
<!DOCTYPE html>
<head><title>jshtml</title></head>
<div>
<h4>list:</h4>
<?jshtml
for(var i=0;i<divs.length;i++)echo(<<<t
<div>${divs[i]}</div>
t);
?>
</div>
</script>
<script type="text/javascript">
// print the html
console.log(_jsh.parseHTML(b.innerText.trim(),{
divs:['x1','x2','x3']
}));
</script>
justParse的唯一目的就是缓存,纯前端使用不考虑这个问题,之后我会在nodejs版本里补充缓存的代码,要不然每次都正则替换开销是很大的。
写这个插件并不是说Json2html废了,实际上这两个东西用于处理不同的情况。我个人比较讨厌把一堆方法强行塞进一个插件里,搞得那个插件大到恶心。反正不论Json2html还是Jsh,我始终坚持:一个插件只做一件事。
2016/12/13更新
增加全局变量调用。
2016/12/15更新
代码上git
https://github.com/treemonster/Jsh
相关文档
暂无
随便看看