OWL教程7 插槽

OWL教程7 插槽

1 概述

Owl是一个基于模板的组件系统。因此,需要能够制作通用组件。例如,想象一个通用的导航条组件,它显示一个导航条,但带有一些可定制的内容。因为特定的内容只有导航条的用户知道,所以最好在使用导航条的模板中指定它:

  <div>
    <Navbar>
      <span>Hello Owl</span>
    </Navbar>
  </div>

这正是插槽的工作方式!在上面的示例中,Navbar组件的用户指定了一些内容(在这里,在默认槽中)。Navbar组件可以在自己的模板中适当的位置插入该内容。需要注意的一个重要信息是,槽的内容是在父组件中渲染的,而不是在导航栏中。因此,它可以访问父组件的值和方法。

下面是导航栏组件的定义方式,使用t-slot指令,这是一个默认插槽:

<div class="navbar">
  <t t-slot="default"/>
  <ul>
    <!-- rest of the navbar here -->
  </ul>
</div>

2 命名插槽

默认插槽非常有用,但有时我们可能需要多个插槽。这就是命名插槽的作用!例如,假设我们实现了一个组件InfoBox,它显示标题和一些特定的内容。它的模板看起来像这样:

<div class="info-box">
  <div class="info-box-title">
    <t t-slot="title"/>
    <span class="info-box-close-button" t-on-click="close">X</span>
  </div>
  <div class="info-box-content">
    <t t-slot="content"/>
  </div>
</div>

可以将它与t-set-slot指令一起使用:

<InfoBox>
  <t t-set-slot="title">
    Specific Title. It could be html also.
  </t>
  <t t-set-slot="content">
    <!-- some template here, with html, events, whatever -->
  </t>
</InfoBox>

3 渲染上下文

槽的内容实际上是用与其定义位置相对应的渲染上下文渲染的,而不是与其定位位置相对应的渲染上下文。这允许用户定义事件处理程序,这些事件处理程序将绑定到正确的组件(通常是槽内容的祖父组件)。

4 默认插槽

组件中所有不是命名槽的元素都将被视为默认槽内容的一部分。例如:

<div t-name="Parent">
  <Child>
    <span>some content</span>
  </Child>
</div>

<div t-name="Child">
  <t t-slot="default"/>
</div>

可以混合使用默认槽位和命名槽位:

<div>
  <Child>
    default content
    <t t-set-slot="footer">
      content for footer slot here
    </t>
  </Child>
</div>

5 默认的上下文

插槽可以定义一个默认的内容,以防父节点没有定义它们:

<div t-name="Parent">
  <Child/>
</div>

<span t-name="Child">
  <t t-slot="default">default content</t>
</span>
<!-- will be rendered as: <div><span>default content</span></div> -->

6 动态插槽

t-slot指令实际上可以使用任何表达式,使用字符串插入:

 <t t-slot="{{current}}" />

这将计算当前表达式,并在t-slot指令的位置插入相应的slot。

7 插槽和props

在某种意义上,slot几乎与prop相同:它们定义了一些要传递给子组件的信息。为了能够使用它,并将其传递给子组件,Owl实际上真的定义了一个特殊的prop “slots”,其中包含给定给组件的所有插槽信息。它是这样的:

{ slotName_1: slotInfo_1, ..., slotName_m: slotInfo_m }

所以,一个组件可以像这样把它的槽传递给子组件:

<Child slots="props.slots"/>

fatux: 可以通过props 传递插槽的值, slot和props确实有相同之处,都是为了父组件给子组件传递信息. 只不过呢,一个传递个组件,一个传递给模板.

8 插槽参数

对于高级用例,可能需要将附加信息传递给插槽。这可以通过向t-set-slot指令提供额外的键/值对来实现。然后,通用组件可以在它的prop槽中读取它们。

例如,下面是如何实现Notebook组件(一个具有多个页面的组件和一个选项卡栏,它只呈现当前的活动页面,每个页面都有一个标题)。

class Notebook extends Component {
  static template = xml`
    <div class="notebook">
      <div class="tabs">
        <t t-foreach="tabNames" t-as="tab" t-key="tab_index">
          <span t-att-class="{active:tab_index === activeTab}" t-on-click="() => state.activeTab=tab_index">
            <t t-esc="props.slots[tab].title"/>
          </span>
        </t>
      </div>
      <div class="page">
        <t t-slot="{{currentSlot}}"/>
      </div>
    </div>`;

  setup() {
    this.state = useState({ activeTab: 0 });
    this.tabNames = Object.keys(this.props.slots);
  }

  get currentSlot() {
    return this.tabNames[this.state.activeTab];
  }
}

请注意如何读取每个槽的标题值。下面是如何使用这个Notebook组件:

<Notebook>
  <t t-set-slot="page1" title="'Page 1'">
    <div>this is in the page 1</div>
  </t>
  <t t-set-slot="page2" title="'Page 2'" hidden="somevalue">
    <div>this is in the page 2</div>
  </t>
</Notebook>

Slot参数的工作方式与普通的props类似,因此如果需要,可以使用.bind后缀来绑定函数。

9 插槽作用域

对于其他类型的高级用例,槽的内容可能依赖于特定于通用组件的一些信息。这与槽参数相反。

为了解决这类问题,可以使用t-slot-scope指令和t-set-slot指令。它定义了一个变量的名称,该变量可以访问子组件给出的所有内容:

<MyComponent>
    <t t-set-slot="foo" t-slot-scope="scope">
        content
        <t t-esc="scope.bool"/>
        <t t-esc="scope.num"/>
    </t>
</MyComponent>

包含slot的子组件可以提供这样的值:

<t t-slot="foo" bool="other_var" num="5">

或者这样

<t t-slot="foo" t-props="someObject">

在使用默认插槽的情况下,你可以直接在组件本身上声明插槽作用域:

<MyComponent t-slot-scope="scope">
    content
    <t t-esc="scope.bool"/>
    <t t-esc="scope.num"/>
</MyComponent>

Slot值的工作方式与普通的props类似,因此如果需要,可以使用.bind后缀来绑定函数。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值