第二章 图片预览
Odoo原生虽然支持附件的预览,但是并不支持表单中的图片预览,因此我们在开源模块的基础上制作了自己的图片预览模块mommy_image_preview。
模块的基本用法
该模块的用法如下,在图片字段的视图文件中,使用image_preview部件。
<field name="image_1920" widget="image_preview" options="{'size':[180,180]}">
options.size用来控制图片预览的默认大小。
模块原理
我们来看一下模块的原理。首先定义了一个部件的视图:
<templates id="template" xml:space="preserve">
<t t-name="mommy_image_preview.ImagePreviewField" t-inherit="web.ImageField" t-inherit-mode="primary" owl="1">
<xpath expr="//img[hasclass('img')]" position="attributes">
<attribute name="t-on-click">onClickImage</attribute>
</xpath>
</t>
</templates>
该视图继承自原生ImageField部件,在img元素上添加了一个click事件的监听。
export class ImagePreviewField extends ImageField {
static template = "mommy_image_preview.ImagePreviewField";
setup() {
super.setup();
this.fileViewer = useFileViewer();
}
onClickImage() {
if (!this.props.record.data[this.props.name]){
return;
}
const attachment = {defaultSource: this.lastURL, isViewable:true, isImage:true, displayName: ''}
if (isBinarySize(this.props.record.data[this.props.name])) {
attachment['downloadUrl'] = this.lastURL;
}
const attachments = [attachment];
this.fileViewer.open(attachment, attachments);
}
}
然后定了一个图片预览组件ImagePreviewField,该部件在setup方法里初始化了一个文件预览的钩子(此钩子为odoo原生代码)。
然后在click事件中,将图片的URL路径传入给fileViewer方法进行打开预览。
export const imagePreviewField = {
component: ImagePreviewField,
displayName: _t("Image"),
supportedOptions: [
{
label: _t("Reload"),
name: "reload",
type: "boolean",
default: true,
},
{
label: _t("Enable zoom"),
name: "zoom",
type: "boolean",
},
{
label: _t("Zoom delay"),
name: "zoom_delay",
type: "number",
help: _t("Delay the apparition of the zoomed image with a value in milliseconds"),
},
{
label: _t("Accepted file extensions"),
name: "accepted_file_extensions",
type: "string",
},
{
label: _t("Size"),
name: "size",
type: "selection",
choices: [
{ label: _t("Small"), value: "[0,90]" },
{ label: _t("Medium"), value: "[0,180]" },
{ label: _t("Large"), value: "[0,270]" },
],
},
{
label: _t("Preview image"),
name: "preview_image",
type: "field",
availableTypes: ["binary"],
},
],
supportedTypes: ["binary"],
fieldDependencies: [{ name: "write_date", type: "datetime" }],
isEmpty: () => false,
extractProps: ({ attrs, options }) => ({
enableZoom: options.zoom,
zoomDelay: options.zoom_delay,
previewImage: options.preview_image,
acceptedFileExtensions: options.accepted_file_extensions,
width: options.size && Boolean(options.size[0]) ? options.size[0] : attrs.width,
height: options.size && Boolean(options.size[1]) ? options.size[1] : attrs.height,
reload: "reload" in options ? Boolean(options.reload) : true,
}),
};
registry.category("fields").add("image_preview", imagePreviewField);
最后是定义了一个imagePreviewField字段,该字段使用ImagePreviewField组件。最后将此字段注册到字段中。
图片预览非钩子用法
在OWL环境中我们可以使用上述的方法进行调用。但是如果是在传统WC环境的中,由于钩子的初始化不能脱离setup方法,导致我们无法在传统的WC环境中使用(例如门户环境的publicWidget)。
解决这个问题的方法是我们不用钩子,而是自己实现预览方法:
const viewerId = `web.file_viewer${fileViewerId++}`
registry.category("main_components").add(viewerId, {
Component: FileViewer,
props: {
files: [{
isImage: true,
isViewable: true,
displayName: url,
defaultSource: url,
downloadUrl: url,
}],
startIndex: 0,
close: () => {
registry.category('main_components').remove(viewerId);
},
},
})
我们在图片的单击事件中,使用FileViewer组件,传入相应的文件参数和URL,即可完成图片的预览。