zoukankan      html  css  js  c++  java
  • javascript 模板系统 ejs v1

    由于各种原因,被逼使用前台模板。看了一下其他JS模板库的实现,发现其原理并不难,遂决定重造轮子。

    做一个前台模板,有如下几个问题需要考量:

    • 模板是放置于哪里?是内嵌于HTML页面还是像JS文件那样独立出来?如果是内嵌可以减少请求数但无法让模板重用于另一个HTML页面,反之亦然。
    • 如果是内嵌于HTML页面,如何存放它?目前有两种方式,script标签与textarea。
    • 模板界定符的风格,是ASP的<%与%>,还是Django的{{与}},还是其他方式。

    下面是我一些不成熟的见解:

    • 应该存在两种模板,普通模板(内嵌于HTML)与局部模板(存放于独立的文件中)。普通模板是为某个页面订制的,局部模板可以是订制的,但多是为了实现多页面的重用,它可以与普通模板一起组成完整的模板。用rails的术语来说,这是一个partial。
    • 普通模板的容器为一个丧失解析脚本能力的script标签,因为我们可以不需要在script标签里面内嵌script标签。但是与textara作为容器,就很可能碰到模板存在textarea的情况,这时就存在一个错位套嵌的问题。
    • 模板风格,让它可以定制就行了。默认是ASP风格,好让它在一些主流的IDE中自动排版。

    我把我的模板引擎称之为ejs(embedded javascript snippet,嵌入式javascript代码片断)。任何javascript模板只最终目的就是生成一个可以传入后台参数的函数。

    <!doctype html>
    <html>
        <head>
            <meta charset="utf-8"/>
            <meta content="IE=8" http-equiv="X-UA-Compatible"/>
            <meta name="keywords" content="javascript模板 by 司徒正美" />
            <meta name="description" content="javascript模板 by 司徒正美" />
            <title>javascript模板 by 司徒正美</title>
        </head>
        <body>
            <h1>javascript模板 by 司徒正美</h1>
            <script id="tmpl" type="text/html">
                    <h2><%=  name %></h2>
                    <%# 这是注释!!!!!!!!! %>
                    <ul>
                    <% for(var i=0; i< supplies.length; i++){ %>
                        <li><%=  supplies[i] %></li>
                        <% } %>
                    </ul>
                    <% var color = "color:red;" %>
                    <p style="text-indent:2em;<%= color %>"><%= address %></p>
            </script>
             <script id="tmpl" type="template" ></script  >
            <script>  
    
                window.onload = function(){
                    dom.ejs({
                        selector:"tmpl",
                        json: {
                            name:"司徒正美",
                            supplies:["第一个LI元素","第二个LI元素","第三个LI元素","第四个LI元素"],
                            address:"异次元"}
                    });
                }
            </script>
        </body>
    </html>
    

    模板系统:

     //司徒正美 javascript template - http://www.cnblogs.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 = obj.selector,
                        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ニコニコ動画

  • 相关阅读:
    vue-cli 3.0 路由懒加载
    vue 路由拦截、axios请求拦截
    vue-cli 3.0 图片路径问题(何时使用 public 文件夹)
    vue 监听页面宽度变化 和 键盘事件
    WGS84、GCJ-02(火星坐标)、百度坐标,Web墨卡托坐标
    Java学习之道:Java项目打包发布
    ora-14550问题解决
    费氏搜寻法之算法分析与实现
    [置顶] woff格式字体怎么打开和编辑?
    C++小知识之Vector排序
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1796383.html
Copyright © 2011-2022 走看看