ODOO一直以来有一个不成文的习惯,就是好多好用的组件代码中写了,但是没有公开出来,官方文档上根本没有相关的介绍,所以这个时候就需要我们自己去发掘,今天就是Dropzone为例,这个组件是用于拖拉上传文件等,在Odoo中,导入处实际上进行了使用,dropzone代码如下
import { Dropzone } from "@web/core/dropzone/dropzone";
import { useEffect, useExternalListener } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
/**
* @param {Ref} targetRef - Element on which to place the dropzone.
* @param {Class} dropzoneComponent - Class used to instantiate the dropzone component.
* @param {Object} dropzoneComponentProps - Props given to the instantiated dropzone component.
* @param {function} isDropzoneEnabled - Function that determines whether the dropzone should be enabled.
*/
export function useCustomDropzone(targetRef, dropzoneComponent, dropzoneComponentProps, isDropzoneEnabled = () => true) {
const overlayService = useService("overlay");
const uiService = useService("ui");
let dragCount = 0;
let hasTarget = false;
let removeDropzone = false;
useExternalListener(document, "dragenter", onDragEnter, { capture: true });
useExternalListener(document, "dragleave", onDragLeave, { capture: true });
// Prevents the browser to open or download the file when it is dropped
// outside of the dropzone.
useExternalListener(window, "dragover", (ev) => {
if (ev.dataTransfer && ev.dataTransfer.types.includes("Files")) {
ev.preventDefault();
}
});
useExternalListener(
window,
"drop",
(ev) => {
if (ev.dataTransfer && ev.dataTransfer.types.includes("Files")) {
ev.preventDefault();
}
dragCount = 0;
updateDropzone();
},
{ capture: true }
);
function updateDropzone() {
const hasDropzone = !!removeDropzone;
const isTargetInActiveElement = uiService.activeElement.contains(targetRef.el);
const shouldDisplayDropzone = dragCount && hasTarget && isTargetInActiveElement && isDropzoneEnabled();
if (shouldDisplayDropzone && !hasDropzone) {
removeDropzone = overlayService.add(dropzoneComponent, {
ref: targetRef,
...dropzoneComponentProps
});
}
if (!shouldDisplayDropzone && hasDropzone) {
removeDropzone();
removeDropzone = false;
}
}
function onDragEnter(ev) {
if (dragCount || (ev.dataTransfer && ev.dataTransfer.types.includes("Files"))) {
dragCount++;
updateDropzone();
}
}
function onDragLeave() {
if (dragCount) {
dragCount--;
updateDropzone();
}
}
useEffect(
(el) => {
hasTarget = !!el;
updateDropzone();
},
() => [targetRef.el]
);
}
/**
* @param {Ref} targetRef - Element on which to place the dropzone.
* @param {function} onDrop - Callback function called when the user drops a file on the dropzone.
* @param {string} extraClass - Classes that will be added to the standard `Dropzone` component.
* @param {function} isDropzoneEnabled - Function that determines whether the dropzone should be enabled.
*/
export function useDropzone(targetRef, onDrop, extraClass, isDropzoneEnabled = () => true) {
const dropzoneComponent = Dropzone;
const dropzoneComponentProps = { extraClass, onDrop };
useCustomDropzone(targetRef, dropzoneComponent, dropzoneComponentProps, isDropzoneEnabled);
}
代码不复杂,主要是监听了相关的事件处理,不过再简单的代码,要做稳定实际上也要花时间,相对来讲,odoo的代码还是比较稳定和考虑全面的,所以最好是把自带的用起来,使用代码如下
import { useDropzone } from "@web/core/dropzone/dropzone_hook";
this.uploadFiles = useFileUploader();
useDropzone(useRef("root"), async event => {
const { files } = event.dataTransfer;
if (files.length === 0) {
this.notification.add(_t("Please upload an Excel (.xls or .xlsx) or .csv file to import."), {
type: "danger",
});
} else if (files.length > 1) {
this.notification.add(_t("Please upload a single file."), {
type: "danger",
});
} else {
const file = files[0];
const isValidFile = file.name.endsWith(".csv")
|| file.name.endsWith(".xls")
|| file.name.endsWith(".xlsx");
if (!isValidFile) {
this.notification.add(_t("Please upload an Excel (.xls or .xlsx) or .csv file to import."), {
type: "danger",
});
} else {
await this.uploadFiles(this.uploadFilesRoute, {
csrf_token: odoo.csrf_token,
ufile: [file],
model: this.resModel,
id: this.model.id,
});
this.handleFilesUpload([file]);
}
}
});