展开目录
jshtml模板引擎
javascriptjsh
X
陈尼玛的博客
记录开发生涯的踩坑经历,用时间来验证成长
加载中

之前我写过一个插件 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;

这样写看上去非常简介,完全没有多余的描述符干扰视线,而且再也不用为了转义里面的字符串浪费时间了。

设计思想

实例

<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

相关文档

暂无

随便看看

  1. 记一次nodejs内存泄漏的排查经历

  2. mac ssh透过代理连接

  3. 华为等国产手机rem宽度超过实际宽度

  4. sass变量和继承类写法

  5. SSL certificate problem: self signed certificate in certificate chain

  6. jxa运动指令脚本

  7. mongodb 批量修改字段语句

  8. webrtc服务搭建

  9. webrtc泄漏本地ip信息

  10. 单页应用的单向数据流的流程图

  11. 树莓派配置wifi热点

  12. TIME_WAIT过多

  13. ssl 证书生成方式

  14. 树莓派配置收发邮件

  15. mysql选取内容导出到文件

  16. ie8上Image.onload不触发问题

  17. 简易版事件封装

  18. bootstrap modal弹框导致ie无法获取焦点

畅言模块加载中