layui/examples/laytpl.html
贤心 169f6ff9b8
feat: 重构 laytpl,增强对更多复杂模板结构的解析能力 (#2577)
* feat: 重构 laytpl,增强对更多复杂模板结构的解析能力

* Squashed commit of the following:

commit 6884f80378
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 14:45:58 2025 +0800

    release: v2.10.1

commit 8d643ad6dc
Merge: 5521e48c 213fe5a2
Author: corededitor <107152508+corededitor@users.noreply.github.com>
Date:   Wed Mar 19 14:24:50 2025 +0800

    feat: Merge pull request #2566 from layui/feat/component

    feat: 优化 component, tabs 若干功能

commit 213fe5a209
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 14:15:39 2025 +0800

    docs: 添加 component 文档中实验性选项标记

commit 5521e48c05
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 14:10:46 2025 +0800

    fix: 修复 `body` 初始 `line-height` 无效的问题 (#2569)

commit 8c7cf0f606
Author: 青崖 <33601030+bxjt123@users.noreply.github.com>
Date:   Wed Mar 19 14:10:08 2025 +0800

    优化 checkbox 标签风格选中且禁用时的显示 (#2563)

commit 23b21254d4
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 14:04:44 2025 +0800

    docs: Squashed commit of the following:

    commit 95a0503f41
    Merge: e6eb86ba 87ba4c43
    Author: 贤心 <3277200+sentsim@users.noreply.github.com>
    Date:   Wed Mar 19 14:03:13 2025 +0800

        Merge branch 'main' into 2.x

    commit e6eb86bacb
    Author: morning-star <26325820+Sight-wcg@users.noreply.github.com>
    Date:   Wed Mar 19 14:02:05 2025 +0800

        docs(slider): 修正错别字 (#2578)

    commit 46f7a9783e
    Merge: df1fc4f4 c204590a
    Author: 贤心 <3277200+sentsim@users.noreply.github.com>
    Date:   Fri Mar 14 19:07:50 2025 +0800

        Merge branch 'main' into 2.x

    commit df1fc4f419
    Author: itletu <itletu@163.com>
    Date:   Mon Mar 10 13:54:06 2025 +0800

        docs: 更正 class 公共类文档错误 (#2544)

        | layui-border-box | 设置元素及其所有子元素均为 `box-sizing: border-box` 模型的容器 |

commit 87ba4c4394
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 13:41:33 2025 +0800

    docs(version): 优化 2.9.x 锚点

commit a0f533f0fd
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 13:37:29 2025 +0800

    docs: 修复 tabs 文档示例异常问题

commit 0f0584e2ed
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 13:35:00 2025 +0800

    docs: 修复 tabs 文档中自定义事件示例重新点击 Preview 失效的问题

commit 172957d243
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Wed Mar 19 13:29:09 2025 +0800

    docs: 优化文档中的用词细节 (#2571)

commit 094be4ddcc
Author: letianpailove <113023596+letianpailove@users.noreply.github.com>
Date:   Wed Mar 19 13:28:46 2025 +0800

    fix: 更正 class 公共类文档错误 (#2562)

commit 53ded26cb9
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Sun Mar 16 00:15:25 2025 +0800

    fix: 优化 tabs 重载时未按照传入的 closable 正确渲染可关闭状态

commit bd892bf87e
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Sun Mar 16 00:15:17 2025 +0800

    feat(component): 新增 cache 原型方法,用于元素缓存操作

commit 6ccc5a453d
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Sun Mar 16 00:14:18 2025 +0800

    fix(component): 优化元素 lay-options 属性上的配置在重载时的优先级

commit 79b0a56f50
Author: 贤心 <3277200+sentsim@users.noreply.github.com>
Date:   Sun Mar 16 00:13:55 2025 +0800

    fix(component): 修复 reload 时传入的选项未正确合并的问题

* refactor(laytpl): 优化代码细节

* docs: 重写 laytpl 模块文档
2025-03-27 23:55:04 +08:00

378 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>模板引擎 - Layui</title>
<link rel="stylesheet" href="../src/css/layui.css">
<style>
.laytpl-demo{border: 1px solid #eee;}
.laytpl-demo:first-child{border-right: none;}
.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;}
.laytpl-demo>div:first-child{height: 32px; line-height: 32px; padding: 6px 11px; border-bottom: 1px solid #eee; background-color: #F8F9FA;}
.laytpl-demo .layui-tabs{top: -1px;}
#ID-tpl-view-body {
height: calc(100vh - 430px); overflow: auto; clear: both;
}
#ID-tpl-view-body > div {
display: none;
}
.laytpl-demo pre {
padding: 16px; background-color: #20222A; color: #F8F9FA; font-family: 'Courier New',Consolas, monospace;
}
</style>
</head>
<body>
<div class="layui-padding-3">
<div class="layui-row">
<div class="layui-col-xs6 laytpl-demo">
<div>
<a href="javascript:;" id="ID-tpl-src-title">
<cite><strong>模板</strong></cite>
<i class="layui-icon layui-icon-down layui-font-12"></i>
</a>
</div>
<textarea id="ID-tpl-src"></textarea>
</div>
<div class="layui-col-xs6 laytpl-demo">
<div class="layui-row">
<div><strong>数据</strong></div>
</div>
<textarea id="ID-tpl-data">
{
"title": "标题",
"desc": "<a href=\"\" style=\"color:blue;\">一段描述</a>",
"items": [
{
"title": "list 1",
"child": [{
"title": "list 1-1",
"child": [{
"title": "list 1-1-1"
}]
}]
},
{
"title": "list 2",
"child": [{
"title": "list 2-1"
}]
},
{"title": "list 3"}
]
}</textarea>
</div>
<div class="layui-col-xs12 laytpl-demo" style="border-top: none;">
<div class="layui-row">
<div class="layui-col-xs4 layui-tabs" id="ID-tpl-view-header">
<ul class="layui-tabs-header">
<li><strong>渲染结果</strong></li>
<li><strong>源码</strong></li>
</ul>
</div>
<div class="layui-col-xs4" style="text-align: center">
<button class="layui-btn layui-btn-sm layui-btn-border" lay-on="test">性能测试</button>
</div>
<div class="layui-col-xs4" style="text-align: right">
<span class="layui-badge" id="ID-tpl-view-time"></span>
</div>
</div>
<div id="ID-tpl-view-body">
<div class="layui-show layui-padding-3 layui-text" id="ID-tpl-view"></div>
<div><pre id="ID-tpl-view-code"></pre></div>
</div>
</div>
</div>
<script type="text/html" id="ID-tpl-template-modern">
<h2>
{{= d.title }} - {{= d.title ? '#' : '' }}
{{ if(true){ }}AAAA{{='A'}}{{ } }}
</h2>
{{- include('ID-tpl-template-common', {title: '头部'}) }}
<hr>
<p>转义输出{{= d.desc }}</p>
<p>原文输出{{- d.desc }}</p>
{{# 这是一段注释仅在模板中显示不在视图中输出 }}
{{!
这是一段不进行模板解析的区域可显示原始标签
{{ let a = 0; }}{{= escape }}{{- source }}{{# comments }}&#123;&#123;! ignore !&#125;&#125;
!}}
{{# 空主体测试 }}
{{}} {{ }} {{ }} {{= }} {{=}} {{= }}
<div>
{{- !0 ? '<br>循环输出:' : '' }}
<hr>
<ul>
{{
var str = "一级列表 a \\ b c";
d.items.forEach(function(value, index) {
}}
<li class="{{= index > 0 ? 'list' : '' }}">
<strong>{{= value.title }}</strong>
{{ if(value.content){ }}
<span>{{= value.content }}</span>
{{ } }}
<span>{{= value.time || '' }}</span>
{{= str }}
{{- include('ID-tpl-template-list', { items: value.child }) }}
</li>
{{ }); }}
{{ if(d.items.length === 0){ }}
无数据
{{ } }}
</ul>
<hr>
</div>
<div>
{{= d.content || '' }}
\反斜杠 | '单引号' "双引号" ""''"" | "左双右单' | '左单右双"
</div>
<p>渲染时间{{= layui.util.toDateString(new Date()) }}</p>
</script>
<script type="text/html" id="ID-tpl-template-common">
公共模板 - {{= d.title }}
</script>
<script type="text/html" id="ID-tpl-template-list">
{{ if(d.items && d.items.length > 0){ }}
<ul>
{{ layui.each(d.items, function(index, item){ }}
<li>
<strong>{{= item.title }}</strong>
{{- include('ID-tpl-template-list', {items: item.child}) }}
</li>
{{ }); }}
</ul>
{{ } }}
</script>
<script type="text/html" id="ID-tpl-template-test">
{{ for (var i = 0; i < d.items.length; i++) { }}
{{= d.items[i].index }} Name: {{- d.items[i].name }} Number: {{= d.items[i].number }}
{{ } }}
</script>
<!-- 旧版本模板 -->
<script type="text/html" id="ID-tpl-template-legacy">
<h2>
{{= d.title }} - {{= d.title ? '#' : '' }}
{{# if(true){ }}AAAA{{='A'}}{{# } }}
</h2>
<hr>
<p>转义输出{{ d.desc }}</p>
<p>转义输出{{= d.desc }}</p>
<p>原文输出{{- d.desc }}</p>
{{}} {{ }} {{ }} {{= }} {{=}} {{= }}
<div>
<ul>
{{# var str = "a b c"; }}
{{# layui.each(d.items, function(index, item) { }}
<li class="{{= index > 0 ? 'list' : '' }}">
<strong>{{= item.title }}</strong>
{{# if(item.content){ }}
<span>{{= item.content }}</span>
{{# } }}
<span>{{= item.time || '' }}</span>
{{ str }}
</li>
{{# }); }}
{{# if (d.items.length === 0) { }}
无数据
{{# } }}
</ul>
<hr>
</div>
<div>
{{= d.content || '' }}
\反斜杠 | '单引号' "双引号" ""''"" | "左双右单' | '左单右双"
</div>
<p>渲染时间{{ layui.util.toDateString(new Date()) }}</p>
</script>
</div>
<script src="../src/layui.js"></script>
<script>
layui.use(['laytpl', 'util', 'tabs', 'dropdown'], function() {
var laytpl = layui.laytpl;
var util = layui.util;
var tabs = layui.tabs;
var dropdown = layui.dropdown;
var $ = layui.$;
// 默认设置
laytpl.config({
tagStyle: 'modern' // 初始采用新版标签风格
})
// 获取模板和数据
var getData = function(type) {
return {
template: $('#ID-tpl-src').val(), // 获取模板
data: function(){ // 获取数据
try {
return JSON.parse($('#ID-tpl-data').val());
} catch(e) {
$('#ID-tpl-view').html(e);
}
}()
};
};
// 视图渲染
var renderView = function(html, startTime) {
timer(startTime);
$('#ID-tpl-view').html(html);
$('#ID-tpl-view-code').html(util.escape(html));
};
// 生成模板
var createTemplate = function(opts) {
opts = $.extend({
tagStyle: 'modern'
}, opts);
// 初始化模板
var elem = $('#ID-tpl-template-'+ opts.tagStyle);
$('#ID-tpl-src').val(elem.html());
return opts;
};
var tplConfig = createTemplate();
var data = getData();
// 耗时计算
var timer = function(startTime, title) {
var endTime = new Date();
$('#ID-tpl-view-time').html((title || '模板解析耗时:')+ (endTime - startTime) + 'ms');
};
var startTime = new Date();
// 创建一个模板实例
var templateInst = laytpl(data.template, {
condense: false, // 不处理连续空白符,即保留模板原始结构
tagStyle: tplConfig.tagStyle
});
// 初始渲染
templateInst.render(data.data, function(html) {
renderView(html, startTime);
});
// 编辑
$('.laytpl-demo textarea').on('input', function() {
var data = getData();
var startTime = new Date();
// 若模板有变化,则重新编译模板
if (this.id === 'ID-tpl-src') {
templateInst.compile(data.template);
}
// 若模板没变,数据有变化,则从模板缓存中直接渲染数据(效率大增)
templateInst.render(data.data, function(html) {
renderView(html, startTime);
});
});
// 事件
util.on({
// 性能测试
test: function() {
var dataLen = 1000 // 数据量
var renderTimes = 1000; // 渲染次数
// 初始化数据
var data = {
title: '性能测试',
items: function(items) {
for (var i = 0; i < dataLen; i++) {
items.push({
index: i,
name: '<strong style="color: red;">张三</strong>',
number: 100+i
});
}
return items;
}([])
};
// 模板
var startTime = new Date();
for (var j = 0; j < renderTimes; j++) {
var template = document.getElementById('ID-tpl-template-test').innerHTML;
var html = laytpl(template).render(data);
}
renderView(html, startTime);
}
});
// 局部自定义标签符
laytpl(`
<% var job = ["前端工程师"]; %>
<%= d.name %>是一名<%= job[d.index] %>。
`, {
open: '<%',
close: '%>'
}).render({
name: '张三',
index: 0
}, function(str) {
console.log(str); // 张三是一名前端工程师。
});
// 视图结果 tabs
tabs.render({
elem: '#ID-tpl-view-header',
body: ['#ID-tpl-view-body', '>div']
});
// 切换模板
dropdown.render({
elem: '#ID-tpl-src-title',
data: [{
title: '新版本模板',
tagStyle: 'modern'
}, {
title: '旧版本模板',
tagStyle: 'legacy'
}],
click: function(obj){
createTemplate({
tagStyle: obj.tagStyle
});
this.elem.children('cite').html(obj.title);
// 同步设置标签风格
templateInst.config.tagStyle = obj.tagStyle;
var data = getData();
var startTime = new Date();
// 重新渲染
templateInst.compile(data.template).render(data.data, function(html) {
renderView(html, startTime);
});
}
})
});
</script>
</body>
</html>