OWL教程4 OWL五大组成部分之三模板编译器

OWL教程4 OWL五大组成部分之三模板编译器

参考文档:https://github.com/odoo/owl/blob/master/doc/miscellaneous/compiled_template.md

粗略的讲,Owl有五个主要部分:

  1. 虚拟DOM系统(src/blockdom)
  2. 组件系统(src/component)
  3. 模板编译器(src/compiler 目录)
  4. 一个小的运行时让各层组合在一起(src/app)
  5. 响应式系统(src/reactivity.ts)

三 关于Owl编译模板的说明

本页将解释Owl编译的模板是什么样子的。这是一份技术文档,面向有兴趣了解Owl内部工作原理的开发人员。

一般来说,Owl将模板编译成一个javascript函数(闭包),该函数返回一个函数(“render”函数)。闭包的目的是有一个地方存储模板特定的所有值(特别是“块”)。一旦模板被编译,它的闭包函数被调用一次以获得渲染函数,从那时起,只使用渲染函数。

渲染函数接受一些上下文(和一些附加信息),并以块树的形式返回渲染模板的虚拟dom表示。块树是一种非常轻量级的表示,它只包含模板的动态部分及其结构。它实际上独立于模板的静态部分(包含在闭包捕获的块中)。这意味着在渲染时执行的工作只是收集动态数据,并描述结果的块结构。

它看起来像这样,在伪代码中:

function closure(bdom, helpers) {
    // here is some place to put stuff specific to the template, such as
    // blocks
    ...

    return function render(context, node, key) {
        // only build here all dynamic parts of the template
        // build a block tree
        return tree;
    }
}

现在,让我们看一个例子。考虑以下模板:

<div class="some-class">
    <div class="blabla">
        <span><t t-esc="state.value"/></span>
    </div>
    <t t-if="state.info">
        <p class="info" t-att-class="someAttribute">
            <t t-esc="state.info"/>
        </p>
    </t>
    <SomeComponent value="value"/>
</div>

如果你仔细观察,有5个动态的东西:

  • a text value (the first t-esc),
  • a sub block (the t-if),
  • a dynamic attribute (the t-att-class attribute),
  • another text value (the second t-esc),
  • and finally, a sub component

下面是这个模板的编译代码:

function closure(bdom, helpers) {
  let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;

  let block1 = createBlock(
    `<div class="some-class"><div class="blabla"><span><block-text-0/></span></div><block-child-0/><block-child-1/></div>`
  );
  let block2 = createBlock(`<p class="info" block-attribute-0="class"><block-text-1/></p>`);

  return function render(ctx, node, key = "") {
    let b2, b3;
    let txt1 = ctx["state"].value;
    if (ctx["state"].info) {
      let attr1 = ctx["someAttribute"];
      let txt2 = ctx["state"].info;
      b2 = block2([attr1, txt2]);
    }
    b3 = component(`SomeComponent`, { value: ctx["value"] }, key + `__1`, node, ctx);
    return block1([txt1], [b2, b3]);
  };
}

闭包中捕获的值捕获模板的静态部分:我们在这里定义了两个块(其中包含一个模板节点,可以在挂载块时进行深度克隆)。然后,渲染函数仅根据上下文描述结果的块树结构。这意味着我们将在渲染时完成的工作量最小化。

然后,当我们想要patch dom时,Owl将使用来自blockdom的patch函数,该函数将对块树进行diff,并在插入新块时深度克隆新块,跟踪每个块的动态部分,并相应地更新它们。

在这种设计中,渲染模板的成本与动态值的数量成正比,而与模板的大小无关。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值