mcpField
B
boxlang-templating

boxlang-templating

github.com/ortus-boxlang开发045 次安装1 周前更新
代码仓库

关于 boxlang-templating

boxlang-templating 是面向 BoxLang 开发者的服务端页面模板技能,讲解如何在 `.bxm` 中组合 HTML 与动态代码,以及复用模板、控制流程和输出编码。

主要功能

  1. 01在 `.bxm` 文件中编写 HTML 与 BoxLang
  2. 02插值输出表达式
  3. 03条件判断与迭代
  4. 04复用局部模板和布局
  5. 05在模板中编写脚本块
  6. 06HTML 输出编码指导

适用场景

  1. 01构建动态 BoxLang 网页
  2. 02使用共享布局组织视图
  3. 03安全呈现用户提供的内容

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ortus-boxlang/skills --skill boxlang-templating

安装后在 Claude Code 中输入/boxlang-templating确认已加载。

详细介绍

BoxLang 模板语言

BoxLang 是面向 AI 的软件生产力平台,用于构建、现代化改造和运行应用程序,让开发者与 AI Agent 协同工作。

概览

BoxLang 模板语言使用 .bxm 文件(BoxLang 标记)将 HTML 与动态服务器端代码混合使用。.bxm 文件的默认模式是 HTML 输出——使用 <bx:*> 标签嵌入 BoxLang 逻辑,并通过 #expression# 输出表达式。


文件类型一览

扩展名默认模式主要用途
.bx脚本类、服务、模型
.bxs脚本独立脚本、CLI 工具
.bxm标签/标记模板、视图、HTML 页面

输出表达式语法

使用 #expression# 插入值。在 <bx:output> 中,表达式会被求值并自动进行 HTML 转义:

<bx:output>
    <h1>Hello, #user.name#!</h1>
    <p>Today is #dateFormat( now(), "long" )#</p>
    <p>Items: #order.items.len()#</p>
</bx:output>

始终将输出包裹在 <bx:output> 中——否则,#variable# 会被视为字面字符串,而不会进行求值:


<p>#name#</p>


<bx:output><p>#name#</p></bx:output>

对于可复用的局部模板(app/views/partials/*.bxm),只要渲染的 HTML 区块中包含插值,就应将 <bx:output> 作为该区块的包裹标签。将 bx:param 和 bx:set 声明放在输出区块之外。


核心模板组件

<bx:output> — 渲染动态内容
<bx:output>
    <p>User: #user.firstName# #user.lastName#</p>
    <p>Email: #encodeForHTML( user.email )#</p>
</bx:output>

选项:

  • encodeFor="html" — 自动编码所有表达式(适用于不受信任的数据,推荐使用)

<bx:output encodeFor="html">
    <p>#userSuppliedContent#</p>
</bx:output>
<bx:set> — 声明变量
<bx:set var="greeting" value="Hello, #user.name#!">
<bx:set var="items" value="#productService.getFeatured()#">
<bx:set var="count" value="#items.len()#">
<bx:if> / <bx:elseif> / <bx:else> — 条件语句
<bx:if condition="#user.isLoggedIn#">
    <p>Welcome back, #encodeForHTML( user.name )#!</p>
<bx:elseif condition="#session.hasGuideToken#">
    <p>Continue as guest</p>
<bx:else>
    <a href="/login">Please log in</a>
</bx:if>
<bx:loop> — 迭代

数组循环:

<bx:loop array="#products#" item="product">
    <div class="product">
        <h3><bx:output>#encodeForHTML( product.name )#</bx:output></h3>
        <p><bx:output>$#numberFormat( product.price, "0.00" )#</bx:output></p>
    </div>
</bx:loop>

结构体循环:

<bx:loop struct="#config#" item="value" key="key">
    <bx:output><p>#key#: #value#</p></bx:output>
</bx:loop>

查询循环:

<bx:loop query="#users#">
    <bx:output>
        <tr>
            <td>#users.id#</td>
            <td>#encodeForHTML( users.name )#</td>
            <td>#encodeForHTML( users.email )#</td>
        </tr>
    </bx:output>
</bx:loop>

索引/计数循环:

<bx:loop from="1" to="#items.len()#" index="i">
    <bx:output><li>#i#. #items[ i ].name#</li></bx:output>
</bx:loop>
<bx:include> — 引入局部模板

<bx:include template="/includes/header.bxm">

<main>
    
</main>

<bx:include template="/includes/footer.bxm">

通过当前作用域向引入的模板传递变量(默认情况下,引入时会继承变量)。

<bx:script> — 内联脚本块

在模板中切换到脚本模式:

<bx:script>
    var products  = productService.getFeatured( limit=6 )
    var totalPages = ceiling( products.recordCount / 10 )
</bx:script>

<bx:loop array="#products#" item="p">
    <bx:output><div>#p.name#</div></bx:output>
</bx:loop>
<bx:switch> / <bx:case> — Switch 语句
<bx:switch expression="#user.role#">
    <bx:case value="admin">
        <bx:include template="/views/admin-dashboard.bxm">
    </bx:case>
    <bx:case value="editor">
        <bx:include template="/views/editor-dashboard.bxm">
    </bx:case>
    <bx:defaultcase>
        <bx:include template="/views/user-dashboard.bxm">
    </bx:defaultcase>
</bx:switch>
<bx:try> / <bx:catch> — 模板中的错误处理
<bx:try>
    <bx:set var="data" value="#remoteService.getData()#">
    <bx:output><p>#data.message#</p></bx:output>
<bx:catch type="any" variable="e">
    <p class="error">Could not load data: <bx:output>#encodeForHTML( e.message )#</bx:output></p>
</bx:catch>
</bx:try>

混用脚本和标签语法

你可以在 .bxm 文件中自由混用脚本块和标签组件:

<bx:script>
    // Load data using script syntax
    var pageTitle    = "Product Catalog"
    var categories   = categoryService.getAll()
    var featuredIds  = url.keyExists( "cat" ) ? [ url.cat ] : []
</bx:script>

<!DOCTYPE html>
<html lang="en">
<head>
    <bx:output><title>#encodeForHTML( pageTitle )#</title></bx:output>
</head>
<body>
    <nav>
        <bx:loop array="#categories#" item="cat">
            <bx:output>
                <a href="/catalog?cat=#encodeForURL( cat.slug )#"
                   class="#featuredIds.contains( cat.id ) ? 'active' : ''#">
                    #encodeForHTML( cat.name )#
                </a>
            </bx:output>
        </bx:loop>
    </nav>
</body>
</html>

布局/视图模式

嵌套引入(布局模式)

<!DOCTYPE html>
<html lang="en">
<head>
    <bx:output><title>#pageTitle ?: "My App"#</title></bx:output>
    <link rel="stylesheet" href="/css/app.css">
</head>
<body>
    <bx:include template="/views/partials/nav.bxm">
    <main>
        <bx:include template="#contentTemplate#">
    </main>
    <bx:include template="/views/partials/footer.bxm">
</body>
</html>

<bx:set var="pageTitle" value="Dashboard">
<bx:set var="contentTemplate" value="/views/dashboard-content.bxm">
<bx:include template="/views/layout.bxm">

HTML 输出编码参考

渲染前始终对用户提供的数据进行编码:

<bx:output>
    
    <p>#encodeForHTML( userBio )#</p>

    
    <input value="#encodeForHTMLAttribute( formValue )#">

    
    <a href="/profile?u=#encodeForURL( username )#">View Profile</a>

    
    <script>
        const name = "#encodeForJavaScript( displayName )#";
    </script>
</bx:output>

模板中的查询之查询

使用 <bx:query> 直接在模板中执行数据库查询(简单模板可以接受;复杂逻辑应优先放在服务层):

<bx:script>
    var users = queryExecute(
        "SELECT id, name, email FROM users WHERE active = :active ORDER BY name",
        { active: { value: true, cfsqltype: "cf_sql_bit" } }
    )
</bx:script>

<table>
    <thead><tr><th>Name</th><th>Email</th></tr></thead>
    <tbody>
        <bx:loop query="#users#">
            <bx:output>
                <tr>
                    <td>#encodeForHTML( users.name )#</td>
                    <td>#encodeForHTML( users.email )#</td>
                </tr>
            </bx:output>
        </bx:loop>
    </tbody>
</table>

应避免的常见错误

错误修正方法
在 <bx:output> 之外使用 #var#用 <bx:output> 包裹
输出中的原始用户数据使用 encodeForHTML() 或 encodeFor="html"
模板中包含过多逻辑将逻辑移至服务层;模板只负责展示
缺少闭合标签<bx:if> 需要 </bx:if>,<bx:loop> 需要 </bx:loop>
变量未指定作用域使用 <bx:set> 或 <bx:script> 中的 var 语句进行声明
使用绝对操作系统路径进行引入使用相对于 Web 根目录的路径:/views/...

评论

支持 Markdown