一辫塌、依賴包
- vue-pdf
"^4.0.12"
- v-viewer
"^1.5.1"
- jquery
"^3.4.1"
- element-ui
"^2.13.0"
二原押、初衷分冈、思路圾另、想法
絕大數(shù)后臺管理項目和少數(shù)C端項目都離不開文件的上傳及預(yù)覽,所以我就做了一個這個自認(rèn)為適用于絕大多數(shù)項目的組件~
用戶上傳圖片or
PDF丈秩,預(yù)覽上傳的文件無論圖片or
PDF盯捌,由于在現(xiàn)在的公司做的主要項目針對的是后臺管理,且有的頁面上傳的文件較多蘑秽,有的文件必傳饺著、有的文件需要顯示示例圖、有的文件需要對文件類型及文件大小做限制肠牲、有的場景希望上傳的區(qū)域較大或較小幼衰、直接拖拽文件到某一特定區(qū)域上傳、在文件較多的頁面希望用戶“直接”定位到有哪一個或哪一些文件上傳的校驗沒通過
對于開發(fā)者缀雳,希望在用戶上傳特定的一些文件后立即觸發(fā)回調(diào)事件對用戶上傳的文件及時做處理渡嚣。
三、組件預(yù)覽圖
-
總攬
-
pdf預(yù)覽
-
圖片預(yù)覽
-
gif
四、使用
<uploadFileNew
:fileImgList="fileNameList"
:fileSizeByte="10240"
ref="uploadFiles"
type="orange"
size="mini"
/>
fileNameList: Array<object> = [
{
id: "idCardFront",
fileName: "身份證正面",
required: true, // 必上傳
fileSizeByte: 15360, // 自定義當(dāng)前文件最大15兆
fileType: ["pdf"],
callback: (file: any) => {
console.log("回調(diào)成功", file);
},
},
{
id: "idCardBack",
fileName: "身份證反面",
},
{
id: "vin",
fileName: "vim碼",
},
{
id: "businessLicense",
fileName: "營業(yè)執(zhí)照",
},
{
id: "engine",
fileName: "車輛發(fā)動機艙全景",
initImg: require("@/assets/img/11592459733_.pic.jpg"),
},
];
// 獲取上傳的所有文件
(this as any).$refs.filePdf.getFiles("object");
五识椰、源碼
基本上全都寫了注釋
- 文件上傳組件
<template>
<el-row class="clearfix upload-files">
<el-col
:xs="24"
:sm="12"
:md="12"
:lg="6"
:xl="6"
v-for="(item, index) in fileImgListDrawing"
tag="div"
:key="index"
:id="item.id"
class="upload-show-box"
:class="{'upload-show-box-mini':size=='mini'}"
>
<!-- 目標(biāo)文件名稱 -->
<span class="file-info-top">{{item.fileName}}</span>
<main class="file-container" ref="fileBox" :data-index="index">
<!-- 文件展示區(qū)域 -->
<div
class="file-image-area"
:class="{'file-image-area-orange':type=='orange','no-border':!item.border}"
@click.stop="uploadImg(index)"
>
<!-- 初始化展示 -->
<div class="file-image-init-display" v-show="!item.data&&!item.pdfData">
<img class="initial-img-url" :src="initialImgUrl" />
<!-- 蒙板示例圖片 -->
<img class="mask-sample-img" :src="item.initImg" v-if="item.initImg" />
<p class="initial-title">
<span>將圖片拖放到這里 或 </span>
<span class="underline">點擊選擇圖片</span>
</p>
</div>
<!-- 圖片展示 -->
<img class="file-img" v-show="item.data" :src="item.data" alt />
<!-- pdf展示 -->
<pdf v-show="item.pdfData" :src="item.pdfData" :page="1" />
<input type="file" id="upLoad" ref="fileImage" @change.stop="uploadFile($event,index)" />
</div>
<!-- 文件名及文件操作區(qū)域 -->
<div class="file-text-bottom">
<!-- 文件名 -->
<el-tooltip
class="item"
:disabled="item.fileData.name?false:true"
effect="light"
:content="item.fileData.name"
placement="top-start"
>
<span class="file-name">{{item.fileData.name}}</span>
</el-tooltip>
<!-- 操作區(qū)域 -->
<div class="operating-area">
<i class="el-icon-folder-opened" @click.stop="uploadImg(index)"></i>
<i
class="el-icon-zoom-in"
v-show="item.data||item.pdfData"
@click="filePreview(item,index)"
></i>
<el-popconfirm
confirmButtonText="確定"
cancelButtonText="取消"
icon="el-icon-info"
title="您是否刪除該已上傳圖片绝葡?"
popper-class="deleteUpload"
@onConfirm="deleteFile(index,item.id)"
v-show="item.data||item.pdfData"
>
<i class="el-icon-delete" slot="reference"></i>
</el-popconfirm>
</div>
</div>
</main>
<!-- 文件驗證錯誤 -->
<span class="file-info-err" v-show="item.errInfo">{{item.errInfo}}</span>
</el-col>
<!-- 圖片預(yù)覽 -->
<img-viewer ref="viewer" />
<!-- pdf預(yù)覽 -->
<div class="pdf-preview" v-show="pdf.pdfPreview" @click.self="pdf.pdfPreview=false">
<div class="pdf-preview-box">
<div class="pdf-preview-box-top">
<span class="pdf-title">{{pdf.name}}</span>
<i class="el-icon-circle-close" @click="pdf.pdfPreview=false"></i>
</div>
<div class="pdf-preview-box-main">
<pdf
v-for="i in 1"
:key="i"
:src="pdf.pdf"
:page="pdf.page"
style="display: inline-block; width: 100%"
></pdf>
</div>
<div class="pdf-preview-box-paging">
<i class="el-icon-arrow-left" @click="pdfPaging(false)"></i>
<span>{{pdf.page}}</span>
<span style="margin:0px">/</span>
<span>{{pdf.size}}</span>
<i class="el-icon-arrow-right" @click="pdfPaging(true)"></i>
</div>
</div>
</div>
</el-row>
</template>
<script lang="ts">
// 引入vue-pdf
import pdf from "vue-pdf";
import CMapReaderFactory from "vue-pdf/src/CMapReaderFactory.js";
// 圖片查看
import imgViewer from "components/imgViewer/index.vue";
import { Component, Vue, Prop, Watch } from "vue-property-decorator";
import type from "@/utils/type";
@Component({
components: {
pdf: Vue.extend(pdf),
imgViewer,
},
})
export default class UploadFiles extends Vue {
// pdf預(yù)覽
pdf = {
pdfPreview: false,
pdf: "",
page: 1,
size: 1,
name: "",
};
// 組件大小
@Prop({
type: String,
})
private size?: string;
// 組件風(fēng)格
@Prop({
type: String,
default: "blue",
})
private type?: string;
// 初始化默認(rèn)圖片橙色
initialImgUrlConfigOrange =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEQAAAA0CAYAAAAzMZ5zAAAFeElEQVRoQ+1aa2wUVRg9Z7oWaH1AAsluWx6+wEcUBDEN8sNHIgkqMb4iRqpYOtMfPlA0oCZKTCSBIAY1sdMiaDRBMT5iTCSKwUeiQSGAJkABBQ3dXREloqgt7Ryz5SG73e3c2W3TGeL+nfN93zln7zf33rmX+P+X5QBz/ZBEuDW1sLwrAAwHcAAWN6Le/opc6J3q/mUZoubELZAWSzg3VziBvYC1gI3JN09lU04YIrdqqeTN8xNL4kU66fv9cFF93m2I3Pg8CUtNRZB8gk5qkSk+SjiqpboGnrdL0mBT4iQ7YJVfwIYf95jGRAVHNSUWCXosKGFaXEY75dtiQfMONJ5yE5slTQhKhOQOOqkLg8aFHU81xX8XcGZQogTb2ZgybrOg+QcKnxkhhyVVBCVAoBNOqpykgsaGGZ95h+wQNC4oycy6hI3ps4PGhR1PufEXJNwXlCjJFXRSDUHjwo6n3JpLoM4tAixTsiQEi5PZkNpkGhMV3NGFWXP8eXkwXn0SbGFjyo6KyCA8j61UJ50Gtb0j4Aa/YJIfYWTlDE7f3e6HjeLz//Yya24rw8EvHgcwX0JlrhiCf4NcirFjn+bVn3ZGUawJ557bf7dqOKCbAEzu3v4Lv4LYiCEV77Hu+/0mSfsDo5erxrE+2dofuU/O2cOQ/i5YTH6tqDkPnZ2bwbIZdNrWF5PDNCb0hkgLLTS7n0maSiIJWOPpJA+YCgyKC78hbmKupOeOCyPwARvTNwYVaooPtSFaVXM+2ru2ChqS1ecW59JOLTcVGQQXWkNObpU8M147LKuWdtuWIGJNsOE1JKdV8pjSiooRk1j37WEToaaYUBpSqFV6moJX2JiebSrWBBc6Q3prlXyCWGbdyYbkahOxJpg+M0RufCWIl2invzEpXAgjN/GQpGWmOQgcQnn5Zbz3px9MY3rD9Ykhaq66Q563msQRwHoStr2kmEMt01bJ0zpfg9VT6Ww6UqopJRsit6oCUKukmhNrBWI9Bsdm8e59baYEu1vFdT8XdKVpTNZUTCyhk55fTGxWnlITyE08IymzKcz6kfwNxBzaqXdNagRtlZ71Mt9orGlsSH5sUq8QpqQRopWjzkHHkW2CBhUsQLoAH6aT/Kvge6PAAiyoMAJpVFSOL2UTWpohbvx9Cb7LaJLbEbNmsr5ta67IUlslz8hcCzs5vdiP30UboubENHlaa/ovZo4tQCyAnVx+MtlSWyXvVEw8Qif9rCm3kt8hcjNf2JLfFfW1nlwLa/A9bNjzc7Gzip/Q7tlOnMLG1EY/bJ4ZK2hI5nC86lHJWxI88mgEgf2wyurheQuKnVX8apPYjdhZE1nf+ocftqQRolVj4uj4Z6eEM4IUGggsydfppGYFqR34HaKmxKuC6oIUGUgsLdbRTr1myiGQIWqproXX9aWUGfXR+BH4E4NiEzl73y4TxsbCjm26Nki63CRxmDAkN2HYsCm8fVuHHy9zQ9zEHEktfgnD+tz0PouRIVo1Zig62ndKGhFWwX68uo9fietppz/sDWtmiJtYLukBv6Jhf07yF5QPupSz96YLcfU1RM2jLobXkTkMj4VdsAk/kutgJ68rtLT3N6Qp/omAa0yKRQXDo/dtF+fj26shaonfqi68FRWhpjy7bz8xNpXOvg25MQUN0ZqaITjYtV3SaNNCUcKR2IPK0yfwrt2HjJbucqsWSt5TURIZlCuJN+ikZ/oaohWJ0ejE9twTs6AFo4CnZdXTTq48zjVvy8hNvC3p5igIKpUjicOIWZOOX7XoeT+kqfpaoWtdqYWiFE9yC0ZW1mZuRWUZovVXxdDamjlcvihKgvqCK8nn6aQezDbE5zy1LwqHOQdhzcg1xAY4NMyk+5UbceBfXqQOZiFnaPcAAAAASUVORK5CYII=";
// 初始化默認(rèn)圖片藍(lán)色
initialImgUrlConfigBlue =
"data:image/png;base64,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";
// 初始化展示默認(rèn)圖片
initialImgUrl =
this.type === "blue"
? this.initialImgUrlConfigBlue
: this.initialImgUrlConfigOrange;
// 上傳文件的列表
@Prop({
type: Array,
required: true,
})
private fileImgList?: Array<any>;
// 上傳的文件限制大小
@Prop({
type: Number,
default: 5120, // 默認(rèn)5兆
})
private fileSizeByte?: number;
// 上傳的文件類型限制
@Prop({
type: Array,
default: () => ["jpg", "jpeg", "pdf", "png", "txt", "webp"],
})
private fileType?: Array<string>;
// 錯誤滾動盒子
@Prop({
type: String,
default: ".el-scrollbar__wrap",
})
private errScrollBox?: string;
// 渲染列表
fileImgListDrawing: Array<any> = [];
// 向外暴露出去的總文件數(shù)組
exposedFileArr: Array<any> = [];
created() {
// 初始化上傳文件列表
this.fileImgListDrawing = (this as any).fileImgList.map((v: any) => {
// 文件錯誤提示
v.errInfo = "";
// 文件
v.fileData = {};
// border虛線
v.border = true;
return v;
});
}
mounted() {
// 拖拽文件上傳
const that = this;
document.addEventListener(
"drop",
function (e) {
e.preventDefault();
},
false
);
document.addEventListener(
"dragover",
function (e) {
e.preventDefault();
},
false
);
(this.$refs.fileBox as any).forEach((el: any) => {
el.ondragleave = (e: any) => {
e.preventDefault(); //阻止離開時的瀏覽器默認(rèn)行為
};
el.ondrop = (e: any) => {
//阻止拖放后的瀏覽器默認(rèn)行為
e.preventDefault();
const data = e.dataTransfer.files;
// 檢測是否有文件拖拽到頁面
if (data.length < 1) {
return;
}
that.uploadFile(e, $(el).data("index"));
};
el.ondragenter = (e: any) => {
//阻止拖入時的瀏覽器默認(rèn)行為
e.preventDefault();
};
el.ondragover = (e: any) => {
//阻止拖來拖去的瀏覽器默認(rèn)行為
e.preventDefault();
};
});
}
// 代理打開文件上傳
uploadImg(i: number) {
(this.$refs as any).fileImage[i].dispatchEvent(new MouseEvent("click"));
}
// 文件上傳-預(yù)覽文件至“文件展示區(qū)域”
uploadFile(el: any, i: number) {
// 將讀出的文件保存
const elFile = el.dataTransfer
? el.dataTransfer.files[0]
: el.target.files[0];
if (!elFile) return;
// 文件驗證不通過
if (!this.fileLimit(elFile, i)) {
return this.deleteFile(i, this.fileImgListDrawing[i].id);
}
const reader = new FileReader();
this.$set(this.fileImgListDrawing[i], "fileData", elFile);
reader.readAsDataURL(elFile);
reader.onloadstart = () => {
const that = this;
// 判斷是否為pdf文件
if (elFile.type == "application/pdf") {
reader.onload = function () {
that.fileImgListDrawing[i].pdfData = (pdf as any).createLoadingTask({
url: this.result,
CMapReaderFactory,
});
that.fileImgListDrawing[i].data = "";
that.fileImgListDrawing[i].border = false;
that.$set(that.fileImgListDrawing, i, that.fileImgListDrawing[i]);
};
} else {
reader.onload = function () {
that.fileImgListDrawing[i].data = this.result;
that.fileImgListDrawing[i].pdfData = "";
that.fileImgListDrawing[i].border = false;
that.$set(that.fileImgListDrawing, i, that.fileImgListDrawing[i]);
};
}
// 觸發(fā)回調(diào)
this.fileImgListDrawing[i].callback &&
this.fileImgListDrawing[i].callback(elFile);
};
elFile.typefileId = this.fileImgListDrawing[i].id;
this.integrationFileArr(elFile);
}
// 文件大小限制及類型限制
fileLimit(file: any, i: number): boolean {
const arrFile = this.fileImgListDrawing[i];
// 獲取文件大小
const fileSize = file.size / 1024,
// 單個文件最大大小
onesBiggestFileSize = arrFile.fileSizeByte,
// 最終文件最大大小
biggestFileSize = onesBiggestFileSize
? onesBiggestFileSize
: this.fileSizeByte,
// 驗證文件大小是否符合
fileSizeValidation = fileSize > biggestFileSize;
if (fileSizeValidation) {
arrFile.errInfo = `文件不能超過${biggestFileSize / 1024}兆`;
return false;
}
// 獲取文件類型
const fileType = file.type
.substring(file.type.lastIndexOf("/") + 1)
.toLowerCase(),
// 單個文件最終驗證類型
onesUltimatelyFileType = arrFile.fileType,
// 文件最終驗證類型
ultimatelyFileType = onesUltimatelyFileType
? onesUltimatelyFileType
: this.fileType,
// 驗證文件類型是否符合
fileTypeValidation = ultimatelyFileType.some(
(v: string) => v == fileType
);
if (!fileTypeValidation) {
arrFile.errInfo = `只能上傳${ultimatelyFileType.join("/")}文件`;
return false;
}
arrFile.errInfo = "";
return true;
}
// 文件必傳攔截
fileErrorToIntercept() {
const errArr: any = [];
this.fileImgListDrawing = this.fileImgListDrawing.map((v, i) => {
if (v.required && !v.fileData.size) {
v.errInfo = `${v.fileName}必須上傳`;
errArr.push(v.id);
}
return v;
});
const noRulesLength = errArr.length;
if (!noRulesLength) {
return {
isValidation: true,
// 必傳但未傳的文件數(shù)量
noRulesLength,
};
}
// 錨點滾動
$((this as any).errScrollBox).animate(
{ scrollTop: $("#" + errArr[0])[0].offsetTop },
300
);
return {
isValidation: false,
noRulesLength,
};
}
// 文件整合數(shù)組 去重
integrationFileArr(val: any) {
if (this.exposedFileArr.length === 0) {
this.exposedFileArr.push(val);
}
const index = this.exposedFileArr.findIndex(
(e) => e.typefileId === val.typefileId
);
if (
this.exposedFileArr.findIndex(
(element) => element.typefileId == val.typefileId
) === -1
) {
this.exposedFileArr.push(val);
} else {
this.exposedFileArr.splice(index, 1, val);
}
}
// 獲取向外暴露出去的文件集合
getFiles(type?: string) {
let newList: any = this.exposedFileArr;
if (type === "object") {
newList = {};
this.exposedFileArr.forEach((v) => {
newList[v.typefileId] = v;
});
}
const { isValidation, noRulesLength } = this.fileErrorToIntercept();
return {
fileList: newList,
// 總共上傳的文件數(shù)量
length: this.exposedFileArr.length,
// 需上傳的文件是否全部驗證成功
isValidation,
// 必傳但未傳的文件數(shù)量
noRulesLength,
};
}
// 文件刪除
deleteFile(i: number, id: string) {
const fileObj = this.fileImgListDrawing[i];
fileObj.data = fileObj.pdfData = "";
fileObj.fileData = {};
fileObj.border = true;
this.$set(this.fileImgListDrawing, i, fileObj);
// 清空數(shù)據(jù)
(this.$refs as any).fileImage[i].value = "";
// 刪除文件
this.exposedFileArr.forEach((v, i) => {
if (v.typefileId === id) return this.exposedFileArr.splice(i, 1);
});
}
// 文件預(yù)覽
filePreview(val: any, index: number) {
const file = this.fileImgListDrawing[index];
// pdf預(yù)覽
if (file.pdfData) {
this.pdfScrollBarTop();
this.pdf.pdfPreview = true;
this.pdf.pdf = file.pdfData;
this.pdf.page = 1;
this.pdf.name = file.fileName;
file.pdfData.promise.then((pdf: any) => {
this.pdf.size = pdf.numPages ? pdf.numPages : 1;
});
}
// 圖片預(yù)覽
if (file.data) {
let imgArr: any = [];
imgArr.push({
thumbnail: file.data,
source: file.data,
});
(this.$refs as any).viewer.show(imgArr, 0);
}
}
// pdf滾動條置頂
pdfScrollBarTop() {
$(".pdf-preview-box-main").animate({ scrollTop: 0 }, 300);
}
// pdf分頁
pdfPaging(isAdd: boolean) {
this.pdfScrollBarTop();
this.pdf.page =
isAdd && this.pdf.page < this.pdf.size ? ++this.pdf.page : this.pdf.page;
this.pdf.page =
!isAdd && this.pdf.page > 1 ? --this.pdf.page : this.pdf.page;
}
}
</script>
<style scoped lang="scss">
$gobal-color-big: rgba(75, 108, 246, 1);
$gobal-color-orange: #fe9818;
.upload-files {
.upload-show-box {
margin-bottom: 20px;
position: relative;
}
.upload-show-box-mini {
.file-container {
width: 174px;
height: 160px;
box-shadow: 0px 0px 8px 0px rgba(39, 59, 100, 0.19);
.file-image-area {
width: 162px;
height: 120px;
margin: 6px auto;
.file-image-init-display {
.initial-img-url {
margin: 28px auto 10px;
}
}
}
.file-text-bottom {
width: 162px;
height: 20px;
.file-name {
width: 95px;
line-height: 20px;
}
.operating-area {
i,
span {
height: 20px;
line-height: 20px;
font-size: 16px;
&:hover {
color: $gobal-color-orange;
}
}
}
}
}
}
.file-info-top {
font-size: 12px;
font-weight: 400;
color: rgba(81, 81, 81, 1);
margin-bottom: 6px;
display: inline-block;
}
.file-info-err {
left: 0;
bottom: -20px;
position: absolute;
font-size: 12px;
font-weight: 400;
color: red;
display: inline-block;
}
.file-container {
width: 230px;
box-sizing: border-box;
height: 210px;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 0px 8px 0px rgba(39, 59, 100, 0.08);
border-radius: 1px;
overflow: hidden;
.no-border {
border: none !important;
}
.file-image-area {
width: 214px;
height: 156px;
margin: 8px auto;
background: rgba(252, 254, 255, 1);
border-radius: 1px;
overflow: auto;
border: 1px dashed $gobal-color-big;
#upLoad {
display: none;
}
.file-image-init-display {
width: 100%;
height: 100%;
cursor: pointer;
display: inline-block;
position: relative;
.initial-img-url {
margin: 48px auto 20px;
width: 32px;
display: block;
position: relative;
z-index: 1;
}
.mask-sample-img {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
opacity: 0.2;
-webkit-mask: -webkit-linear-gradient(
rgba(0, 0, 0, 0.5),
rgba(0, 0, 0, 1),
rgba(0, 0, 0, 1),
rgba(0, 0, 0, 0.5)
);
}
.initial-title {
font-size: 12px;
font-weight: 400;
color: rgba(81, 81, 81, 1);
text-align: center;
.underline {
text-decoration: underline;
}
}
}
.file-img {
cursor: pointer;
width: 100%;
height: 100%;
object-fit: cover;
}
}
.file-image-area-orange {
border: 1px dashed $gobal-color-orange;
}
.file-text-bottom {
width: 214px;
height: 30px;
margin: 0 auto;
background: rgba(255, 255, 255, 1);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.08);
display: flex;
.file-name {
width: 135px;
height: 100%;
line-height: 30px;
font-size: 12px;
color: #414141;
font-weight: 600;
padding-left: 8px;
box-sizing: border-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.operating-area {
flex: 1;
display: flex;
margin-right: 4px;
i,
span {
flex: 1;
font-size: 18px;
color: #bbbbbb;
cursor: pointer;
text-align: right;
height: 30px;
line-height: 30px;
&:hover {
color: $gobal-color-big;
}
}
}
}
}
.pdf-preview {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #0000004d;
z-index: 999;
overflow: auto;
.pdf-preview-box {
width: 600px;
height: 450px;
border-radius: 10px;
overflow: hidden;
background-color: #fff;
margin: 0 auto;
position: relative;
top: 50%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
.pdf-preview-box-top {
width: 100%;
height: 24px;
background-color: #233e48;
text-align: center;
line-height: 24px;
position: relative;
.pdf-title {
vertical-align: super;
font-size: 12px;
font-weight: 400;
color: rgba(255, 255, 255, 1);
}
.el-icon-circle-close {
position: absolute;
font-size: 16px;
color: #fff;
right: 10px;
cursor: pointer;
top: 50%;
transform: translateY(-50%);
}
}
.pdf-preview-box-main {
flex: 1;
overflow: auto;
}
.pdf-preview-box-paging {
width: 100%;
height: 24px;
background-color: #233e484d;
text-align: center;
font-size: 14px;
font-weight: 400;
line-height: 24px;
i {
color: #000;
cursor: pointer;
margin: 0 10px;
}
span {
margin: 0 10px;
user-select: none;
}
}
}
}
}
</style>
- 圖片預(yù)覽組件
<template>
<div>
<viewer
:images="images"
:options="options"
class="viewer"
ref="viewer"
@inited="inited"
v-if="images && images.length"
>
<img
v-for="{source, thumbnail} in images"
:src="thumbnail"
:data-source="source"
:key="source"
class="image"
/>
</viewer>
</div>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import vue from "vue";
import Viewer from "v-viewer";
import "viewerjs/dist/viewer.css";
vue.use(Viewer);
@Component
export default class ImgViewer extends Vue {
options = {
url: "data-source",
};
index = 0;
images = [];
inited(viewer: any) {
(this as any).$viewer = viewer;
(this as any).$viewer.view(this.index);
}
view(index: any) {
this.index = index;
(this as any).$viewer.view(this.index);
}
show(images: any, index = 0) {
if (this.images === images) {
this.view(index);
return;
}
this.images = images;
this.index = index;
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
.image {
display: none;
}
</style>
<style>
.viewer-loading > img {
display: none; /* hide big images when it is loading */
}
.viewer-list > li {
opacity: 0.3;
}
</style>
- 刪除彈框樣式
.deleteUpload {
width: 160px;
height: 68px;
padding: 10px 5px 0 7px;
margin-left: -120px;
box-sizing: border-box;
.el-popconfirm__main {
font-size: 12px;
color: #515151;
margin-bottom: 8px;
i {
display: none;
}
}
&[x-placement^=top] {
// margin-bottom: 0px;
.popper__arrow {
left: 132px !important;
right: 18px;
}
}
&[x-placement^=bottom] {
// margin-top: 1px;
.popper__arrow {
left: 132px !important;
right: 18px;
}
}
.el-popconfirm__action {
text-align: center;
.el-button {
width: 60px;
height: 20px;
padding: 0;
}
.el-button--text {
border: 1px solid rgba(239, 244, 255, 1);
color: #AEAEAE;
}
.el-button--primary {
background-color: #4b6cf6;
border-color: #4b6cf6;
}
}
}