大概是一年多以前还在一淘实习的时候, 萌生了这么个想法, 如果一个模板可以是基数据驱动的, 那能胜任的工作就从现在更多的格式化字符串和其他一些简单的东西变得更加复杂和强大. 当然因为是数据驱动的, 在写这样一个模板时, 也将体会到数据驱动带来的逻辑上的优势. 不过也是因为各种原因, 当时做完第一步的模板解析之后, 就没再继续了. 因为要做好, 略微困难, 而且不像原来做Prever什么的时候, 虽然代码总量大, 但可以分开成很多小块, 今天断开一点, 明天稍微回想下继续写就好.
除此之外, 另外一个数据驱动的小库, Drop(未更新), 倒是做了出来, 虽然还有诸多不完善, 到最后肯定也免不了被重写的命运… 但就实践来看, 这种方式的确是很实用的.
那回归可能会基于Drop(顺便Drop最近的版本是基于VEJIS的)之上的这个模板系统, 之前取名叫Sonne, 以后多半也是这个名字吧. 前些时候了解了下lisp语言, 才发现它和lisp之间还有一点点相似之处. 这里贴一段很久很久以前写的示例.
<!-- comments -->
{header
<img src="xxx.jpg" />
<h1>{title}</h1>
<p><span>{tip}</span><span>{tip}</span>{description}</p>
}
{nav
<ul>
{items[]
<li>
{#link {
{@hash page}
{@value home}
{@inner {home}}
{@class nav-link}
}}
</li>
}
</ul>
{#if {
{@if {#cookies loggedin}}
{@then <a href="#logout">log out</a>}
{@else <a href="#login">log in</a>}
}}
}
{content
<div>
{#async {
{@type html}
{@url content.ashx?page={#hash { {@name page} {@default home} }}}
{@loading
loading...
}
{@loaded {data}}
}}
</div>
}
{sidebar
<div>
{#async {
{@type json}
{@url sidebar.ashx?page={#hash { {@name page} {@default home} }}}
{@loaded
{data
<ul>
{list[]
<li>{text}</li>
}
</ul>
}
}
}}
</div>
}
还是大概能看出来吧? 大括号开始, 紧接一个字母的, 是闭包, 在里面可以直接书写文本内容. #号开头的则是组件(当然, 你可以定义自己的组件), 里面的@开头的是属性, 也可以理解成参数. 包括if都是以组件的形式存在的, 所以这种一般性让Sonne具有更强的扩展性. 好吧其实, 还有个原因是我实现起来会相对容易, 不用处理更多的特殊化的语法… 😛
再以#async组件为例, 可以看到url属性对应的字符串中存在另一个组件, 所以实际上, 组件是有 “返回值” 的, 可以是字符串, 也可以是文档片段. 因为是数据驱动, 当数据发生变动的时候, #async组件所管理的文档片段也就随之变化了, 并且因为是组件, 也可以很容易地实现定时更新数据.
当时一直期望这东西能改变Web开发的某个分支, 其实现在也有这个想法, 但也不知道最后能不能做出来… 记得后来看到过某个库, 也有类似的功能, 但印象里并没有Sonne强大,,, 具体哪里没有… 忘记了…