Vapor 教程
用 Leaf 渲染动态网页
接口返回 JSON 是给前端 App 用的;但要做一个人人能直接打开的网站,你得返回 HTML。Leaf 就是 Vapor 自带的模板语言:把变量塞进页面,动态生成最终 HTML。
一、为什么需要模板引擎
你可以手写字符串拼 HTML,但一旦页面多了、还要套用公共头部和底部,就会又臭又长。模板引擎的任务是:在静态 HTML 的骨架上,留出变量坑位,运行时把数据填进去。Leaf 就是 Vapor 官方推荐的那个引擎,纯 Swift 生态、零额外依赖。
二、先把 Leaf 加进来
在 Package.swift 的 dependencies 里加入 Leaf:
.package(url: "https://github.com/vapor/leaf.git", from: "4.0.0")并在 target 的依赖里引用它。然后在 configure.swift 中把 Leaf 注册为一种「视图渲染服务」:
import Leaf
app.views.use(.leaf)新建目录 Resources/Views/,模板文件就放在这里,后缀是 .leaf。
三、你的第一个模板
建一个 Resources/Views/index.leaf,内容就是普通 HTML,区别是用 #(变量名) 占位:
<!DOCTYPE html>
<html>
<head><title>#(title) | Acronyms</title></head>
<body>
<h1>#(title)</h1>
<p>欢迎来到用 Swift 写的网站。</p>
</body>
</html>这里的 #(title) 就是坑位,运行时由 Swift 填值。
四、用上下文把数据传进去
控制器里通常定义一个遵循 Encodable 的「上下文」结构体,专门描述这个页面需要哪些数据:
struct IndexContext: Encodable {
let title: String
}渲染时把上下文一并传进去:
import Vapor
import Leaf
struct WebsiteController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.get(use: indexHandler)
}
func indexHandler(_ req: Request) throws -> EventLoopFuture<View> {
let context = IndexContext(title: "首页")
return req.view.render("index", context)
}
}req.view.render("index", context) 会去找 index.leaf,把 title 填进 #(title),最后返回一页完整 HTML。
本质是服务端渲染:Leaf 在服务器上就把页面拼好再发给浏览器,所以首屏快、对 SEO 友好。它跟前端的 React/Vue 是两套思路,按需选择。
五、常用模板语法
Leaf 不止能填变量,还支持基础逻辑:
#(name):输出变量。#for(item in items):遍历数组,渲染列表(比如把所有缩略语列出来)。#if(condition):条件判断,控制某段显隐。#embed("header"):把另一个模板(如公共头部)嵌进来,避免重复。
例如列出所有缩略语:
#for(acronym in acronyms)
<li>#(acronym.short) — #(acronym.long)</li>
#endfor六、下一步
页面要显示真实数据,得接数据库。下一篇我们用 Fluent 把「缩略语」存进数据库,并在控制器里查询后交给 Leaf 渲染。