go 导出 html 报告(使用 hero 预编译 html 模板引擎)
前言
项目需求,需要将服务器的数据进行导出,方便携带展示,做了一次 html
报告的导出,考虑如何实现。
- 使用
vue
等前端框架,将数据导出成一个个的json
文件,然后通过读取js
来动态渲染html
视图 - 直接将数据写入
html
页面,多导出一些html
,通过iframe
来进行页面的加载
这里使用的是第二种方式。
本篇主要介绍一下 go
的一个开源库 hero 预编译模板引擎,用于快速的渲染 html
。
常见的模板引擎一般有两种实现方式,一种是直接解析 HTML 语法树,然后根据一定的规则动态的拼接,另外一种是把模板预先生成代码,渲染模板时调用相关的函数即可。
go
官方内置的 template
包是第一种实现方式,本篇的主角用的是第二种。
hero 简介
可以直接去 github 上看,这里做一个简短的介绍。
安装
go get github.com/shiyanhui/hero
go get github.com/shiyanhui/hero/hero// Hero需要goimports处理生成的go代码,所以需要安装goimports.
go get golang.org/x/tools/cmd/goimports
使用
hero [options]options:- source: 模板目录,默认为当前目录- dest: 生成的go代码的目录,如果没有设置的话,和source一样- pkgname: 生成的go代码包的名称,默认为template- extensions: source文件的后缀, 如果有多个则用英文逗号隔开, 默认为.html- watch: 是否监控模板文件改动并自动编译example:hero -source="./"hero -source="$GOPATH/src/app/template" -watch
基本语法
Hero
总共有九种语句,他们分别是:
函数定义语句
<%: func define %>
- 该语句定义了该模板所对应的函数,如果一个模板中没有函数定义语句,那么最终结果不会生成对应的函数。
- 该函数最后一个参数必须为
*bytes.Buffer
或者io.Writer
, hero会自动识别该参数的名字,并把把结果写到该参数里。 - 例:
<%: func UserList(userList []string, buffer *bytes.Buffer) %>
<%: func UserList(userList []string, w io.Writer) %>
<%: func UserList(userList []string, w io.Writer) (int, error) %>
模板继承语句
<%~ "parent template" %>
- 该语句声明要继承的模板。
- 例:
<%~ "index.html" >
模板include语句
<%+ "sub template" %>
- 该语句把要include的模板加载进该模板,工作原理和
C++
中的#include
有点类似。 - 例:
<%+ "user.html" >
- 该语句把要include的模板加载进该模板,工作原理和
包导入语句
<%! go code %>
该语句用来声明所有在函数外的代码,包括依赖包导入、全局变量、const等。
该语句不会被子模板所继承
例:
<%!import ("fmt""strings")var a intconst b = "hello, world"func Add(a, b int) int {return a + b}type S struct {Name string}func (s S) String() string {return s.Name} %>
块语句
<%@ blockName { %> <% } %>
块语句是用来在子模板中重写父模中的同名块,进而实现模板的继承。
例:
<!DOCTYPE html> <html><head><meta charset="utf-8"></head><body><%@ body { %><% } %></body> </html>
Go代码语句
<% go code %>
该语句定义了函数内部的代码部分。
例:
<% for _, user := range userList { %><% if user != "Alice" { %><%= user %><% } %> <% } %><%a, b := 1, 2c := Add(a, b) %>
原生值语句
<%==[t] variable %>
该语句把变量转换为string。
t
是变量的类型,hero会自动根据t
来选择转换函数。t
的待选值有:b
: booli
: int, int8, int16, int32, int64u
: byte, uint, uint8, uint16, uint32, uint64f
: float32, float64s
: stringbs
: []bytev
: interface
注意:
- 如果
t
没有设置,那么t
默认为s
. - 最好不要使用
v
,因为其对应的转换函数为fmt.Sprintf("%v", variable)
,该函数很慢。
例:
<%== "hello" %> <%==i 34 %> <%==u Add(a, b) %> <%==s user.Name %>
转义值语句
<%= statement %>
该语句把变量转换为string后,又通过
html.EscapesString
记性转义。t
跟上面原生值语句中的t
一样。例:
<%= a %> <%= a + b %> <%= Add(a, b) %> <%= user.Name %>
注释语句
<%# note %>
- 该语句注释相关模板,注释不会被生成到go代码里边去。
- 例:
<# 这是一个注释 >
.
原理
最终生成的代码,就是通过字符串拼接,写入 io.Writer
。下面是一个例子,生成后的代码如下:
func WriteTreeNodeHtml(param *RenderTemplateParam, w io.Writer) {_buffer := hero.GetBuffer()defer hero.PutBuffer(_buffer)_buffer.WriteString(`<html><head><meta charset="utf-8" /><link rel="stylesheet" href="css/build.css" /><link rel="stylesheet" href="css/jquery.treeview.css" /><link rel="stylesheet" href="css/screen.css" /><script src="js/jquery.min.js"></script><script src="js/jquery.cookie.js"></script><script src="js/jquery.treeview.js" type="text/javascript"></script><script type="text/javascript">$(function() {$("#tree").treeview({collapsed: true,animated: "fast",control: "#sidetreecontrol",prerendered: true,persist: "location"});})</script></head><body style="margin: 10px;"><div><h3>`)hero.EscapeHTML(GetAppName(), _buffer)_buffer.WriteString(`报告</h3><div id=jstree style="font-size:14px"><ul class="treeview" id="tree" style="margin-top:6px;"><li><a class="jstree-anchor" href="page1.html#case" target="pageframe"><i style="margin-left: 4px;margin-right: 4px;" class="icon-file iconfont"></i>案件</a></li><li><a class="jstree-anchor" href="page1.html#evidences" target="pageframe"><i style="margin-left: 4px;margin-right: 4px;" class="icon-evidence iconfont"></i>检材信息</a></li><li><a class="jstree-anchor" href="page1.html#brief" target="pageframe"><i style="margin-left: 4px;margin-right: 4px;" class="icon-evidence iconfont"></i>数据统计文字概括</a></li><li><a class="jstree-anchor" href="page1.html#summary" target="pageframe"><i style="margin-left: 4px;margin-right: 4px;" class="icon-summary iconfont"></i>数据统计清单</a></li>`)treeNodes, ok := param.Data.([]*ReportTreeNode)if !ok {return}for _, node := range treeNodes {GenerateTreeNode(node, _buffer)}_buffer.WriteString(`</ul></div></div></body>
</html>`)w.Write(_buffer.Bytes())}
总结
使用 go
生成 html
,原理很简单,通过字符串拼接,将数据都写入对应的地方即可。麻烦的点就在于 html
页面的布局和数据的插入对应。
参考
https://github.com/shiyanhui/hero
go 导出 html 报告(使用 hero 预编译 html 模板引擎)相关推荐
- Jquery 模板插件 jquery.tmpl.js 的使用方法(2):嵌套each循环,temp调用(使用预编译的模板缓存)...
直接上代码吧 一:主窗口 /*#region SendChooseTargetTemplate 发送候选人主窗口模板*/ var SendChooseTargetTemplate = ''; Send ...
- C#中的预编译指令介绍
原文:C#中的预编译指令介绍 1.#define和#undef 用法: #define DEBUG #undef DEBUG #define告诉编译器,我定义了一个DEBUG的一个符号,他类似一个变量 ...
- 课程 预编译框架,开发高性能应用 - 微软技术暨生态大会 2018
微软技术暨生态大会(Tech Summit),2018 年在上海世博中心召开.这是最后一次的 Tech Summit 了:明年开始,中国大陆地区就要和其他国家和地区一样,进行全球 Ignite Tou ...
- RT-Thread中如何预编译一个.c文件
本文介绍在RT-Thread系统,使用scons,如何预编译一个.c文件 首先新建一个测试文件test.c #include "rtthread.h"void test(void) ...
- 使用预编译库PREBUILT LIBRARY官方说明
使用预编译库 NDK 支持使用预编译库(同时支持静态库和共享库).此功能有以下两个主要用例: 向第三方 NDK 开发者分发您自己的库(而不分发您的源代码). 使用您自己的库的预编译版本来提升编译速度. ...
- android应用资源预编译,编译和打包全解析
我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的. ...
- 从预编译的角度理解Swift与Objective-C及混编机制
本文从预编译的基础知识入手,由浅至深的介绍了 Objective-C 和 Swift 的工作机制,并通过这些机制来解释混编项目中使用到的技术和各种参数的作用,由此来指导开发者如何进行混编. 写在前面 ...
- 浅谈GCC预编译头技术
浅谈GCC预编译头技术 文/jorge --谨以此文,悼念我等待MinGW编译时逝去的那些时间. 其 实刚开始编程的时候,我是丝毫不重视编译速度之类的问题的,原因很简单,因为那时我用BASICA.后来 ...
- PHP 预编译加速: eAccelerator的安装和性能比较
eAccelerator已经是很常用的PHP平台预编译加速的手段了.今天在自己机器上尝试安装了一下,备忘如下: 获得源代码: http://bart.eaccelerator.net/source/ ...
- 5单个编译总会编译全部_5分钟读懂JavaScript预编译
大家都知道JavaScript是解释型语言,既然是解释型语言,就是编译一行,执行一行,那又何来预编译一说呢?脚本执行js引擎都做了什么呢?今天我们就来看看吧. 1-JavaScript运行三部曲 语法 ...
最新文章
- linux selinux 安全子系统简介
- PHP上传图片到数据库和存储到本地文件夹的方法
- Android布局管理器-使用FrameLayout帧布局管理器显示层叠的正方形以及前景照片
- Ajax(jquery)
- 利用shell脚本监控网站状态
- MySQL多种安装方式选择
- 在windows 2008 R2上安装sharepoint 2013时遇到提示必须安装 .netframeword4.5的处理办法...
- 重新创建Activity
- pat乙级相当于什么水平_雅思6分是什么水平?相当于英语几级
- *nix下部署第三方动态库文件
- @Autowired 与@Resource的区别
- 假如我来发明编程语言
- CentOS 7.4创建普通用户赋予登录权限
- 邹城的关于机器人教育_【喜报】我校机器人队问鼎全国大学生机器人大赛冠军!...
- Android 开发环境搭建之——ADT-Bundle for Windows
- python正交表运用
- Mac m1 安装jdk
- Bitvise密钥登录Linux服务器
- char在mysql中的意思_mysql中char表示什么意思
- 阿里巴巴 Excel工具easyExcel