|
@@ -14,7 +14,45 @@
|
|
|
</svg>
|
|
</svg>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="output" v-show="!renderLoading" ref="output"></div>
|
|
|
|
|
|
|
+ <div v-if="isImageType" class="viewfile-image" v-show="!renderLoading">
|
|
|
|
|
+ <slot
|
|
|
|
|
+ name="image"
|
|
|
|
|
+ :src="imageUrl"
|
|
|
|
|
+ :src-list="imageSrcList"
|
|
|
|
|
+ :index="previewIndex"
|
|
|
|
|
+ :file="file"
|
|
|
|
|
+ :preview="previewApi"
|
|
|
|
|
+ >
|
|
|
|
|
+ <img
|
|
|
|
|
+ class="viewfile-image-inner"
|
|
|
|
|
+ :src="imageUrl"
|
|
|
|
|
+ :alt="file.filename || ''"
|
|
|
|
|
+ @click="openImagePreview(0)"
|
|
|
|
|
+ />
|
|
|
|
|
+ </slot>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="previewVisible" class="viewfile-image-preview" @click.self="closeImagePreview">
|
|
|
|
|
+ <button class="viewfile-image-preview-close" type="button" @click="closeImagePreview">×</button>
|
|
|
|
|
+ <button
|
|
|
|
|
+ v-if="imageSrcList.length > 1"
|
|
|
|
|
+ class="viewfile-image-preview-prev"
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ @click.stop="prevImage"
|
|
|
|
|
+ >
|
|
|
|
|
+ ‹
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <img class="viewfile-image-preview-img" :src="imageSrcList[previewIndex]" alt="" />
|
|
|
|
|
+ <button
|
|
|
|
|
+ v-if="imageSrcList.length > 1"
|
|
|
|
|
+ class="viewfile-image-preview-next"
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ @click.stop="nextImage"
|
|
|
|
|
+ >
|
|
|
|
|
+ ›
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-else class="output" v-show="!renderLoading" ref="output"></div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<view-other-component
|
|
<view-other-component
|
|
@@ -28,10 +66,9 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, computed, watch, nextTick } from "vue"
|
|
|
|
|
-import commJs from "@/comm_js"
|
|
|
|
|
-import { render } from "@/components/view_file/util"
|
|
|
|
|
-import ViewOtherComponent from "@/components/view_file/vendors/other/index.vue"
|
|
|
|
|
|
|
+import { ref, computed, watch, nextTick, onBeforeUnmount, onMounted } from "vue"
|
|
|
|
|
+import { readDataURL, render } from "./util"
|
|
|
|
|
+import ViewOtherComponent from "./vendors/other/index.vue"
|
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
@@ -45,6 +82,9 @@ const props = defineProps({
|
|
|
|
|
|
|
|
const renderLoading = ref(false)
|
|
const renderLoading = ref(false)
|
|
|
const output = ref(null)
|
|
const output = ref(null)
|
|
|
|
|
+const imageUrl = ref("")
|
|
|
|
|
+const previewVisible = ref(false)
|
|
|
|
|
+const previewIndex = ref(0)
|
|
|
|
|
|
|
|
// 可在在线预览文件类型
|
|
// 可在在线预览文件类型
|
|
|
const isAbleView = computed(() => {
|
|
const isAbleView = computed(() => {
|
|
@@ -75,6 +115,63 @@ const isAbleView = computed(() => {
|
|
|
return ablePreviewTypes.includes(lowType)
|
|
return ablePreviewTypes.includes(lowType)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+const isImageType = computed(() => {
|
|
|
|
|
+ const lowType = (props.file.type || "").toLowerCase()
|
|
|
|
|
+ return ["gif", "jpg", "jpeg", "bmp", "tiff", "tif", "png", "svg"].includes(lowType)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const imageSrcList = computed(() => {
|
|
|
|
|
+ const src = String(imageUrl.value || "")
|
|
|
|
|
+ return src ? [src] : []
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const previewApi = computed(() => {
|
|
|
|
|
+ return {
|
|
|
|
|
+ visible: previewVisible.value,
|
|
|
|
|
+ open: openImagePreview,
|
|
|
|
|
+ close: closeImagePreview,
|
|
|
|
|
+ next: nextImage,
|
|
|
|
|
+ prev: prevImage,
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+function openImagePreview(index = 0) {
|
|
|
|
|
+ if (!imageSrcList.value.length) return
|
|
|
|
|
+ previewIndex.value = Math.max(0, Math.min(imageSrcList.value.length - 1, Number(index) || 0))
|
|
|
|
|
+ previewVisible.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function closeImagePreview() {
|
|
|
|
|
+ previewVisible.value = false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function nextImage() {
|
|
|
|
|
+ const list = imageSrcList.value
|
|
|
|
|
+ if (list.length <= 1) return
|
|
|
|
|
+ previewIndex.value = (previewIndex.value + 1) % list.length
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function prevImage() {
|
|
|
|
|
+ const list = imageSrcList.value
|
|
|
|
|
+ if (list.length <= 1) return
|
|
|
|
|
+ previewIndex.value = (previewIndex.value - 1 + list.length) % list.length
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function onKeydown(e) {
|
|
|
|
|
+ if (!previewVisible.value) return
|
|
|
|
|
+ if (e.key === "Escape") closeImagePreview()
|
|
|
|
|
+ if (e.key === "ArrowRight") nextImage()
|
|
|
|
|
+ if (e.key === "ArrowLeft") prevImage()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ window.addEventListener("keydown", onKeydown)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ window.removeEventListener("keydown", onKeydown)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* @{params} buffer 文件字节流
|
|
* @{params} buffer 文件字节流
|
|
|
* @{params} extend 文件扩展名
|
|
* @{params} extend 文件扩展名
|
|
@@ -98,6 +195,24 @@ watch(
|
|
|
try {
|
|
try {
|
|
|
renderLoading.value = true
|
|
renderLoading.value = true
|
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
|
|
|
+ if (isImageType.value) {
|
|
|
|
|
+ imageUrl.value = ""
|
|
|
|
|
+ previewVisible.value = false
|
|
|
|
|
+ previewIndex.value = 0
|
|
|
|
|
+ if (output.value) output.value.innerHTML = ""
|
|
|
|
|
+ readDataURL(newFile.fileBuffer)
|
|
|
|
|
+ .then((url) => {
|
|
|
|
|
+ imageUrl.value = String(url || "")
|
|
|
|
|
+ })
|
|
|
|
|
+ .finally(() => {
|
|
|
|
|
+ renderLoading.value = false
|
|
|
|
|
+ })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ imageUrl.value = ""
|
|
|
|
|
+ previewVisible.value = false
|
|
|
|
|
+ previewIndex.value = 0
|
|
|
renderResult(newFile.fileBuffer, newFile.type).finally(() => {
|
|
renderResult(newFile.fileBuffer, newFile.type).finally(() => {
|
|
|
renderLoading.value = false
|
|
renderLoading.value = false
|
|
|
})
|
|
})
|
|
@@ -124,6 +239,76 @@ watch(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-inner {
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ max-height: 100%;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.72);
|
|
|
|
|
+ z-index: 9999;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-img {
|
|
|
|
|
+ max-width: calc(100vw - 120px);
|
|
|
|
|
+ max-height: calc(100vh - 120px);
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-close,
|
|
|
|
|
+.viewfile-image-preview-prev,
|
|
|
|
|
+.viewfile-image-preview-next {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ border: 0;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.36);
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ line-height: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-close {
|
|
|
|
|
+ right: 16px;
|
|
|
|
|
+ top: 16px;
|
|
|
|
|
+ width: 40px;
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ border-radius: 20px;
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-prev,
|
|
|
|
|
+.viewfile-image-preview-next {
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ transform: translateY(-50%);
|
|
|
|
|
+ width: 44px;
|
|
|
|
|
+ height: 44px;
|
|
|
|
|
+ border-radius: 22px;
|
|
|
|
|
+ font-size: 28px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-prev {
|
|
|
|
|
+ left: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.viewfile-image-preview-next {
|
|
|
|
|
+ right: 16px;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
|
@import url("./index.less");
|
|
@import url("./index.less");
|