第五章 小部件(Widgets)
篇别:第一篇 基础知识
本章学习目标
- 能根据 字段类型与业务场景 为视图字段选择合适的
widget。 - 理解 widget 与底层字段类型 的约束关系,避免「有 widget 无数据」类问题。
- 了解 OWL 字段组件 的注册方式,并能指向第三十二章做深入实现。
- 能排查 widget 不生效(资产未加载、注册名拼写、字段类型不匹配)的常见原因。
导读:小部件解决什么问题
在 XML 视图中,同一字段类型往往有多种呈现方式:例如金额既可 plain text 显示,也可用 monetary 做币种对齐与小数格式;状态字段可用下拉框,也可用 statusbar 强化流程感。widget 属性告诉 WebClient:在 fields 注册表中选用哪一个 字段组件 来渲染该字段。
Odoo 19 中,这些组件绝大多数已是 OWL 实现;自定义扩展应优先 注册 OWL 字段组件,而不是沿用已废弃的 legacy Widget 体系。
5.1 常用字段小部件
5.1.1 知识要点
widget写在<field>上,仅影响 表现层;不改变数据库类型或 ORM 行为。- 可用 widget 集合由
web及已安装模块 在前端注册表registry.category("fields")中决定;拼写错误时通常 静默回退 到默认组件,排查时易忽略。 - 部分 widget 依赖同视图内其他字段(如
monetary依赖币种字段),缺字段会导致显示异常或报错。
5.1.2 字段类型与 widget 对照(常用)
| 字段类型 | 常用 widget | 说明 |
|---|---|---|
Selection |
statusbar、radio、priority、badge |
statusbar 常配合 statusbar_visible |
Many2many |
many2many_tags、many2many_checkboxes |
标签可配合 comodel 的 color 字段(若支持) |
Monetary |
monetary |
需 currency_field 对应字段出现在视图中(或默认可解析) |
Float |
percentage、float_time、progressbar |
percentage 多用于 0–1 或 0–100 约定(与模块一致) |
Integer |
handle |
列表拖拽排序,常配合 sequence |
Binary |
image、pdf_viewer(视版本) |
图片预览注意体积与权限 |
Char |
url、email、phone |
可点击跳转或唤起客户端 |
Text / Html |
html(富文本) |
注意 XSS 与消毒策略 |
上表为经验归纳,以当前版本注册表为准。
5.1.3 案例
案例 A:流程状态条
<header>
<field name="state" widget="statusbar"
statusbar_visible="draft,sent,sale,done"
options="{'clickable': '1'}"/>
</header>
statusbar_visible 限制 可见的选项(其余状态仍可能存在,只是条上不显示);clickable 是否允许点击切换依版本与字段是否只读而定。
案例 B:列表拖拽排序
<list default_order="sequence,name">
<field name="sequence" widget="handle"/>
<field name="name"/>
</list>
案例 C:金额与币种同屏
<group>
<field name="currency_id" invisible="1"/>
<field name="amount" widget="monetary" options="{'currency_field': 'currency_id'}"/>
</group>
若 currency_id 对当前用户不可见但仍需参与计算,可用 invisible="1" 保留字段在视图中(注意与权限、业务暴露的平衡)。
案例 D:Many2many 标签 + 颜色(若关联模型有 color)
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
案例 E:布尔或状态的高亮
<field name="active" widget="boolean_toggle"/>
5.1.4 截图占位


5.1.5 本节练习
- 实操:为某
Selection字段配置statusbar,并故意写错widget="statusbarr",观察界面表现与控制台(若有)报错。 - 简答:
monetary为何通常要求币种字段同视图可解析? - 判断:
widget可以替代字段上的groups做敏感数据保护。( )
参考答案提示:2. 格式化与币种符号依赖 res.currency。3. 错,须 ACL/字段权限等后端策略。
5.2 小部件与视图修饰的配合
5.2.1 知识要点
options:JSON 字符串,向字段组件传参(不同 widget 键名不同)。readonly/required/invisible:可与 widget 同用;注意 attrs 旧写法 在老模块中仍存在。- 列表装饰:
decoration-danger="state=='cancel'"等,与 widget 独立,用于行样式。
5.2.2 案例
<list decoration-muted="state=='draft'" decoration-success="state=='done'">
<field name="name"/>
<field name="amount" widget="monetary" sum="Total"/>
</list>
5.2.3 本节练习
- 实操:为列表金额列加
sum属性,观察底部合计行。 - 简答:
sum是 ORM 聚合还是纯前端累加?
参考答案提示:2. 一般为当前列表已加载行的前端合计(大数据量分页时不等于全表)。
5.3 OWL 组件化小部件(新增)
5.3.1 知识要点
新开发推荐三步:
- 编写 OWL 字段组件类(实现与
record.props/standardFieldProps等契约,以@web字段组件为准)。 registry.category("fields").add("my_widget", 组件类或描述对象)。- 视图中
<field widget="my_widget"/>。
旧 AbstractField / legacy widget 应计划迁移;迁移检查:props、更新值、子键 additionalClasses、移动端。
5.3.2 案例:自定义 widget 的「骨架」(与第三十二章对照)
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Component } from "@odoo/owl";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
export class CounterField extends Component {
static template = "my_module.CounterField";
static props = { ...standardFieldProps };
}
registry.category("fields").add("counter", CounterField);
<!-- QWeb 模板 my_module.CounterField:展示 props.record.data[name] 与增减按钮,更新用 props.record.update({...}) -->
完整 update、只读态、对比 CharField 源码等见 第三十二章。
5.3.3 截图占位


5.3.4 本节练习
- 简答:OWL 字段组件相对 legacy 的三点优势(测试、类型、打包)。
- 拓展:在源码中打开
@web/views/fields/char/char_field.js,记录其static props与模板名。 - 实操:在本模块
assets中注册一段 JS 后升级模块,确认 Network 中出现对应 chunk。
5.4 故障排查清单
| 现象 | 可能原因 |
|---|---|
| widget 无变化 | 拼写错误、未升级模块、资产缓存、该字段类型不支持 |
| monetary 显示异常 | 缺 currency_id、币种为空、权限看不到币种字段 |
| handle 无法拖拽 | 未 default_order 含 sequence、列表不可编辑、无写权限 |
| 自定义 widget 不加载 | manifest assets 路径错误、未 -u 模块、注册名与 XML 不一致 |
5.4.1 截图占位

5.4.2 本节练习
- 实操:用无痕窗口 + 硬刷新验证 widget 相关 JS 是否更新。
- 简答:生产环境修改静态资源后为何要关注 CDN/浏览器缓存?
本章综合练习
- 为
library.book设计表单:state用 statusbar,cover用image,列表用handle排序。 - 为
Many2many标签在 comodel 增加color(Integer),并配置color_field。 - 列出你项目中 1 处 legacy widget,并写出替换为 OWL 的检查项(不少于 5 条)。
- 情景题:财务要求「列表合计必须等于全表」时,为何不能只依赖
sum属性?应配合什么(报表/read_group/SQL)?
本章对应白皮书目录:第五章 小部件。