zoukankan      html  css  js  c++  java
  • DotLiquid模板引擎简介

    DotLiquid是一个在.Net Framework上运行的模板引擎,采用Ruby的Liquid语法,这个语法广泛的用在Ruby on rails和Django等网页框架中。
    DotLiquid相比于Mvc默认模板引擎Razor的好处有:

    • 因为不需要编译到程序集再载入
      • 首次渲染速度很快
      • 不会导致内存泄漏
    • 可以在任何地方使用
      • 不需要先准备WebViewPage,ViewContext等复杂的上下文对象

    DotLiquid的官网是http://dotliquidmarkup.org/,开源协议是非常宽松的MS-PL。

    示例代码

    我创建一个使用了DotLiquid的示例Mvc项目,完整代码可以查看这里
    以下的示例将以Mvc中的Action为单位,都存放在HomeController下。

    最基础的使用

    Template.Parse可以把字符串解析为模板对象,再使用Render把模板对象渲染为字符串。
    打开页面可以看见Hello, World!

    public ActionResult HelloWorld()
    {
    	var template = Template.Parse("Hello, {{ name }}!");
    	var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));
    	return Content(result);
    }
    

    使用过滤器

    |后面的就是过滤器,过滤器可以连锁起来使用。
    escape过滤器用于做html编码,避免name中的"<"当成是html标签描画。
    upcase过滤器把字符串中的字母全部转换为大写。
    打开页面可以看见Hello, <WORLD>!

    public ActionResult HelloFilter()
    {
    	var template = Template.Parse("Hello, {{ name | escape | upcase }}!");
    	var result = template.Render(Hash.FromAnonymousObject(new { name = "<World>" }));
    	return Content(result);
    }
    

    定义过滤器

    DotLiquid支持自定义过滤器,首先需要一个过滤器类型,其中的函数名称就是过滤器名称。
    过滤器支持多个参数和默认参数。

    public class DotliquidCustomFilter
    {
    	public static string Substr(string value, int startIndex, int length = -1)
    	{
    		if (length >= 0)
    			return value.Substring(startIndex, length);
    		return value.Substring(startIndex);
    	}
    }
    

    在网站启动的时候把这个过滤器注册到DotLiquid

    public class MvcApplication : System.Web.HttpApplication
    {
    	protected void Application_Start()
    	{
    		// 在原有的代码下添加
    		Template.RegisterFilter(typeof(DotliquidCustomFilter));
    	}
    }
    

    这个例子会显示Hello, orl!

    public ActionResult CustomFilter()
    {
    	var template = Template.Parse("Hello, {{ name | substr: 1, 3 }}!");
    	var result = template.Render(Hash.FromAnonymousObject(new { name = "World" }));
    	return Content(result);
    }
    

    使用标签

    DotLiquid中有两种标签,一种是普通标签(Block),一种是自闭合标签(Tag)。
    这里的assign是自闭合标签,if是普通标签,普通标签需要用end+标签名闭合。
    显示内容是Hello, World!

    public ActionResult HelloTag()
    {
    	var template = Template.Parse(@"
    		{% assign name = 'World' %}
    		{% if visible %}
    		Hello, {{ name }}!
    		{% endif %}
    	");
    	var result = template.Render(Hash.FromAnonymousObject(new { visible = true }));
    	return Content(result);
    }
    

    自定义标签

    这里我将定义一个自闭合标签conditional,这个标签有三个参数,如果第一个参数成立则描画第二个否则描画第三个参数。

    public class ConditionalTag : Tag
    {
    	public string ConditionExpression { get; set; }
    	public string TrueExpression { get; set; }
    	public string FalseExpression { get; set; }
    
    	public override void Initialize(string tagName, string markup, List<string> tokens)
    	{
    		base.Initialize(tagName, markup, tokens);
    		var expressions = markup.Trim().Split(' ');
    		ConditionExpression = expressions[0];
    		TrueExpression = expressions[1];
    		FalseExpression = expressions.Length >= 3 ? expressions[2] : "";
    	}
    
    	public override void Render(Context context, TextWriter result)
    	{
    		var condition = context[ConditionExpression];
    		if (!(condition == null || condition.Equals(false) || condition.Equals("")))
    			result.Write(context[TrueExpression]);
    		else
    			result.Write(context[FalseExpression]);
    	}
    }
    

    在网站启动时把这个标签注册到DotLiquid

    public class MvcApplication : System.Web.HttpApplication
    {
    	protected void Application_Start()
    	{
    		// 在原有的代码下添加
    		Template.RegisterTag<ConditionalTag>("conditional");
    	}
    }
    

    这个例子会显示Bar

    public ActionResult CustomTag()
    {
    	var template = Template.Parse("{% conditional cond foo bar %}");
    	var result = template.Render(Hash.FromAnonymousObject(new { cond = false, foo = "Foo", bar = "Bar" }));
    	return Content(result);
    }
    

    模板文件

    DotLiquid也支持从文件读取模板,需要先定义一个TemplateFileSystem

    public class DotliquidTemplateFileSystem : IFileSystem
    {
    	public string ReadTemplateFile(Context context, string templateName)
    	{
    		var path = context[templateName] as string;
    		if (string.IsNullOrEmpty(path))
    			return path;
    		var fullPath = HttpContext.Current.Server.MapPath(path);
    		return File.ReadAllText(fullPath);
    	}
    }
    

    设置DotLiquid使用自定义的文件系统

    public class MvcApplication : System.Web.HttpApplication
    {
    	protected void Application_Start()
    	{
    		// 在原有的代码下添加
    		Template.FileSystem = new DotliquidTemplateFileSystem();
    	}
    }
    

    再定义一个控制器基类

    public abstract class DotliquidController : Controller
    {
    	public ContentResult DotliquidView(string path = null, object parameters = null)
    	{
    		// 路径为空时根据当前的Action决定
    		if (string.IsNullOrEmpty(path))
    		{
    			var controller = RouteData.Values["controller"];
    			var action = RouteData.Values["action"];
    			path = $"~/DotliquidViews/{controller}/{action}.html";
    		}
    		// 根据路径读取模板内容
    		var templateStr = Template.FileSystem.ReadTemplateFile(new Context(), "'" + path + "'");
    		// 解析模板,这里可以缓存Parse出来的对象,但是为了简单这里就略去了
    		var template = Template.Parse(templateStr);
    		// 描画模板
    		Hash templateParameters;
    		if (parameters is IDictionary<string, object>)
    			templateParameters = Hash.FromDictionary((IDictionary<string, object>)parameters);
    		else
    			templateParameters = Hash.FromAnonymousObject(parameters ?? new { });
    		var result = template.Render(templateParameters);
    		// 返回描画出来的内容
    		return Content(result, "text/html");
    	}
    }
    

    现在可以在控制器中使用基于DotLiquid的模板了

    public ActionResult HelloTemplateFile()
    {
    	return DotliquidView();
    }
    

    上面会返回文件~/DotliquidViews/Home/HelloTemplateFile.html的内容

    Hello, Template!
    

    嵌入子模板

    为了实现代码的重用,DotLiquid的模板还可以嵌入其他子模板,嵌入需要使用include标签。
    以下例子会显示Hello, Include!

    public ActionResult HelloInclude()
    {
    	return DotliquidView();
    }
    

    文件~/DotliquidViews/Home/HelloInclude.html的内容

    Hello, {% include "~/DotliquidViews/Home/HelloIncludeContents.html" %}!
    

    文件~/DotliquidViews/Home/HelloIncludeContents.html的内容

    Include
    

    继承父模板

    除了嵌入子模版,还能实现布局(Layout)方式的继承父模板,继承需要使用extends和block标签。
    以下例子会返回Html<div class="layout"><h1>Here is title</h1><p>Here is body</p></div>

    public ActionResult HelloExtends()
    {
    	return DotliquidView();
    }
    

    文件~/DotliquidViews/Home/HelloExtendsLayout.html的内容

    <div class="layout">
    	<h1>
    		{% block title %}
    		Default title
    		{% endblock %}
    	</h1>
    	<p>
    		{% block body %}
    		Default body
    		{% endblock %}
    	</p>
    </div>
    

    文件~/DotliquidViews/Home/HelloExtends.html的内容

    {% extends "~/DotliquidViews/Home/HelloExtendLayout.html" %}
    
    {% block title %}
    Here is title
    {% endblock %}
    
    {% block body %}
    Here is body
    {% endblock %}
    

    描画自定义对象

    请先看以下的例子

    public class ExampleViewModel
    {
    	public string Name { get; set; }
    	public int Age { get; set; }
    }
    
    public ActionResult CustomObject()
    {
    	var template = Template.Parse("Name: {{ model.Name }}, Age: {{ model.Age }}");
    	var model = new ExampleViewModel() { Name = "john", Age = 35 };
    	var result = template.Render(Hash.FromAnonymousObject(new { model }));
    	return Content(result);
    }
    

    你可能预料这个例子会显示Name: john, Age: 35,但实际运行时会给出以下错误

    Name: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable, Age: Liquid syntax error: Object 'Dotliquid.Example.Dotliquid.ExampleViewModel' is invalid because it is neither a built-in type nor implements ILiquidizable
    

    这是因为DotLiquid为了安全性,默认不允许描画未经注册的对象,这样即使模板由前端使用者提供也不会导致信息泄露。
    为了解决上面的错误,需要把ExampleViewModel注册为可描画的对象。
    除了使用RegisterSafeType注册,你也可以让ExampleViewModel继承ILiquidizable,在部分场景下会更适合。

    public class MvcApplication : System.Web.HttpApplication
    {
    	protected void Application_Start()
    	{
    		// 在原有的代码下添加
    		Template.RegisterSafeType(typeof(ExampleViewModel), Hash.FromAnonymousObject);
    	}
    }
    

    写在最后

    DotLiquid是一个灵活性很高并且依赖很少的模板引擎,虽然没有Razor流行,但大量的单元测试保证它可以经得起实际的使用。
    目前使用了DotLiquid的项目有

    目前DotLiquid准备升级2.0版本,作者正在召集PR,如果你有意向可以到DotLiquid的github看看。

  • 相关阅读:
    Notepad++使用-如何导出/导入配置文件
    浏览器清除页面JS文件缓存的方法
    如何搭建一个简易的Web框架
    Visual Studio Code插件Code Runner中文乱码问题
    【笔记】做一个winform时遇到的坑
    【笔记】使用腾讯地图坐标转换
    使用js检测用户是否在用微信浏览器浏览网站
    phonegap+百度地图导航(JS版)
    浮躁的人
    【笔记】自动生成一个不重复的字符串
  • 原文地址:https://www.cnblogs.com/zkweb/p/5864794.html
Copyright © 2011-2022 走看看