跳至内容

Odoo 19 前端:用 OWL 自定义 Service 做全局状态

Odoo用户手册·中文文档|OWL Service 注册、useState、示例代码与最佳实践全文
2026年3月4日
Odoo 19 前端:用 OWL 自定义 Service 做全局状态

在 Odoo Web Library(OWL)中做复杂前端时,常见难题是:用户在表单与看板之间切换后,组件销毁,局部 useState 无法跨动作保留状态。全局状态应通过 Service Registry + OWL reactive 来做。

对照:How to Build Custom Services with OWL in Odoo 19。下文保留步骤、示例与 FAQ,并用中文说明坑点。

一、核心概念:单例 Service

Odoo 的 Service 是 Web Client 初始化时创建的单例,通过 useService 向任意组件提供 orm、rpc、action、notification 等能力。

若自定义 Service 的 start 返回 OWL reactive 对象,它就类似全局 store:跨视图共享且可响应式更新。

二、步骤 1:创建响应式 Service

例如:全局用户偏好(侧边栏折叠、暗色主题)。文件示例路径 static/src/js/user_preference_service.js

/** @odoo-module **/
import { registry } from "@web/core/registry";
import { reactive } from "@odoo/owl";

export const userPreferenceService = {
    dependencies: [],
    start(env) {
        const state = reactive({
            sidebarCollapsed: false,
            darkMode: false,
            toggleSidebar() {
                this.sidebarCollapsed = !this.sidebarCollapsed;
            },
            toggleDarkMode() {
                this.darkMode = !this.darkMode;
                this._applyTheme();
            },
            _applyTheme() {
                const body = document.body;
                if (this.darkMode) body.classList.add("dark-theme");
                else body.classList.remove("dark-theme");
            },
        });
        return state;
    },
};
registry.category("services").add("user_preference", userPreferenceService);

三、步骤 2:在清单中注册资源

在模块 __manifest__.pyweb.assets_backend 中加入 JS(及需要的 XML):

'assets': {
    'web.assets_backend': [
        'my_module/static/src/js/user_preference_service.js',
        'my_module/static/src/js/settings_toggle.js',
        'my_module/static/src/js/sidebar_component.js',
    ],
},

四、步骤 3:用 OWL Hooks 消费与变更状态

useService 不够——必须再包一层 useState,组件才会在状态变化时重渲染。

组件 A(触发变更):

this.preferences = useState(useService("user_preference"));
// 点击时调用 this.preferences.toggleDarkMode();

组件 B(消费状态):同样 useState(useService(...)),侧边栏 class 绑定 sidebarCollapsed / darkMode。A 变更时 B 自动更新。

五、最佳实践与坑

  • 永远配合 useState:否则初始有值,后续不刷新。
  • 服务要聚焦:不要一个 GlobalState 塞下全部业务;按域拆分(cart、preference、sync…)。
  • 勿在组件里直接改属性:通过 Service 内方法变更,便于维护与调试。

OWL reactive + Odoo Service Registry,可用很轻量的方式做全局状态,无需引入大型外部状态库。

六、FAQ

能在标准看板/表单里用吗?可以。扩展标准控制器/视图后,同样可挂接 reactive service,与自定义侧栏/顶栏同步。

和 OWL Context 有何不同?Context 沿组件树向下传,旁系组件难共享;Service 是全局单例,适合兄弟或完全分离的 UI。

会不会更耗内存?单例只有一份状态。注意不要在监听器里长期持有大对象,以免妨碍组件卸载。

中国Odoo网原创中文改写|保留 Service/useState/示例/FAQ。Odoo用户手册 · 中文文档 · 开发实操。

Odoo 19 前端:用 OWL 自定义 Service 做全局状态
2026年3月4日
存档