模板引擎

laytpl 是 Layui 的一款轻量 JavaScript 模板引擎,在字符解析上有着比较出色的表现。

在线测试

在以下模板数据中进行编辑,下方视图将呈现对应结果。

  • Preview
  • 模板
    数据
    视图
    模板解析耗时:1ms

    Layui 常用模块

    • 弹层 layer: layer.domain.com
    • 表单 form:
    • 表格 table:
    • 日期 laydate:
    • 上传 upload:

    01.
    <!DOCTYPE html>
    02.
    <html>
    03.
    <head>
    04.
    <meta charset="utf-8">
    05.
    <meta name="viewport" content="width=device-width, initial-scale=1">
    06.
    <title>Demo</title>
    07.
    <!-- 请勿在项目正式环境中引用该 layui.css 地址 -->
    08.
    <link href="/laydev/staticdev/layui/v/2.9.18/css/layui.css" rel="stylesheet">
    09.
    </head>
    10.
    <body>
    11.
    <style>
    12.
    .laytpl-demo{border: 1px solid #eee;}
    13.
    .laytpl-demo:first-child{border-right: none;}
    14.
    .laytpl-demo>textarea{position: relative; display: block; width:100%; height: 300px; padding: 11px; border: 0; box-sizing: border-box; resize: none; background-color: #fff; font-family: Courier New; font-size: 13px;}
    15.
    .laytpl-demo>div:first-child{height: 32px; line-height: 32px; padding: 6px 11px; border-bottom: 1px solid #eee; background-color: #F8F9FA;}
    16.
    </style>
    17.
    <div class="layui-row">
    18.
    <div class="layui-col-xs6 laytpl-demo">
    19.
    <div>模板</div>
    20.
    <textarea id="ID-tpl-src">
    21.
    <h3>{{= d.title }}</h3>
    22.
    <ul>
    23.
    {{# layui.each(d.list, function(index, item){ }}
    24.
    <li>
    25.
    <span>{{= item.modname }}</span>
    26.
    <span>{{= item.alias }}:</span>
    27.
    <span>{{= item.site || '' }}</span>
    28.
    </li>
    29.
    {{# }); }}
    30.
    <p>{{# if(d.list.length === 0){ }}
    31.
    无数据
    32.
    {{# } }}</p>
    33.
    </ul>
    34.
    </textarea>
    35.
    </div>
    36.
    <div class="layui-col-xs6 laytpl-demo">
    37.
    <div>数据</div>
    38.
    <textarea id="ID-tpl-data">
    39.
    {
    40.
    "title": "Layui 常用模块",
    41.
    "list": [
    42.
    {
    43.
    "modname": "弹层",
    44.
    "alias": "layer",
    45.
    "site": "layer.domain.com"
    46.
    },
    47.
    {
    48.
    "modname": "表单",
    49.
    "alias": "form"
    50.
    },
    51.
    {
    52.
    "modname": "表格",
    53.
    "alias": "table"
    54.
    },
    55.
    {
    56.
    "modname": "日期",
    57.
    "alias": "laydate"
    58.
    },
    59.
    {
    60.
    "modname": "上传",
    61.
    "alias": "upload"
    62.
    }
    63.
    ]
    64.
    }
    65.
    </textarea>
    66.
    </div>
    67.
    <div class="layui-col-xs12 laytpl-demo" style="border-top: none;">
    68.
    <div class="layui-row">
    69.
    <div class="layui-col-xs6">视图</div>
    70.
    <div class="layui-col-xs6" style="text-align: right">
    71.
    <span id="ID-tpl-viewtime"></span>
    72.
    </div>
    73.
    </div>
    74.
    <div class="layui-padding-sm" id="ID-tpl-view" style="max-height: 300px; padding: 16px; overflow: auto;">…</div>
    75.
    </div>
    76.
    </div>
    77.
    <div class="layui-clear"></div>
    78.
    79.
    <!-- 请勿在项目正式环境中引用该 layui.js 地址 -->
    80.
    <script src="/laydev/staticdev/layui/v/2.9.18/layui.js"></script>
    81.
    <script>
    82.
    layui.use(function(){
    83.
    var laytpl = layui.laytpl;
    84.
    var util = layui.util;
    85.
    var $ = layui.$;
    86.
    // 获取模板和数据
    87.
    var get = function(type){
    88.
    return {
    89.
    template: $('#ID-tpl-src').val(), // 获取模板
    90.
    data: function(){ // 获取数据
    91.
    try {
    92.
    return JSON.parse($('#ID-tpl-data').val());
    93.
    } catch(e){
    94.
    $('#ID-tpl-view').html(e);
    95.
    }
    96.
    }()
    97.
    };
    98.
    };
    99.
    100.
    var data = get();
    101.
    102.
    // 耗时计算
    103.
    var startTime = new Date().getTime(), timer = function(startTime, title){
    104.
    var endTime = new Date().getTime();
    105.
    $('#ID-tpl-viewtime').html((title || '模板解析耗时:')+ (endTime - startTime) + 'ms');
    106.
    };
    107.
    // 渲染模板
    108.
    var thisTpl = laytpl(data.template);
    109.
    // 执行渲染
    110.
    thisTpl.render(data.data, function(view){
    111.
    timer(startTime);
    112.
    $('#ID-tpl-view').html(view);
    113.
    });
    114.
    115.
    // 编辑
    116.
    $('.laytpl-demo textarea').on('input propertychange', function(){
    117.
    var data = get();
    118.
    if(!data.data) return;
    119.
    120.
    // 计算模板渲染耗时
    121.
    var startTime = new Date().getTime();
    122.
    123.
    // 若模板有变化,则重新解析模板;若模板没变,数据有变化,则从模板缓存中直接渲染(效率大增)
    124.
    if(this.id === 'ID-tpl-src'){
    125.
    thisTpl.parse(data.template, data.data); // 解析模板
    126.
    }
    127.
    128.
    // 执行渲染
    129.
    thisTpl.render(data.data, function(view){
    130.
    timer(startTime);
    131.
    $('#ID-tpl-view').html(view);
    132.
    });
    133.
    });
    134.
    });
    135.
    </script>
    136.
    <p>
    137.
    138.
    </body>
    139.
    </html>

    API

    API 描述
    var laytpl = layui.laytpl 获得 laytpl 模块。
    laytpl(str, options).render(data, callback) laytpl 组件渲染,核心方法。
    laytpl.config(options) 配置 laytpl 全局属性

    模板解析和渲染

    laytpl(str, options).render(data, callback);

    • 参数 str : 模板原始字符
    • 参数 options 2.8+ : 当前模板实例的属性配置项。可选项详见:#属性配置
    • 参数 data : 模板数据
    • 参数 callback : 模板渲染完毕的回调函数,并返回渲染后的字符

    01.
    layui.use('laytpl', function(){
    02.
    var laytpl = layui.laytpl;
    03.
    // 直接解析字符
    04.
    laytpl('{{= d.name }}是一名前端工程师').render({
    05.
    name: '张三'
    06.
    }, function(str){
    07.
    console.log(str); // 张三是一名前端工程师
    08.
    });
    09.
    // 同步写法
    10.
    var str = laytpl('{{= d.name }}是一名前端工程师').render({
    11.
    name: '张三'
    12.
    });
    13.
    console.log(str); // 张三是一名前端工程师
    14.
    });

    若模板字符较大,可存放在页面某个标签中,如:

    01.
    <script id="TPL" type="text/html">
    02.
    <h3>{{= d.name }}</h3>
    03.
    <p>性别:{{= d.sex ? '男' : '女' }}</p>
    04.
    </script>
    05.
    <div id="view"></div>
    06.
    <!-- import layui -->
    07.
    <script>
    08.
    layui.use(function(){
    09.
    var laytpl = layui.laytpl;
    10.
    // 渲染
    11.
    var data = {
    12.
    name: '张三',
    13.
    sex: 1
    14.
    };
    15.
    var getTpl = document.getElementById('TPL').innerHTML; // 获取模板字符
    16.
    var elemView = document.getElementById('view'); // 视图对象
    17.
    // 渲染并输出结果
    18.
    laytpl(getTpl).render(data, function(str){
    19.
    elemView.innerHTML = str;
    20.
    });
    21.
    });
    22.
    </script>

    在实际使用时,若模板通用,而数据不同,为减少模板解析的开销,可将语句分开书写,如。

    01.
    var compile = laytpl(str); // 模板解析
    02.
    compile.render(data, callback); // 模板渲染

    标签语法

    标签 描述
    {{= }}

    转义输出。若字段存在 HTML,将进行转义。

    01.
    <h2>{{= d.title }}</h2>
    {{- }} 2.8+

    原始输出。若字段存在 HTML,将正常渲染。

    01.
    <div>{{- d.content }}</div>

    该语句一般在需要正常渲染 HTML 时用到,但若字段存在 script 等标签,为防止 xss 问题,可采用 {{= }} 进行转义输出。

    注意

    由于 2.6.11 版本对 laytpl 语句进行了重要调整,原 {{ }} 语法即等同 {{- }},升级版本时,请进行相应调整。可参考:https://gitee.com/layui/layui/issues/I5AXSP

    {{# }}

    JavaScript 语句。一般用于逻辑处理。

    01.
    <div>
    02.
    {{#
    03.
    var fn = function(){
    04.
    return '2017-08-18';
    05.
    };
    06.
    }}
    07.
    {{# if(true){ }}
    08.
    开始日期:{{= fn() }}
    09.
    {{# } else { }}
    10.
    已截止
    11.
    {{# } }}
    12.
    </div>
    {{! !}}

    对一段指定的模板区域进行过滤,即不解析该区域的模板。

    01.
    {{! 这里面的模板不会被解析 !}}

    注意

    开发者在使用模板语法时,需确保模板中的 JS 语句不来自于页面用户输入,即必须在页面开发者自身的可控范围内,否则请避免使用该模板引擎。

    属性配置

    laytpl.config(options);

    • 参数 options : 属性配置项。可选项详见下表
    属性 描述
    open 标签符前缀
    close 标签符后缀

    全局配置

    若模板默认的标签符与其他模板存在冲突,可通过该方法重新设置标签符,如:

    01.
    laytpl.config({
    02.
    open: '<%',
    03.
    close: '%>'
    04.
    });
    05.
    // 模板语法将默认采用上述定义的标签符书写
    06.
    laytpl(`
    07.
    <%# var job = ["前端工程师"]; %>
    08.
    <%= d.name %>是一名<%= job[d.type] %>。
    09.
    `).render({
    10.
    name: '张三',
    11.
    type: 0
    12.
    }, function(string){
    13.
    console.log(string); // 张三是一名前端工程师。
    14.
    });

    局部配置 2.8+

    若不想受到上述全局配置的影响,可在 laytpl(str, options) 方法的第二个参数中设置当前模板的局部属性,如:

    01.
    laytpl('<%= d.name %>是一名前端工程师', {
    02.
    open: '<%',
    03.
    close: '%>'
    04.
    }).render({name: '张三'}, function(string){
    05.
    console.log(string); // 张三是一名前端工程师。
    06.
    });

    贴士

    Layui table 等组件的动态模板功能,均采用 laytpl 驱动。 laytpl 亦可承载单页面应用开发中的视图模板。