init
This commit is contained in:
9
src/component/upload/cropper.min.css
vendored
Normal file
9
src/component/upload/cropper.min.css
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Cropper.js v1.5.12
|
||||
* https://fengyuanchen.github.io/cropperjs
|
||||
*
|
||||
* Copyright 2015-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2021-06-12T08:00:11.623Z
|
||||
*/.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{image-orientation:0deg;display:block;height:100%;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline:1px solid #39f;outline-color:rgba(51,153,255,.75);overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed}
|
||||
110
src/component/upload/index.less
Normal file
110
src/component/upload/index.less
Normal file
@@ -0,0 +1,110 @@
|
||||
@import "./cropper.min.css";
|
||||
@import "../button/index.less";
|
||||
|
||||
.layui-upload-file {
|
||||
opacity: 0.01;
|
||||
position: relative;
|
||||
filter: Alpha(opacity=1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layui-upload-btn-box {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layui-upload-drag,
|
||||
.layui-upload-form,
|
||||
.layui-upload-wrap {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.layui-upload-list {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.layui-upload-choose {
|
||||
max-width: 200px;
|
||||
padding: 0 10px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.layui-upload-drag {
|
||||
position: relative;
|
||||
padding: 30px;
|
||||
border: 1px dashed var(--global-neutral-color-4);
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.layui-upload-drag .layui-icon {
|
||||
font-size: 50px;
|
||||
color: var(--global-primary-color);
|
||||
}
|
||||
|
||||
.layui-upload-drag[lay-over] {
|
||||
border-color: var(--global-primary-color);
|
||||
}
|
||||
.layui-upload-drag-draging {
|
||||
border-color: var(--global-primary-color);
|
||||
}
|
||||
|
||||
.layui-upload-iframe {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.layui-upload-wrap {
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layui-upload-wrap .layui-upload-file {
|
||||
display: block !important;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
font-size: 100px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
opacity: 0.01;
|
||||
filter: Alpha(opacity=1);
|
||||
}
|
||||
|
||||
.layui-upload-file-disabled {
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
|
||||
.layui-btn-container .layui-upload-choose {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.layui-upload-drag-disable {
|
||||
opacity: 0.8;
|
||||
z-index: 1;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
._lay_upload_img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.layui-upload-list-disabled {
|
||||
width: auto;
|
||||
height: auto;
|
||||
pointer-events: none !important;
|
||||
background-color: #fbfbfb !important;
|
||||
filter: opacity(0.9);
|
||||
}
|
||||
5
src/component/upload/index.ts
Normal file
5
src/component/upload/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { withInstall, WithInstallType } from "../../utils";
|
||||
import Component from "./index.vue";
|
||||
|
||||
const component: WithInstallType<typeof Component> = withInstall(Component);
|
||||
export default component;
|
||||
487
src/component/upload/index.vue
Normal file
487
src/component/upload/index.vue
Normal file
@@ -0,0 +1,487 @@
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "LayUpload",
|
||||
};
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import "./index.less";
|
||||
import { Recordable } from "../../types";
|
||||
import { layer } from "@layui/layer-vue";
|
||||
import {
|
||||
computed,
|
||||
ComputedRef,
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
ref,
|
||||
useSlots,
|
||||
withDefaults,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { templateRef } from "@vueuse/core";
|
||||
import { LayLayer } from "@layui/layer-vue";
|
||||
import LayButton from "../button/index.vue";
|
||||
import Cropper from "cropperjs";
|
||||
import { useI18n } from "../../language";
|
||||
|
||||
export interface LayerButton {
|
||||
text: string;
|
||||
callback: Function;
|
||||
}
|
||||
|
||||
export interface LayerModal {
|
||||
title?: string;
|
||||
resize?: boolean;
|
||||
move?: boolean;
|
||||
maxmin?: boolean;
|
||||
offset?: string[];
|
||||
content?: string;
|
||||
shade?: boolean;
|
||||
shadeClose?: boolean;
|
||||
shadeOpacity?: number;
|
||||
zIndex?: number;
|
||||
type?: "component" | "iframe";
|
||||
closeBtn?: boolean;
|
||||
area: string[];
|
||||
btn?: LayerButton[];
|
||||
btnAlign?: "l" | "r" | "c";
|
||||
anim?: boolean;
|
||||
isOutAnim?: boolean;
|
||||
}
|
||||
|
||||
export interface CutOptions {
|
||||
layerOption: LayerModal;
|
||||
copperOption?: typeof Cropper;
|
||||
}
|
||||
|
||||
export interface UploadProps {
|
||||
url?: string;
|
||||
data?: any;
|
||||
headers?: Recordable;
|
||||
acceptMime?: string;
|
||||
field?: string;
|
||||
size?: number;
|
||||
multiple?: boolean;
|
||||
number?: number;
|
||||
drag?: boolean;
|
||||
disabled?: boolean;
|
||||
disabledPreview?: boolean;
|
||||
cut?: boolean;
|
||||
cutOptions?: CutOptions;
|
||||
text?: string;
|
||||
dragText?: string;
|
||||
modelValue?: any;
|
||||
auto?: boolean;
|
||||
}
|
||||
|
||||
const getCutDownResult = () => {
|
||||
if (_cropper) {
|
||||
const canvas = _cropper.getCroppedCanvas();
|
||||
let imgData = canvas.toDataURL('"image/png"');
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
let orgInfo = activeUploadFiles.value[0];
|
||||
emit(
|
||||
"cutdone",
|
||||
Object.assign({ currentTimeStamp, cutResult: imgData, orginal: orgInfo })
|
||||
);
|
||||
let newFile = dataURLtoFile(imgData);
|
||||
if (!props.auto) {
|
||||
emit("update:modelValue", [newFile]);
|
||||
clearLightCutEffect();
|
||||
return;
|
||||
}
|
||||
commonUploadTransaction([newFile]);
|
||||
nextTick(() => clearAllCutEffect());
|
||||
} else {
|
||||
errorF(cutInitErrorMsg.value);
|
||||
}
|
||||
};
|
||||
|
||||
const closeCutDownModal = () => {
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
emit("cutcancel", Object.assign({ currentTimeStamp }));
|
||||
nextTick(() => clearAllCutEffect());
|
||||
};
|
||||
|
||||
const clearAllCutEffect = () => {
|
||||
activeUploadFiles.value = [];
|
||||
activeUploadFilesImgs.value = [];
|
||||
innerCutVisible.value = false;
|
||||
(orgFileInput.value as HTMLInputElement).value = "";
|
||||
_cropper = null;
|
||||
};
|
||||
|
||||
const clearLightCutEffect = () => {
|
||||
activeUploadFiles.value = [];
|
||||
activeUploadFilesImgs.value = [];
|
||||
innerCutVisible.value = false;
|
||||
_cropper = null;
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
const text = computed(() => {
|
||||
return props.text ? props.text : t("upload.text");
|
||||
});
|
||||
const dragText = computed(() => {
|
||||
return props.dragText ? props.dragText : t("upload.dragText");
|
||||
});
|
||||
const defaultErrorMsg = computed(() => t("upload.defaultErrorMsg"));
|
||||
const urlErrorMsg = computed(() => t("upload.urlErrorMsg"));
|
||||
const numberErrorMsg = computed(() => t("upload.numberErrorMsg"));
|
||||
const occurFileSizeErrorMsg = computed(() => t("upload.occurFileSizeErrorMsg"));
|
||||
const cutInitErrorMsg = computed(() => t("upload.cutInitErrorMsg"));
|
||||
const uploadSuccess = computed(() => t("upload.uploadSuccess"));
|
||||
const startUploadMsg = computed(() => t("upload.startUploadMsg"));
|
||||
const cannotSupportCutMsg = computed(() => t("upload.cannotSupportCutMsg"));
|
||||
const title = computed(() => t("upload.title"));
|
||||
const confirmBtn = computed(() => t("upload.confirmBtn"));
|
||||
const cancelBtn = computed(() => t("upload.cancelBtn"));
|
||||
|
||||
let defaultCutLayerOption = computed<LayerModal>(() => {
|
||||
return {
|
||||
type: "component",
|
||||
title: title.value,
|
||||
shade: true,
|
||||
shadeClose: true,
|
||||
area: ["640px", "640px"],
|
||||
btn: [
|
||||
{ text: confirmBtn.value, callback: getCutDownResult },
|
||||
{ text: cancelBtn.value, callback: closeCutDownModal },
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<UploadProps>(), {
|
||||
field: "file",
|
||||
acceptMime: "MIME_type",
|
||||
size: 0,
|
||||
multiple: false,
|
||||
number: 0,
|
||||
drag: false,
|
||||
disabled: false,
|
||||
disabledPreview: false,
|
||||
cut: false,
|
||||
cutOptions: void 0,
|
||||
modelValue: null,
|
||||
auto: true,
|
||||
});
|
||||
|
||||
const slot = useSlots();
|
||||
const slots = slot.default && slot.default();
|
||||
const context = getCurrentInstance();
|
||||
const emit = defineEmits([
|
||||
"choose",
|
||||
"before",
|
||||
"done",
|
||||
"error",
|
||||
"cutdone",
|
||||
"cutcancel",
|
||||
"update:modelValue",
|
||||
]);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => {
|
||||
if (!props.modelValue) {
|
||||
clearAllCutEffect();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const isDragEnter = ref(false);
|
||||
const activeUploadFiles = ref<any[]>([]);
|
||||
const activeUploadFilesImgs = ref<any[]>([]);
|
||||
const orgFileInput = templateRef<HTMLElement>("orgFileInput");
|
||||
let _cropper: any = null;
|
||||
|
||||
let computedCutLayerOption: ComputedRef<LayerModal>;
|
||||
|
||||
if (props.cutOptions && props.cutOptions.layerOption) {
|
||||
computedCutLayerOption = computed(() =>
|
||||
Object.assign(defaultCutLayerOption, props.cutOptions.layerOption)
|
||||
);
|
||||
} else {
|
||||
computedCutLayerOption = computed(() => defaultCutLayerOption.value);
|
||||
}
|
||||
|
||||
interface localUploadTransaction {
|
||||
url: string;
|
||||
files: File[] | Blob[];
|
||||
[propMame: string]: any;
|
||||
}
|
||||
|
||||
interface localUploadOption {
|
||||
url: string;
|
||||
[propMame: string]: any;
|
||||
}
|
||||
|
||||
const innerCutVisible = ref<boolean>(false);
|
||||
|
||||
const localUploadTransaction = (option: localUploadTransaction) => {
|
||||
const { url, files } = option;
|
||||
let formData = new FormData();
|
||||
if (url.length <= 5) {
|
||||
errorF(urlErrorMsg.value);
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(files) && files.length > 0) {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
let _file = files[i];
|
||||
formData.append(props.field + "[" + i + "]", _file);
|
||||
}
|
||||
}
|
||||
if (props.data && props.data instanceof Object) {
|
||||
let _requestDate = props.data;
|
||||
for (const key in _requestDate) {
|
||||
formData.append(key, _requestDate[key]);
|
||||
}
|
||||
}
|
||||
let utimer = window.setTimeout(() => {
|
||||
localUpload({ url, formData }, function () {
|
||||
clearTimeout(utimer);
|
||||
});
|
||||
}, 200);
|
||||
};
|
||||
|
||||
const dataURLtoFile = (dataurl: string) => {
|
||||
let arr: any[] = dataurl.split(",");
|
||||
let mime = "";
|
||||
if (arr.length > 0) {
|
||||
mime = arr[0].match(/:(.*?);/)[1];
|
||||
}
|
||||
let bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
let u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return new Blob([u8arr], { type: mime });
|
||||
};
|
||||
|
||||
const errorF = (errorText: string) => {
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
let errorMsg = errorText ? errorText : defaultErrorMsg;
|
||||
errorMsg = `layui-vue:${errorMsg}`;
|
||||
console.warn(errorMsg);
|
||||
layer.msg(errorMsg, { icon: 2, time: 1000 }, function (res: unknown) { });
|
||||
emit("error", Object.assign({ currentTimeStamp, msg: errorMsg }));
|
||||
};
|
||||
|
||||
const localUpload = (option: localUploadOption, callback: Function) => {
|
||||
let xhr: XMLHttpRequest, url;
|
||||
xhr = new XMLHttpRequest();
|
||||
url = option.url;
|
||||
let formData = option.formData;
|
||||
const cb = callback;
|
||||
xhr.onreadystatechange = function () {
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
if (xhr.readyState === 1) {
|
||||
if (
|
||||
(xhr.status >= 200 && xhr.status <= 300) ||
|
||||
xhr.status === 304 ||
|
||||
xhr.status == 0
|
||||
) {
|
||||
let successText = startUploadMsg.value;
|
||||
emit(
|
||||
"before",
|
||||
Object.assign({ currentTimeStamp, msg: successText, ...option })
|
||||
);
|
||||
}
|
||||
} else if (xhr.readyState === 4) {
|
||||
let successText = xhr.responseText ? xhr.responseText : uploadSuccess;
|
||||
if (
|
||||
(xhr.status >= 200 && xhr.status <= 300) ||
|
||||
xhr.status === 304 ||
|
||||
xhr.status == 0
|
||||
) {
|
||||
let data = xhr.responseText;
|
||||
emit("done", { currentTimeStamp, msg: successText, data: data });
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.open("post", url, true);
|
||||
if (props.headers) {
|
||||
for (let key in props.headers) {
|
||||
xhr.setRequestHeader(key, props.headers[key]);
|
||||
}
|
||||
} else {
|
||||
xhr.setRequestHeader("Accept", "application/json, text/javascript");
|
||||
}
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
emit("before", Object.assign(option, currentTimeStamp));
|
||||
xhr.send(formData);
|
||||
if (cb && typeof cb == "function") {
|
||||
cb();
|
||||
}
|
||||
clearAllCutEffect();
|
||||
};
|
||||
|
||||
const filetoDataURL = (file: File, fn: Function) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = function (e: any) {
|
||||
fn(e.target.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
const uploadChange = (e: any) => {
|
||||
e.preventDefault();
|
||||
const _files = [...(e.target.files || e.dataTransfer.files)];
|
||||
if (props.multiple && props.number != 0 && props.number < _files.length) {
|
||||
errorF(numberErrorMsg.value);
|
||||
return;
|
||||
}
|
||||
if (props.size && props.size != 0) {
|
||||
for (let i = 0; i < _files.length; i++) {
|
||||
let _file = _files[i];
|
||||
let _size = _file.size;
|
||||
if (_size > props.size * 1024) {
|
||||
errorF(occurFileSizeErrorMsg.value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let item of _files) {
|
||||
activeUploadFiles.value.push(item);
|
||||
filetoDataURL(item, function (res: any) {
|
||||
activeUploadFilesImgs.value.push(res);
|
||||
});
|
||||
}
|
||||
let arm1 =
|
||||
props.cut &&
|
||||
props.acceptMime.indexOf("image") != -1 &&
|
||||
props.multiple == false;
|
||||
let arm2 =
|
||||
props.cut &&
|
||||
props.acceptMime.indexOf("image") != -1 &&
|
||||
props.multiple == true;
|
||||
|
||||
if (arm1) {
|
||||
innerCutVisible.value = true;
|
||||
setTimeout(() => {
|
||||
let _imgs = document.getElementsByClassName("_lay_upload_img");
|
||||
if (_imgs && _imgs.length > 0) {
|
||||
let _img = _imgs[0];
|
||||
// @ts-ignore
|
||||
_cropper = new Cropper(_img, {
|
||||
aspectRatio: 16 / 9,
|
||||
});
|
||||
} else {
|
||||
clearAllCutEffect();
|
||||
}
|
||||
}, 200);
|
||||
} else {
|
||||
if (arm2) {
|
||||
console.warn(cannotSupportCutMsg.value);
|
||||
}
|
||||
if (!props.auto) {
|
||||
emit("update:modelValue", _files);
|
||||
return;
|
||||
}
|
||||
commonUploadTransaction(_files);
|
||||
}
|
||||
};
|
||||
|
||||
const commonUploadTransaction = (_files: any[]) => {
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
let successText = uploadSuccess;
|
||||
if (props.url) {
|
||||
localUploadTransaction({
|
||||
url: props.url,
|
||||
files: _files,
|
||||
});
|
||||
} else {
|
||||
emit("done", { currentTimeStamp, msg: successText, data: _files });
|
||||
clearAllCutEffect();
|
||||
}
|
||||
};
|
||||
|
||||
const chooseFile = () => {
|
||||
let _target = orgFileInput.value;
|
||||
if (_target) {
|
||||
_target.click();
|
||||
}
|
||||
};
|
||||
|
||||
const clickOrgInput = () => {
|
||||
let currentTimeStamp = new Date().valueOf();
|
||||
emit("choose", currentTimeStamp);
|
||||
};
|
||||
|
||||
const dragRef = ref();
|
||||
|
||||
function dragEnter(e: any) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function dragOver(e: any) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if (dragRef.value) {
|
||||
dragRef.value.addEventListener("dragenter", dragEnter, false);
|
||||
dragRef.value.addEventListener("dragover", dragOver, false);
|
||||
dragRef.value.addEventListener("drop", uploadChange, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (dragRef.value) {
|
||||
dragRef.value.removeEventListener("dragenter");
|
||||
dragRef.value.removeEventListener("dragover");
|
||||
dragRef.value.removeEventListener("drop");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layui-upload layui-upload-wrap" :class="disabledPreview ? 'layui-upload-file-disabled' : ''">
|
||||
<input type="file" class="layui-upload-file" ref="orgFileInput" :name="field" :field="field" :multiple="multiple"
|
||||
:accept="acceptMime" :disabled="disabled" @click="clickOrgInput" @change="uploadChange" />
|
||||
<div v-if="!drag">
|
||||
<div class="layui-upload-btn-box" @click.stop="chooseFile">
|
||||
<template v-if="slot.default">
|
||||
<slot :disabled="disabled"></slot>
|
||||
</template>
|
||||
<template v-else>
|
||||
<lay-button type="primary" :disabled="disabled">{{
|
||||
text
|
||||
}}</lay-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else ref="dragRef" class="layui-upload-drag" :class="
|
||||
disabled
|
||||
? 'layui-upload-drag-disable'
|
||||
: isDragEnter
|
||||
? 'layui-upload-drag-draging'
|
||||
: ''
|
||||
" @click.stop="chooseFile">
|
||||
<i class="layui-icon"></i>
|
||||
<p>{{ dragText }}</p>
|
||||
<div class="layui-hide" id="uploadDemoView">
|
||||
<hr />
|
||||
<img src="" alt="上传成功后渲染" style="max-width: 196px" />
|
||||
</div>
|
||||
</div>
|
||||
<lay-layer v-model="innerCutVisible" :title="computedCutLayerOption.title" :move="computedCutLayerOption.move"
|
||||
:resize="computedCutLayerOption.resize" :shade="computedCutLayerOption.shade"
|
||||
:shadeClose="computedCutLayerOption.shadeClose" :shadeOpacity="computedCutLayerOption.shadeOpacity"
|
||||
:zIndex="computedCutLayerOption.zIndex" :btnAlign="computedCutLayerOption.btnAlign"
|
||||
:area="computedCutLayerOption.area" :anim="computedCutLayerOption.anim"
|
||||
:isOutAnim="computedCutLayerOption.isOutAnim" :btn="computedCutLayerOption.btn" @close="clearAllCutEffect">
|
||||
<div class="copper-container" v-for="(base64str, index) in activeUploadFilesImgs" :key="`file${index}`">
|
||||
<img :src="base64str" :id="`_lay_upload_img${index}`" class="_lay_upload_img" />
|
||||
</div>
|
||||
</lay-layer>
|
||||
<div class="layui-upload-list" :class="disabledPreview ? 'layui-upload-list-disabled' : ''">
|
||||
<slot name="preview"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user