|
@@ -0,0 +1,306 @@
|
|
|
+<template>
|
|
|
+ <el-dialog
|
|
|
+ :class="prefixCls"
|
|
|
+ title="图片预览"
|
|
|
+ :visible.sync="modalIsShow"
|
|
|
+ :close-on-press-escape="false"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ append-to-body
|
|
|
+ fullscreen
|
|
|
+ destroy-on-close
|
|
|
+ @opened="dialogOpen"
|
|
|
+ @close="dialogClose"
|
|
|
+ >
|
|
|
+ <div slot="title"></div>
|
|
|
+ <div :class="[`${prefixCls}-close`]" @click="cancel">
|
|
|
+ <i class="el-icon-circle-close"></i>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div :class="[`${prefixCls}-body`]" ref="ReviewBody">
|
|
|
+ <!-- <div
|
|
|
+ :class="[`${prefixCls}-guide`, `${prefixCls}-guide-prev`]"
|
|
|
+ @click.stop="showPrev"
|
|
|
+ >
|
|
|
+ <i class="el-icon-arrow-left"></i>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :class="[`${prefixCls}-guide`, `${prefixCls}-guide-next`]"
|
|
|
+ @click.stop="showNext"
|
|
|
+ >
|
|
|
+ <i class="el-icon-arrow-right"></i>
|
|
|
+ </div> -->
|
|
|
+ <div
|
|
|
+ :class="[
|
|
|
+ `${prefixCls}-imgs`,
|
|
|
+ { [`${prefixCls}-imgs-nosition`]: nosition },
|
|
|
+ ]"
|
|
|
+ :style="styles"
|
|
|
+ v-move-ele.prevent.stop="{ mouseMove }"
|
|
|
+ v-if="modalIsShow"
|
|
|
+ >
|
|
|
+ <img
|
|
|
+ :key="curImage.imgSrc"
|
|
|
+ :src="curImage.imgSrc"
|
|
|
+ :alt="curImage.name"
|
|
|
+ ref="PreviewImgDetail"
|
|
|
+ @load="resizeImage"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div :class="[`${prefixCls}-none`]" v-if="!curImage.imgSrc">
|
|
|
+ <i class="el-icon-picture"></i>
|
|
|
+ <p>暂无数据</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div :class="[`${prefixCls}-loading`]" v-show="loading">
|
|
|
+ <i class="el-icon-loading"></i>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div :class="[`${prefixCls}-footer`]">
|
|
|
+ <ul>
|
|
|
+ <li title="合适大小" @click="toOrigin">
|
|
|
+ <i class="el-icon-rank"></i>
|
|
|
+ </li>
|
|
|
+ <li
|
|
|
+ title="放大"
|
|
|
+ @click="toMagnify"
|
|
|
+ :class="{
|
|
|
+ 'li-disabled': transform.scale === maxScale,
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <i class="el-icon-zoom-in"></i>
|
|
|
+ </li>
|
|
|
+ <li
|
|
|
+ title="缩小"
|
|
|
+ @click="toShrink"
|
|
|
+ :class="{
|
|
|
+ 'li-disabled': transform.scale === minScale,
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <i class="el-icon-zoom-out"></i>
|
|
|
+ </li>
|
|
|
+ <li title="旋转" @click.stop="toRotate">
|
|
|
+ <i class="el-icon-refresh"></i>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import MoveEle from "./move-ele";
|
|
|
+const prefixCls = "cc-image-preview";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "simple-image-preview",
|
|
|
+ props: {
|
|
|
+ curImage: {
|
|
|
+ type: Object,
|
|
|
+ default() {
|
|
|
+ return {};
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ directives: { MoveEle },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ prefixCls,
|
|
|
+ modalIsShow: false,
|
|
|
+ styles: { width: "", height: "", top: "", left: "", transform: "" },
|
|
|
+ initWidth: 500,
|
|
|
+ minScale: 0.2,
|
|
|
+ maxScale: 5,
|
|
|
+ transform: {
|
|
|
+ scale: 1,
|
|
|
+ rotate: 0,
|
|
|
+ },
|
|
|
+ loading: false,
|
|
|
+ loadingSetT: null,
|
|
|
+ nosition: false,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // watch: {
|
|
|
+ // "curImage.imgSrc": {
|
|
|
+ // handler(val) {
|
|
|
+ // if (val) {
|
|
|
+ // this.loadingSetT = setTimeout(() => {
|
|
|
+ // this.loading = true;
|
|
|
+ // }, 300);
|
|
|
+ // this.styles = {
|
|
|
+ // width: "",
|
|
|
+ // height: "",
|
|
|
+ // top: "",
|
|
|
+ // left: "",
|
|
|
+ // transform: ""
|
|
|
+ // };
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // },
|
|
|
+ methods: {
|
|
|
+ dialogClose() {
|
|
|
+ this.$refs.ReviewBody.removeEventListener("wheel", this.mouseWheel);
|
|
|
+ },
|
|
|
+ dialogOpen() {
|
|
|
+ this.$refs.ReviewBody.addEventListener("wheel", this.mouseWheel);
|
|
|
+ },
|
|
|
+ resizeImage() {
|
|
|
+ if (this.loadingSetT) clearTimeout(this.loadingSetT);
|
|
|
+
|
|
|
+ const imgDom = this.$refs.PreviewImgDetail;
|
|
|
+ const { naturalWidth, naturalHeight } = imgDom;
|
|
|
+ const imageSize = this.getImageSizePos({
|
|
|
+ win: {
|
|
|
+ width: this.$refs.ReviewBody.clientWidth,
|
|
|
+ height: this.$refs.ReviewBody.clientHeight,
|
|
|
+ },
|
|
|
+ img: {
|
|
|
+ width: naturalWidth,
|
|
|
+ height: naturalHeight,
|
|
|
+ },
|
|
|
+ rotate: 0,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.styles = Object.assign(this.styles, {
|
|
|
+ width: imageSize.width + "px",
|
|
|
+ height: imageSize.height + "px",
|
|
|
+ top: imageSize.top + "px",
|
|
|
+ left: imageSize.left + "px",
|
|
|
+ marginLeft: "auto",
|
|
|
+ transform: "none",
|
|
|
+ });
|
|
|
+ this.transform = {
|
|
|
+ scale: 1,
|
|
|
+ rotate: 0,
|
|
|
+ };
|
|
|
+ this.loading = false;
|
|
|
+ setTimeout(() => {
|
|
|
+ this.nosition = false;
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+ getImageSizePos({ win, img, rotate }) {
|
|
|
+ const imageSize = {
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+ top: 0,
|
|
|
+ left: 0,
|
|
|
+ };
|
|
|
+ const isHorizontal = !!(rotate % 180);
|
|
|
+
|
|
|
+ const rateWin = isHorizontal
|
|
|
+ ? win.height / win.width
|
|
|
+ : win.width / win.height;
|
|
|
+ const hwin = isHorizontal
|
|
|
+ ? {
|
|
|
+ width: win.height,
|
|
|
+ height: win.width,
|
|
|
+ }
|
|
|
+ : win;
|
|
|
+
|
|
|
+ const rateImg = img.width / img.height;
|
|
|
+
|
|
|
+ if (rateImg <= rateWin) {
|
|
|
+ imageSize.height = Math.min(hwin.height, img.height);
|
|
|
+ imageSize.width = Math.floor(
|
|
|
+ (imageSize.height * img.width) / img.height
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ imageSize.width = Math.min(hwin.width, img.width);
|
|
|
+ imageSize.height = Math.floor(
|
|
|
+ (imageSize.width * img.height) / img.width
|
|
|
+ );
|
|
|
+ }
|
|
|
+ imageSize.left = (win.width - imageSize.width) / 2;
|
|
|
+ imageSize.top = (win.height - imageSize.height) / 2;
|
|
|
+ return imageSize;
|
|
|
+ },
|
|
|
+ cancel() {
|
|
|
+ this.modalIsShow = false;
|
|
|
+ this.$emit("on-close");
|
|
|
+ },
|
|
|
+ open() {
|
|
|
+ this.modalIsShow = true;
|
|
|
+ },
|
|
|
+ showPrev() {
|
|
|
+ this.$emit("on-prev");
|
|
|
+ // this.initData();
|
|
|
+ },
|
|
|
+ showNext() {
|
|
|
+ this.$emit("on-next");
|
|
|
+ // this.initData();
|
|
|
+ },
|
|
|
+ // dome-move
|
|
|
+ registWheelHandle() {
|
|
|
+ this.$refs.ReviewBody.addEventListener("wheel", this.mouseWheel);
|
|
|
+ },
|
|
|
+ mouseMove({ left, top }) {
|
|
|
+ this.styles.left = left + "px";
|
|
|
+ this.styles.top = top + "px";
|
|
|
+ },
|
|
|
+ mouseWheel(e) {
|
|
|
+ e.preventDefault();
|
|
|
+
|
|
|
+ if (e.wheelDeltaY < 0) {
|
|
|
+ this.toMagnify();
|
|
|
+ } else {
|
|
|
+ this.toShrink();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ setStyleTransform() {
|
|
|
+ const { scale, rotate } = this.transform;
|
|
|
+ this.styles.transform = `scale(${scale}, ${scale}) rotate(${rotate}deg)`;
|
|
|
+ },
|
|
|
+ toOrigin() {
|
|
|
+ this.transform.scale = 1;
|
|
|
+ this.setStyleTransform();
|
|
|
+ this.resizeImage();
|
|
|
+ },
|
|
|
+ toMagnify() {
|
|
|
+ const scale = (this.transform.scale * 1.2).toFixed(2);
|
|
|
+ this.transform.scale = scale >= this.maxScale ? this.maxScale : scale;
|
|
|
+ this.setStyleTransform();
|
|
|
+ },
|
|
|
+ toShrink() {
|
|
|
+ const scale = (this.transform.scale * 0.75).toFixed(2);
|
|
|
+ this.transform.scale = scale <= this.minScale ? this.minScale : scale;
|
|
|
+ this.setStyleTransform();
|
|
|
+ },
|
|
|
+ toRotate() {
|
|
|
+ this.transform.rotate = this.transform.rotate + 90;
|
|
|
+ this.setStyleTransform();
|
|
|
+ // 调整图片尺寸
|
|
|
+ const { naturalWidth, naturalHeight } = this.$refs.PreviewImgDetail;
|
|
|
+ const imageSize = this.getImageSizePos({
|
|
|
+ win: {
|
|
|
+ width: this.$refs.ReviewBody.clientWidth,
|
|
|
+ height: this.$refs.ReviewBody.clientHeight,
|
|
|
+ },
|
|
|
+ img: {
|
|
|
+ width: naturalWidth,
|
|
|
+ height: naturalHeight,
|
|
|
+ },
|
|
|
+ rotate: this.transform.rotate,
|
|
|
+ });
|
|
|
+
|
|
|
+ this.styles = Object.assign(this.styles, {
|
|
|
+ width: imageSize.width + "px",
|
|
|
+ height: imageSize.height + "px",
|
|
|
+ top: imageSize.top + "px",
|
|
|
+ left: imageSize.left + "px",
|
|
|
+ });
|
|
|
+ // 360度无缝切换到0度
|
|
|
+ if (this.transform.rotate >= 360) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.nosition = true;
|
|
|
+ this.transform.rotate = 0;
|
|
|
+ this.setStyleTransform();
|
|
|
+ setTimeout(() => {
|
|
|
+ this.nosition = false;
|
|
|
+ }, 100);
|
|
|
+ }, 200);
|
|
|
+ // 200ms当次旋转动画持续时间
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|