Skip to content

🦉 Owl Component 🦉

概述

Owl 组件是一个小的类,代表用户界面中的某一部分。 它是组件树的一部分,并拥有一个从父组件向子组件传递的 环境 (env)。

Owl 组件通过继承 Component 类来定义。例如,下面是一个 Counter 组件的实现方式:

javascript
const { Component, xml, useState } = owl;

class Counter extends Component {
  static template = xml`
    <button t-on-click="increment">
      Click Me! [<t t-esc="state.value"/>]
    </button>`;

  state = useState({ value: 0 });

  increment() {
    this.state.value++;
  }
}

在这个例子中,我们使用 xml 辅助函数定义内联模板,使用 useState 钩子来创建响应式状态(详见响应式一节)。


属性和方法

Component 类的 API 非常小巧:

  • env (object):组件的 环境

  • props (object):由父组件传递给子组件的 props 对象。

    注意:props 是由父组件拥有的,不属于子组件。因此绝对不能在子组件中修改 props,否则可能造成未预期的副作用(因为父组件不会意识到这种变化)。

    当父组件动态修改 props 时,子组件将会依次触发生命周期方法:willUpdatePropswillPatchpatched

  • render(deep[=false]):手动调用此方法将触发重新渲染。 由于使用了响应式系统,通常不需要手动调用该方法。 渲染是异步的,DOM 的更新会稍后(通常在下一帧)发生。

    默认情况下,只有当子组件的 props(浅层比较)变化时,才会渲染子组件。 如需强制子组件全部渲染,可使用布尔值 true 作为 deep 参数。


静态属性

  • template (string):组件的模板字符串。可使用 xml 辅助函数方便地定义内联模板。

  • components (object, optional):如果组件包含子组件,可通过该对象注册子组件类:

    js
    class ParentComponent extends owl.Component {
      static components = { SubComponent };
    }
  • props (object, optional):用于描述接收到的 props 的类型与结构。在 dev 模式下将进行 props 校验。详见 props 验证

    js
    class Counter extends owl.Component {
      static props = {
        initialValue: Number,
        optional: true,
      };
    }
  • defaultProps (object, optional):用于定义 props 的默认值。如果某个 props 未传递,则使用该默认值。注意默认值不会修改原始 props 对象,而是生成一个新对象。详见 默认 props

    js
    class Counter extends owl.Component {
      static defaultProps = {
        initialValue: 0,
      };
    }

生命周期

一个健壮的组件系统需要完善的生命周期机制,Owl 提供了如下生命周期方法:

方法钩子函数说明
setup组件构造后立即执行。
willStartonWillStart异步钩子,首次渲染前调用,可用于初始化异步数据。
willRenderonWillRender模板渲染前调用。
renderedonRendered模板渲染后调用(DOM 尚未更新)。
mountedonMounted渲染并添加到 DOM 后调用。
willUpdatePropsonWillUpdateProps异步钩子,更新 props 之前调用。
willPatchonWillPatchDOM 更新前调用,适合读取当前 DOM 状态。
patchedonPatchedDOM 更新后调用,适合执行额外 DOM 操作。
willUnmountonWillUnmount组件即将从 DOM 移除时调用。
willDestroyonWillDestroy组件销毁前调用,始终会执行。
onErroronError捕捉并处理子组件错误。详见 错误处理

以下是各生命周期方法的简要说明与示例(略去重复代码):

setup

初始化逻辑、注册钩子的地方。相当于构造函数。

js
setup() {
  useSetupAutofocus();
}

willStart

异步初始化,适合加载远程数据、外部库等。首次渲染前只调用一次。

js
setup() {
  onWillStart(async () => {
    this.data = await this.loadData();
  });
}

willRender

在模板函数执行前调用。

js
setup() {
  onWillRender(() => {
    // 执行一些逻辑
  });
}

rendered

模板渲染后调用,但此时 DOM 尚未更新。

js
setup() {
  onRendered(() => {
    // 模板渲染完毕
  });
}

mounted

组件已插入 DOM。适合操作 DOM、添加事件监听等。

js
setup() {
  onMounted(() => {
    // 执行一些 DOM 相关逻辑
  });
}

willUpdateProps

异步钩子,props 更新前调用。适合根据新 props 执行任务(如获取数据)。

js
setup() {
  onWillUpdateProps(nextProps => {
    return this.loadData({ id: nextProps.id });
  });
}

willPatch

DOM 更新前调用,适合读取当前 DOM 状态。

js
setup() {
  onWillPatch(() => {
    this.scrollState = this.getScrollState();
  });
}

patched

DOM 更新后调用。可执行额外 DOM 操作或触发动画。

js
setup() {
  onPatched(() => {
    this.scrollState = this.getScrollState();
  });
}

willUnmount

组件即将从 DOM 中移除时调用。适合移除事件监听。

js
setup() {
  onMounted(() => { /* 添加监听 */ });
  onWillUnmount(() => { /* 移除监听 */ });
}

willDestroy

组件销毁前调用。即使未挂载也会调用,适合做彻底清理。

js
setup() {
  onWillDestroy(() => {
    // 清理逻辑
  });
}

onError

用于捕捉子组件错误,执行恢复逻辑。

js
setup() {
  onError(() => {
    // 错误处理
  });
}

子组件

组件可组合子组件构建复杂 UI。在模板中使用以大写字母开头的标签表示子组件,并通过 components 静态属性注册。

js
class Child extends Component {
  static template = xml`<div>child component <t t-esc="props.value"/></div>`;
}

class Parent extends Component {
  static template = xml`
    <div>
      <Child value="1"/>
      <Child value="2"/>
    </div>`;

  static components = { Child };
}

动态子组件

使用 t-component 指令实现动态选择子组件:

js
class A extends Component {
  static template = xml`<div>child a</div>`;
}
class B extends Component {
  static template = xml`<span>child b</span>`;
}
class Parent extends Component {
  static template = xml`<t t-component="myComponent"/>`;

  state = useState({ child: "a" });

  get myComponent() {
    return this.state.child === "a" ? A : B;
  }
}

status 辅助函数

用于判断组件当前状态:

js
const { status } = owl;

console.log(status(component));
// 返回值可能是:
// - 'new':尚未挂载
// - 'mounted':已挂载
// - 'cancelled':即将被销毁但尚未挂载
// - 'destroyed':已销毁

本站内容仅供学习与参考