由于各种原因,被逼使用前台模板。看了一下其他JS模板库的实现,发现其原理并不难,遂决定重造轮子。
做一个前台模板,有如下几个问题需要考量:
下面是我一些不成熟的见解:
我把我的模板引擎称之为ejs(embedded javascript snippet,嵌入式javascript代码片断)。任何javascript模板只最终目的就是生成一个可以传入后台参数的函数。
javascript模板 by 司徒正美 javascript模板 by 司徒正美
模板系统:
//司徒正美 javascript template - http://www.hack95.com/rubylouvre/ - MIT Licensed(function () {if(!String.prototype.trim){String.prototype.trim = function(str) {return this.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');}}var dom = {quote: function (str) {str = str.replace(/[\x00-\x1f\\]/g, function (chr) {var special = metaObject[chr];return special ? special : '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4)});return '"' + str.replace(/"/g, '\\"') + '"';}},metaObject = {'\b': '\\b','\t': '\\t','\n': '\\n','\f': '\\f','\r': '\\r','\\': '\\\\'},parser = document.createElement("div"),startOfHTML = "\t__views.push(",endOfHTML = ");\n",outerScan = function(str,buff,left,right){var index = str.indexOf(left);if(index !== -1){buff.push(startOfHTML, dom.quote(str.slice(0,index)), endOfHTML);innerScan(str.slice(index+2),buff,left,right);}else{buff.push(startOfHTML, dom.quote(str), endOfHTML);}},innerScan = function(str,buff,left,right){var index = str.indexOf(right);if(index !== -1){var text = str.slice(0,index);switch (text.charAt(0)) {case "#"://处理注释break;case "="://处理后台返回的变量(输出到页面的)buff.push(startOfHTML, text.slice(1), endOfHTML)break;default:buff.push(text, "\n")}outerScan( str.slice(index+2),buff,left,right);}else{throw "找不到右界定符 " + str}}//onsite,可选,Boolean,是否就地替换掉模板容器,默认true,如果为false,则返回一个文档碎片,交由用户自己插入到需要的地方dom.ejs = function (obj) {var onsite = obj.onsite === void 0 ,left = obj.left || "<%",right = obj.right || "%>",selector = www.hack95.comor,buff = ["var __views = [];\n"],fragment = document.createDocumentFragment(),el = document.getElementById(selector),ejs = dom.ejs;if (!el) throw "找不到目标元素";if(!ejs[selector]){outerScan(el.text.trim(),buff,left,right);ejs[selector] = new Function("json", "with(json){"+buff.join("") + '};return __views.join("");')}parser.innerHTML = ejs[selector](obj.json || {});while (parser.firstChild) {fragment.appendChild(parser.firstChild)}return onsite ? el.parentNode.replaceChild(fragment, el) : fragment;};window.dom = dom;})();
运行代码
PS:发现javascript模板没有想象中的糟糕,尤其是大流量的页面在无法使用UI库的情况下,这是个不错的选择,例子如qq zone与ニコニコ動画。