Handlebars.Net 2.1.6
前缀已保留
dotnet add package Handlebars.Net --version 2.1.6
NuGet\Install-Package Handlebars.Net -Version 2.1.6
<PackageReference Include="Handlebars.Net" Version="2.1.6" />
paket add Handlebars.Net --version 2.1.6
#r "nuget: Handlebars.Net, 2.1.6"
// Install Handlebars.Net as a Cake Addin #addin nuget:?package=Handlebars.Net&version=2.1.6 // Install Handlebars.Net as a Cake Tool #tool nuget:?package=Handlebars.Net&version=2.1.6
Handlebars.Net
在您的 .NET 应用程序中快速执行 Handlebars.js 模板。
Handlebars.js 是由 Chris Wanstrath 创建的 Mustache 模板语言的扩展。Handlebars.js 和 Mustache 都是逻辑无关的模板语言,它们像我们所有人都知道的那样将视图和代码分开。
查看 handlebars.js 文档 了解如何编写 Handlebars 模板。
Handlebars.Net 不使用脚本引擎来运行 JavaScript 库 - 它 将 Handlebars 模板直接编译为 IL 字节码。它还尽可能地模拟 JS 库的 API。
安装
dotnet add package Handlebars.Net
扩展
以下项目扩展了 Handlebars.Net
- Handlebars.Net.Extension.Json(添加
System.Text.Json.JsonDocument
支持) - Handlebars.Net.Extension.NewtonsoftJson(添加
Newtonsoft.Json
支持) - Handlebars.Net.Helpers(提供更多辅助函数,分类包括:'Constants', 'Enumerable', 'Math', 'Regex', 'String', 'DateTime', 'Url', 'DynamicLinq', 'Humanizer', 'Json', 'Random', 'Xeger' 和 'XPath'。)
用法
string source =
@"<div class=""entry"">
<h1>{{title}}</h1>
<div class=""body"">
{{body}}
</div>
</div>";
var template = Handlebars.Compile(source);
var data = new {
title = "My new post",
body = "This is my first post!"
};
var result = template(data);
/* Would render:
<div class="entry">
<h1>My New Post</h1>
<div class="body">
This is my first post!
</div>
</div>
*/
注册部分视图
string source =
@"<h2>Names</h2>
{{#names}}
{{> user}}
{{/names}}";
string partialSource =
@"<strong>{{name}}</strong>";
Handlebars.RegisterTemplate("user", partialSource);
var template = Handlebars.Compile(source);
var data = new {
names = new [] {
new {
name = "Karen"
},
new {
name = "Jon"
}
}
};
var result = template(data);
/* Would render:
<h2>Names</h2>
<strong>Karen</strong>
<strong>Jon</strong>
*/
注册辅助函数
Handlebars.RegisterHelper("link_to", (writer, context, parameters) =>
{
writer.WriteSafeString($"<a href='{context["url"]}'>{context["text"]}</a>");
});
string source = @"Click here: {{link_to}}";
var template = Handlebars.Compile(source);
var data = new {
url = "https://github.com/rexm/handlebars.net",
text = "Handlebars.Net"
};
var result = template(data);
/* Would render:
Click here: <a href='https://github.com/rexm/handlebars.net'>Handlebars.Net</a>
*/
此操作将期望你的视图位于 /Views 文件夹中,如下所示:
Views\layout.hbs |<--shared as in \Views
Views\partials\somepartial.hbs <--shared as in \Views\partials
Views\{Controller}\{Action}.hbs
Views\{Controller}\{Action}\partials\somepartial.hbs
注册区块辅助函数
Handlebars.RegisterHelper("StringEqualityBlockHelper", (output, options, context, arguments) =>
{
if (arguments.Length != 2)
{
throw new HandlebarsException("{{#StringEqualityBlockHelper}} helper must have exactly two arguments");
}
var left = arguments.At<string>(0);
var right = arguments[1] as string;
if (left == right) options.Template(output, context);
else options.Inverse(output, context);
});
var animals = new Dictionary<string, string>()
{
{"Fluffy", "cat" },
{"Fido", "dog" },
{"Chewy", "hamster" }
};
var template = "{{#each this}}The animal, {{@key}}, {{#StringEqualityBlockHelper @value 'dog'}}is a dog{{else}}is not a dog{{/StringEqualityBlockHelper}}.\r\n{{/each}}";
var compiledTemplate = Handlebars.Compile(template);
string templateOutput = compiledTemplate(animals);
/* Would render
The animal, Fluffy, is not a dog.
The animal, Fido, is a dog.
The animal, Chewy, is not a dog.
*/
注册装饰器
[Fact]
public void BasicDecorator(IHandlebars handlebars)
{
string source = "{{#block @value-from-decorator}}{{*decorator 42}}{{@value}}{{/block}}";
var handlebars = Handlebars.Create();
handlebars.RegisterHelper("block", (output, options, context, arguments) =>
{
options.Data.CreateProperty("value", arguments[0], out _);
options.Template(output, context);
});
handlebars.RegisterDecorator("decorator",
(TemplateDelegate function, in DecoratorOptions options, in Context context, in Arguments arguments) =>
{
options.Data.CreateProperty("value-from-decorator", arguments[0], out _);
});
var template = handlebars.Compile(source);
var result = template(null);
Assert.Equal("42", result);
}
更多示例请参阅 DecoratorTests.cs
已知限制
- 在装饰器内注册的辅助函数不会覆盖现有注册
注册自定义值格式化
如果你需要应用自定义值格式化(例如 DateTime
),可以使用 IFormatter
和 IFormatterProvider
接口
public sealed class CustomDateTimeFormatter : IFormatter, IFormatterProvider
{
private readonly string _format;
public CustomDateTimeFormatter(string format) => _format = format;
public void Format<T>(T value, in EncodedTextWriter writer)
{
if(!(value is DateTime dateTime))
throw new ArgumentException("supposed to be DateTime");
writer.Write($"{dateTime.ToString(_format)}");
}
public bool TryCreateFormatter(Type type, out IFormatter formatter)
{
if (type != typeof(DateTime))
{
formatter = null;
return false;
}
formatter = this;
return true;
}
}
[Fact]
public void DateTimeFormatter(IHandlebars handlebars)
{
var source = "{{now}}";
var format = "d";
var formatter = new CustomDateTimeFormatter(format);
handlebars.Configuration.FormatterProviders.Add(formatter);
var template = handlebars.Compile(source);
var data = new
{
now = DateTime.Now
};
var result = template(data);
Assert.Equal(data.now.ToString(format), result);
}
备注
- 格式化程序根据注册顺序反向解析。如果有多个提供程序可以提供类型格式化程序,则最后一个注册的会被使用。
共享环境
默认情况下,Handlebars 将为每个编译模板创建一个独立的副本环境。这样做是为了防止从另一个模板中更改一个模板的行为。
不幸的是,如果运行时有大量的编译模板(无论模板大小如何),它可能对内存占用很大。这可以通过使用 SharedEnvironment
解决。
在 SharedEnvironment
中编译的模板将共享相同的配置。
限制
已创建共享环境后,只能更改运行时配置属性。对 Configuration.CompileTimeConfiguration
和其他编译时属性的更改将没有任何效果。
示例
[Fact]
public void BasicSharedEnvironment()
{
var handlebars = Handlebars.CreateSharedEnvironment();
handlebars.RegisterHelper("registerLateHelper",
(in EncodedTextWriter writer, in HelperOptions options, in Context context, in Arguments arguments) =>
{
var configuration = options.Frame
.GetType()
.GetProperty("Configuration", BindingFlags.Instance | BindingFlags.NonPublic)?
.GetValue(options.Frame) as ICompiledHandlebarsConfiguration;
var helpers = configuration?.Helpers;
const string name = "lateHelper";
if (helpers?.TryGetValue(name, out var @ref) ?? false)
{
@ref.Value = new DelegateReturnHelperDescriptor(name, (c, a) => 42);
}
});
var _0_template = "{{registerLateHelper}}";
var _0 = handlebars.Compile(_0_template);
var _1_template = "{{lateHelper}}";
var _1 = handlebars.Compile(_1_template);
var result = _1(null);
Assert.Equal("", result); // `lateHelper` is not registered yet
_0(null);
result = _1(null);
Assert.Equal("42", result);
}
兼容性功能开关
兼容性功能开关定义了一组控制编译/渲染行为的设置。每个设置都会启用某些特性,这可能会破坏与标准 Handlebars 的兼容性。默认情况下,所有开关都设置为 false
。
传说
- 区域
编译时间
:在模板编译时产生影响运行时
:在模板渲染时产生影响
RelaxedHelperNaming
如果为 true
,则启用对 Handlebars.Net 辅助函数命名规则的支持。这允许辅助函数名称不是有效的 Handlebars 标识符(例如 {{ one.two }}
)。这种命名在 Handlebarsjs 中不受支持,将会破坏兼容性。
区域
编译时间
示例
[Fact]
public void HelperWithDotSeparatedName()
{
var source = "{{ one.two }}";
var handlebars = Handlebars.Create();
handlebars.Configuration.Compatibility.RelaxedHelperNaming = true;
handlebars.RegisterHelper("one.two", (context, arguments) => 42);
var template = handlebars.Compile(source);
var actual = template(null);
Assert.Equal("42", actual);
}
HtmlEncoder
用于在旧版 Handlebars.Net 和标准 Handlebars 规则(或自定义实现)之间切换。
对于 Handlebars.Net 2.x.x,HtmlEncoderLegacy
是默认的。
HtmlEncoder
实现标准 Handlebars 规则。
HtmlEncoderLegacy
不会编码
=(等于)
`(反引号)
'(单引号)
将编码非 ASCII 字符 �
,�
,...
为 HTML 实体(<
,â
,ß
,...)。
区域
运行时
示例
[Fact]
public void UseCanonicalHtmlEncodingRules()
{
var handlebars = Handlebars.Create();
handlebars.Configuration.TextEncoder = new HtmlEncoder();
var source = "{{Text}}";
var value = new { Text = "< �" };
var template = handlebars.Compile(source);
var actual = template(value);
Assert.Equal("< �", actual);
}
性能
编译
与渲染相比,编译是一个相当密集的过程。虽然两者都是在毫秒级别测量的,但编译所占用的时间最多。因此,通常最好是只编译一次并将其缓存的结果函数用于重用的生命周期。
渲染
几乎所有的时间都花在将值与模型解析的例程中。不同类型的对象作为模型使用时具有不同的性能特征。
模型类型
- 绝对最快的模型是
IDictionary
(微秒)。 - 其次是 POCO(对于平均大小的模板和模型通常需要几毫秒),它使用传统的反射并且相当快。
- 动态对象上的渲染速度开始变慢(到几十毫秒或更多)。
- 最慢的(高达几百毫秒或更差)往往是具有自定义类型实现的对象(例如
ICustomTypeDescriptor
),这些对象不适用于重量级反射。
未来路线图
待定
贡献
欢迎拉取请求!指南相当直接
- 只添加 Mustache / Handlebars 规范中已有的功能
- 避免使用 .NET BCL 之外的外部依赖项
- 保持跨平台兼容性(.NET/Mono;Windows/OSX/Linux 等)
- 遵循既定的代码格式
产品 | 版本 兼容的和其它计算目标框架版本。 |
---|---|
.NET | net5.0 被计算。 net5.0-windows 被计算。 net6.0 兼容。 net6.0-android 被计算。 net6.0-ios 被计算。 net6.0-maccatalyst 被计算。 net6.0-macos 被计算。 net6.0-tvos 被计算。 net6.0-windows 被计算。 net7.0 被计算。 net7.0-android 被计算。 net7.0-ios 被计算。 net7.0-maccatalyst 被计算。 net7.0-macos 被计算。 net7.0-tvos 被计算。 net7.0-windows 被计算。 net8.0 被计算。 net8.0-android 被计算。 net8.0-browser 被计算。 net8.0-ios 被计算。 net8.0-maccatalyst 被计算。 net8.0-macos 被计算。 net8.0-tvos 被计算。 net8.0-windows 被计算。 |
.NET Core | netcoreapp1.0 已计算。 netcoreapp1.1 已计算。 netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。 |
.NET标准 | netstandard1.3 兼容。 netstandard1.4 已计算。 netstandard1.5 已计算。 netstandard1.6 已计算。 netstandard2.0 兼容。 netstandard2.1 兼容。 |
.NET框架 | net451 兼容。 net452 已计算。 net46 已计算。 net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。 |
MonoAndroid | monoandroid 已计算。 |
MonoMac | monomac 已计算。 |
MonoTouch | monotouch 已计算。 |
Tizen | tizen30 已计算。 tizen40 已计算。 tizen60 已计算。 |
通用Windows平台 | uap 已计算。 uap10.0 已计算。 |
Xamarin.iOS | xamarinios 已计算。 |
Xamarin.Mac | xamarinmac 已计算。 |
Xamarin.TVOS | xamarintvos 已计算。 |
Xamarin.WatchOS | xamarinwatchos 已计算。 |
-
.NETFramework 4.5.1
- System.ValueTuple (>= 4.5.0)
-
.NETStandard 1.3
- Microsoft.CSharp (>= 4.7.0)
- NETStandard.Library (>= 1.6.1)
- System.ComponentModel.TypeConverter (>= 4.3.0)
- System.Diagnostics.Contracts (>= 4.3.0)
- System.ValueTuple (>= 4.5.0)
-
.NETStandard 2.0
- Microsoft.CSharp (>= 4.7.0)
-
.NETStandard 2.1
- Microsoft.CSharp (>= 4.7.0)
-
net6.0
- 没有依赖关系。
NuGet 包 (185)
显示依赖 Handlebars.Net 的前 5 个 NuGet 包
包 | 下载 |
---|---|
Handlebars.Net.AutoRender Handlebars.Net.AutoRender 的核心功能 |
|
EntityFrameworkCore.Scaffolding.Handlebars
允许使用 Entity Framework Core 工具链和 Handlebars 模板自定义从现有数据库反向工程生成的类。 |
|
SyncSoft.App.HandlebarsDotNet
一个适用于 SyncSoft Inc. 的应用框架 |
|
Handlebars.Net.Extension.Json Handlebars.Net 的 System.Text.Json 扩展 |
|
Handlebars.Net.Extension.NewtonsoftJson Handlebars.Net 的 Newtonsoft.Json 扩展 |
GitHub 仓库 (27)
显示依赖 Handlebars.Net 的前 5 个最受欢迎的 GitHub 仓库
仓库 | Stars |
---|---|
microsoft/semantic-kernel
快速轻松地将尖端 LLM 技术集成到您的应用中
|
|
bitwarden/server
Bitwarden 基础设施/后端(API、数据库、Docker 等)。
|
|
dotnetcore/Util
Util 是一个 .Net 平台下的应用框架,旨在提升中小团队的开发能力,由工具类、分层架构基类、UI 组件,配套代码生成模板,权限等组成。
|
|
scriban/scriban
一个快速、强大、安全且轻量级的脚本语言和引擎,用于 .NET
|
|
ChangemakerStudios/Papercut-SMTP
Papercut SMTP -- 简单桌面电子邮件服务器
|
版本 | 下载 | 最后更新 |
---|---|---|
2.1.6 | 1,371,898 | 4/3/2024 |
2.1.5 | 87,121 | 4/1/2024 |
2.1.4 | 9,436,062 | 3/4/2023 |
2.1.3 | 356,392 | 2/15/2023 |
2.1.2 | 7,054,566 | 4/7/2022 |
2.1.1 | 269,448 | 3/26/2022 |
2.1.1-beta-1 | 10,816 | 3/4/2022 |
2.1.0 | 1,411,155 | 1/24/2022 |
2.0.10 | 753,416 | 12/22/2021 |
2.0.9 | 1,289,575 | 8/1/2021 |
2.0.8 | 576,121 | 6/2/2021 |
2.0.7 | 397,656 | 3/26/2021 |
2.0.6 | 29,156 | 3/21/2021 |
2.0.5 | 272,959 | 3/6/2021 |
2.0.4 | 4,145,960 | 1/7/2021 |
2.0.3 | 301,031 | 12/11/2020 |
2.0.2 | 20,679 | 12/8/2020 |
2.0.1 | 2,479 | 12/7/2020 |
2.0.0 | 18,105 | 12/6/2020 |
2.0.0-rc-2 | 2,323 | 12/2/2020 |
2.0.0-rc-1 | 1,676 | 12/2/2020 |
2.0.0-preview-2 | 12,986 | 11/6/2020 |
2.0.0-preview-1 | 2,190 | 10/26/2020 |
1.11.5 | 1,465,441 | 10/10/2020 |
1.11.4 | 3,867 | 10/10/2020 |
1.10.1 | 11,024,055 | 3/23/2019 |
1.10.0 | 7,120 | 3/22/2019 |
1.9.5 | 5,494,652 | 6/16/2018 |
1.9.4 | 96,958 | 5/26/2018 |
1.9.3 | 107,171 | 5/2/2018 |
1.9.0 | 3,180,476 | 5/16/2017 |
1.8.0 | 299,198 | 10/9/2016 |
1.7.1 | 197,690 | 6/4/2016 |
1.7.0 | 14,964 | 5/20/2016 |
1.6.8 | 10,703 | 5/18/2016 |
1.6.7 | 3,862 | 5/15/2016 |
1.6.6 | 2,655 | 5/14/2016 |
1.6.4 | 82,153 | 2/25/2016 |
1.6.3 | 8,162 | 2/22/2016 |
1.6.2 | 2,732 | 2/22/2016 |
1.6.1 | 6,426 | 2/7/2016 |
1.6.0 | 5,843 | 1/29/2016 |
1.5.3 | 5,962 | 1/26/2016 |
1.5.2 | 3,615 | 1/20/2016 |
1.5.1 | 3,630 | 1/5/2016 |
1.4.8 | 6,491 | 11/27/2015 |
1.4.6 | 3,924 | 11/24/2015 |
1.4.4 | 36,867 | 8/9/2015 |
1.4.3 | 2,865 | 8/8/2015 |
1.4.2 | 7,991 | 8/4/2015 |
1.4.0 | 25,927 | 7/20/2015 |
1.3.5 | 3,703 | 7/10/2015 |
1.3.3 | 82,502 | 5/18/2015 |
1.3.2 | 20,197 | 4/11/2015 |
1.3.1 | 2,843 | 4/2/2015 |
1.3.0 | 2,683 | 3/31/2015 |
1.2.10 | 7,413 | 3/17/2015 |
1.2.9 | 27,057 | 3/6/2015 |
1.2.8 | 2,778 | 2/27/2015 |
1.2.7 | 2,643 | 2/27/2015 |
1.2.6 | 6,227 | 2/15/2015 |
1.2.5 | 2,822 | 2/15/2015 |
1.2.4 | 2,841 | 2/13/2015 |
1.2.3 | 2,811 | 2/9/2015 |
1.2.2 | 2,775 | 2/8/2015 |
1.2.1 | 2,714 | 2/7/2015 |
1.2.0 | 3,020 | 1/18/2015 |
1.1.7 | 2,657 | 1/16/2015 |
1.1.6 | 2,621 | 1/16/2015 |
1.1.5 | 2,692 | 1/14/2015 |
1.1.4 | 2,680 | 1/10/2015 |
1.1.3 | 2,619 | 1/10/2015 |
1.1.2 | 2,700 | 1/9/2015 |
1.1.1 | 2,623 | 1/8/2015 |
1.1.0 | 3,033 | 1/7/2015 |
1.0.6 | 2,837 | 1/2/2015 |
1.0.5 | 2,954 | 1/2/2015 |
1.0.4 | 2,860 | 1/2/2015 |
1.0.3 | 2,959 | 12/20/2014 |
1.0.2 | 3,052 | 11/30/2014 |
1.0.0-beta9 | 2,562 | 6/29/2014 |
1.0.0-beta8 | 2,413 | 6/22/2014 |
1.0.0-beta6 | 2,459 | 6/21/2014 |
1.0.0-beta5 | 2,407 | 6/15/2014 |
1.0.0-beta4 | 2,352 | 5/27/2014 |
1.0.0-beta3 | 2,368 | 5/26/2014 |
1.0.0-beta2 | 2,350 | 5/17/2014 |
1.0.0-beta18 | 2,707 | 11/20/2014 |
1.0.0-beta17 | 2,602 | 11/17/2014 |
1.0.0-beta16 | 2,545 | 10/15/2014 |
1.0.0-beta12 | 2,383 | 9/18/2014 |
1.0.0-beta11 | 2,386 | 8/31/2014 |
1.0.0-beta1 | 2,478 | 5/3/2014 |
1.0.0-alpha5 | 2,371 | 5/13/2014 |
1.0.0-alpha4 | 2,401 | 5/11/2014 |
1.0.0-alpha2 | 3,256 | 5/10/2014 |