在 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__.py 的 web.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用户手册 · 中文文档 · 开发实操。