前端进行Velocity开发与调试

229 阅读1分钟

最近在使用 Velocity 模板语法进行邮件的开发。Velocity 是一个基于 Java 的模板引擎,主要用于生成 HTML、邮件等文本输出。它提供了一种简单而强大的模板语言(VTL,Velocity Template Language),可以用来在 HTML 页面中引用 Java 代码定义的对象,实现界面与代码的分离。在这里介绍一下基本的使用。

基础语法:

  • 变量引用:使用 $ 符号,如 $user.name
  • 设置变量:使用 #set 指令,如 #set($name = "value")
  • 条件判断:使用 #if#else#elseif 指令
  • 循环遍历:使用 #foreach 指令
  • 注释:使用 ## 单行注释

调试

可以直接利用 velocity.js 这个项目在node中进行调试,在空文件下执行下面的命令初始化项目

$ npm init -y
$ npm install velocityjs

安装完成之后,编写test.js文件,用于测试

const Velocity = require('velocityjs');
const fs = require('fs');

// 读取模板文件
const template = fs.readFileSync('./example.vm', 'utf-8');

//准备mock数据
const context = {}

// 渲染模板
const result = Velocity.render(template, context);

// 输出结果
fs.writeFileSync('output.html', result);

example.vm文件中写入文件之后,终端中执行

$ node test.js

就可以在output.html文件中看到输出了

实战:表格单元格合并

我们以一个单元格合并为例,具体说明 Velocity 的使用。这个示例将展示如何合并具有相同年龄值的单元格。

进行项目初始化之后,首先在example.vm文件中创建一个简单的表格

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <table border="1">
        <tr>
            <th>姓名</th>
            <th>年龄</th>
        </tr>
        #foreach($item in $tableList)
        <tr>
            <td>$item.name</td>
            <td>$item.age</td>
        </tr>
        #end
    </table>
</body>
</html>

创建之后编写对应的test.js文件,同时给context赋值

const context = {
    tableList: [
        {
            name: '张三',
            age: 20,
        },
        {
            name: '李四',
            age: 25,
        },
        {
            name: '王五',
            age: 25,
        },
    ],
};

在终端中执行$ node test.js之后,就可以打开output.html文件看到输出了

接下来我们尝试将相同的年龄进行合并,通常来说,单元格合并可以封装成一个通用的方法,然后根据传入的列进行操作,但是Velocity语法本身功能不算很丰富,实现起来需要做很多的前期准备,对于我们处理的邮件这种小型的功能,实现起来得不偿失,所以考虑直接实现功能比较划算。

合并单元格的原理都是一致的,基本上都是遍历一遍数据,记录相同的行的数量,然后给rowspan赋上该数量,同时被合并掉的单元格不进行渲染即可。

首先使用#set定义好需要的变量

#set($currentAge = '') ## 用于记录当前遍历到哪一项
#set($ageCount = 0) ## 计数器,用于记录相同的行数

#set($outCounter = 0) ## 记录外侧foreach索引
#set($insideCounter = 0) ## 记录内侧foreach索引

然后进行双重循环,遍历拿到相同的行的数量即可

#foreach($item in $tableList)
	#set($outCounter = $outCounter + 1) ## 初始时就设置为第二行的数据,便于与第一行比较
	<tr>
		<td>$item.name</td>
			## 当前年龄项与上一个年龄项不同,或者是第一次比较时时,需要进行新的单元格处理。
			#if($currentAge != $item.age || $outCounter == 1) 
				#set($currentAge = $item.age) ## 更新当前年龄值
				#set($ageCount = 1) ## 重置计数器
				#set($insideCounter = $outCounter) ## 设置内层循环的起始位置,这样保证只会向下比较
				#foreach($next in $tableList) ## 向下继续查找相同年龄的行数
					## 确保不会超出表格数据范围,将当前年龄与下一行的年龄进行比较
					#if($insideCounter < $tableList.size() && $currentAge == $tableList.get($insideCounter).age)
						#set($ageCount = $ageCount + 1) ## 计数器 + 1
						#set($insideCounter = $insideCounter + 1) ## 移动到下一行继续比较
					#else
						#break
					#end
				#end
				## 只会渲染有计数的行
				<td class="cell-left" colspan="3" #if($ageCount > 1)rowspan="$ageCount"#end>$!item.age</td>
			#end
	</tr>
#end