65.9K
CodeProject 正在变化。 阅读更多。
Home

Bellevue View Engine 入门 - 第二部分

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (3投票s)

2010年3月19日

CPOL

9分钟阅读

viewsIcon

12679

downloadIcon

3

ASP.NET MVC 框架的新模板引擎原型,它尊重 HTML 并使用类似 CSS 的语法进行模型绑定。

Bellevue 是 ASP.NET MVC 框架中一款新的开源模板引擎的原型。Bellevue 的核心使用纯 HTML,没有任何额外的标签或语法。然后,它使用类似 CSS 的语法将活动逻辑注入 HTML 中——换句话说,就是将数据从模型绑定到视图。

intro_picture.png

在本文的第一部分中,我简要介绍了这个想法和一些基本功能。您也可以在那里找到完整的下载包

第二部分包含以下内容

模板

模板通常在需要将某些 HTML 应用于集合中的每个元素时使用。在 Web Forms 页面中,这取代了重复循环的需要(“/Views/Demo/Demo2_Intro_WebForms.aspx”)。

<div class="productList">
    <%
        foreach (string name in (string[])ViewData["AllNames"])
        {
    %>
        <div><a href="https://codeproject.org.cn/demo/Demo2_Intro_Bellevue/
		<%= name %>"><%= name %></a></div>
    <% 
        }
    %>
</div>

请注意,您也可以将模板应用于单个项目,但这目前不太有用。在未来版本中,条件模板和内联模板将使其成为更合理的场景。

您可以通过 `@template` 指令定义模板开始使用模板(“Demo2_Intro_Bellevue.bvue”)。

@template productListTemplate "#leftArea .productList div"
{
    a        
    {
        text:   item(); 
        attr:   href concat("/demo/Demo2_Intro_Bellevue/", item());
    }
}

第一个参数是模板的 ID(与 HTML ID 无关),第二个参数是用于在 HTML 中查找模板的选择器。匹配的元素将从原始 HTML 中移除,仅在调用 apply-template 时使用。

在模板内部,您可能拥有特定于模板的规则集。在这种情况下,模板中的文本和 href 属性将被修改。您也可以在模板内部调用 apply-template,因此嵌套模板是可能的。“item()”函数在循环遍历集合时返回将模板绑定到的项目。

在这种情况下,选择器匹配此 HTML(“Demo2_Intro_Bellevue.html”)。

<div class="productList">
    <div><a href="https://codeproject.org.cn/linkHere">Product 1</a></div>
    <div><a href="https://codeproject.org.cn/linkHere">Product 2</a></div>
    <div><a href="https://codeproject.org.cn/linkHere">Product 3</a></div>
</div>

所有内部 `div` 都被视为模板并一个接一个地应用。在这种情况下,它们都是相同的,但也可以有不同的 HTML,例如,如果您希望奇数行和偶数行具有不同的颜色。

要应用 HTML,您可以使用 apply-template 声明。

#leftArea .productList {   apply-template: data(AllNames) productListTemplate }

在下一个预览版本中,模板语法应该明显有更多的选项。我已经准备好了大部分底层工作,但我需要检查具体如何实现语法。想法是添加以下功能:

  • 内联模板:可以直接在 Bellevue 脚本中添加模板 HTML 的可能性。
  • 条件模板:如果“item(x)”为 `true`,则使用此模板,否则使用那个模板。
  • 使匹配项的内部 HTML 成为模板,而不是外部 HTML。
    • 将允许类似 `text <br />` 的模板。现在您需要使用 `span` 包围它,或者使用非 HTML 标签来 hack 它。
  • 来自包含文件的模板

此外,当前实现中最重要的缺失功能是定义新属性的可能性,当您调用模板时:因此,您将拥有一个始终需要参数“`item(link)`”和“`item(label)`”的可重用模板,并且在调用模板时,您可以指定例如“`link=item(url), label=item(text)`”。我有点 difficoltà 在找出一种与 CSS 语法兼容的良好语法,但它会存在的——我保证。

因此,通过模板,当前版本缺少许多功能。这是最大的未完成领域。但我希望您能理解其潜在的力量:只需几行代码即可轻松创建重复的表行和其他部分。这比使用 Web Forms 容易得多。

母版页

母版页是 Web Forms 特有的:没有 ASP.NET MVC 标准方法可以插入其中。因此,每个视图引擎通常都会创建自己的母版页系统。在 Bellevue 中,您可以使用 `@master` 指令定义一个母版视图(“/Views/Shared/Site_Master.html”)。

@master
{
    #mainContentPlaceholder
    {
        placeholder-id:     main;
    }
    title
    {
        placeholder-id:     title;
    }
    #pageStyles
    {
        placeholder-id:     styles;
    }
}

选择器可以是任何匹配 HTML 的有效选择器——事实上,甚至可以是多个元素 。ID 必须是唯一的。此外,您还可以拥有普通的 Bellevue 规则集,以向母版页 HTML 添加活动内容。

您在单个视图中使用母版视图,使用 `@master`-is 指令(“Demo3_UseMaster.html”)。

@master-is Site_Master
{
    body    { placeholder: main; }
    title   { placeholder: title; }
    
    /*  When page is called with "?useAnotherMaster=true",
        the value "Site_Master" above is overridden by controller */
}

上面示例中的 Body 和 title 可以是页面中的任何选择器。因此,页面可以是一个完整的 HTML 页面,它可以独立渲染,但当应用于母版页时,它的某些部分将被提取(示例就是这样)。

您可以在控制器中切换母版页,就像在 Web Forms 中一样(例如,请参阅 Demo 控制器操作“Demo3_UseMaster”)。

我对母版视图的概念非常满意。我正在考虑添加的唯一内容是自动支持 head 中的 title、styles 和 scripts,以及 body 末尾的 elements。另一件事是,目前,如果没有内容添加到占位符,则渲染占位符内的 HTML,但不会应用任何活动内容——这将通过模板修复。

功能计划

上面,我已经列出了我计划在模板和母版视图中实现的功能。还有一个 `@if` 指令解释在此页面的末尾,但它目前仍然缺少 `else` 和 `else`-`if` 功能,所以现在谈论它没有意义。

我不会做出任何承诺,但这些是我正在考虑的事情:

  • 目前,每个元素或属性都只应用一个声明(除 `@if` 外,即使在那里也有一些问题):应用更多的可能性。
  • 可扩展性:自定义声明处理程序和渲染器,可能还有指令和格式化程序。
  • 实现 ASP.NET MVC `HtmlHelper` 方法:并非所有方法,但那些有意义的方法。
  • 其他声明,如:`display`/`hide`、`attr-hide`、`change-element`。
  • `@debugger` 指令用于更多控制。
  • 解析到 `ViewData` 和 `Model` 属性路径在大多数情况下有效,但在边缘情况/一致性方面仍有改进空间。
  • 缓存

关注点

StringTemplate 作为灵感

对我来说,设计中的主要灵感来自 Terence Parr 的StringTemplate。我试图遵循的主要一点是严格的模型-视图分离原则。来自 `StringTemplate` 网站:

其独特的特征在于它严格强制模型-视图分离,不像其他引擎。严格分离使网站和代码生成器更灵活、更易于维护;它还提供了针对恶意模板作者的绝佳防御。

我确实相信这个概念:我认为 ASP.NET (MVC) Web Forms 的主要问题之一是,当开发人员在项目中面临压力时,他们开始将模型和控制器逻辑黑入 aspx 视图,而不是在控制器和模型代码中进行适当的更改。我见过这种情况发生很多次,我必须承认我自己也这样做过。

查看上面的 PDF 链接以了解整个模型-视图分离的概念。演示项目包含与 `StringTemplate` 功能的比较。

其他鸣谢

我使用以下优秀项目作为实现的基石:

  • 要解析 HTML,我使用了HTML Agility Pack。这个项目似乎相当成熟:我发现了一个 bug,而且它很小。
  • 我使用Simple CSS Parser来解析 Bellevue 脚本。在那里,我遇到了更多问题,我可能被迫更改解析器中的代码或实现自定义解析器。这并不是说 CSS Parser 项目质量不好:只是 Bellevue 脚本并非真正是 CSS,我使用了许多边缘情况,这会产生问题。
  • 为了根据 CSS 选择器在 HTML 中定位自定义逻辑,我当然使用了Fizzler。我按设计使用它——我没有尝试过很多边缘情况,但它似乎运行良好。但请注意,它尚未实现所有更复杂的 CSS Level 3 选择器。

主要设计:解析与渲染和可扩展性

如果您查看了代码,您可能会问为什么解析和渲染代码如此复杂。您可以以更简单的方式做到这一点。第一个原因是性能考虑。

`HtmlAgilityPack` 相当快——对于普通的网站和页面,渲染时间真的可以接受,通常在第一次 JIT 加载后几十毫秒。但对于大型站点以及包含大量替换的大型页面,这可能太多了。所以想法是将 Bellevue 渲染分成两部分:

解析将是 `HtmlAgilityPack`、CSS 解析器和 Fizzler 使用 HTML 和 CSS DOM 和选择器进行繁重解析的部分。它将规则集和指令放置在 HTML 各处,分离模板等。此逻辑应独立于 `ViewData`,后者可能在每次调用时都不同,以便此工作可以缓存以供多次页面调用作为解析结果。

然后将为每次调用进行渲染,并且无法访问完整的 HTML DOM。它获取解析结果并直接输出 HTML,并在有活动内容的地方插入数据。目前解析结果基于 HTML DOM,并且每次都进行,所以没有性能提升。但未来版本可以实现缓存机制,例如将 `static` HTML 部分组合成长 `string`,就像 aspx 编译所做的那样。在极端情况下,甚至可能在解析时从 Bellevue 视图创建 ASPX,但我不知道这是否有意义。

增加复杂性的第二件事是可扩展性。目前还没有可扩展性 API,但我正在为此做准备。想法是您可以添加自己的声明处理程序、渲染器——甚至指令和格式化程序。这样,您就可以添加自己的视图功能,就像您可以为 Web Forms 添加 HTML 帮助器一样。

欢迎反馈

所以,这就是我目前正在努力的方向。我非常希望得到 The Code Project 的各位朋友的反馈

  • 您认为这种方法/语法有意义吗?
  • 您是否清楚地看到了我列表中的缺失功能?
  • 您能否看到一个有效的 MVC 视图,您无法通过这些功能实现?……同时牢记模型-视图分离原则。

当我有发布候选版本然后是 1.0 版本时,我会更新这些文章。在我自己的主页http://www.ope.ag/bellevue上,我有更多材料,我将更频繁地更新。但那里没有讨论/评论,所以目前 CodeProject 页面是提供反馈的最佳场所。

历史

  • 2010年3月19日:初始发布
© . All rights reserved.