SimpleImagePreview.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <el-dialog
  3. :class="[prefixCls, 'opacity-dialog']"
  4. :visible.sync="modalIsShow"
  5. title="图片预览"
  6. fullscreen
  7. append-to-body
  8. :close-on-click-modal="false"
  9. :close-on-press-escape="false"
  10. >
  11. <div slot="title"></div>
  12. <div slot="footer"></div>
  13. <div :class="[`${prefixCls}-close`]" @click="cancel">
  14. <i class="el-icon-circle-close"></i>
  15. </div>
  16. <div :class="[`${prefixCls}-body`]" ref="ReviewBody">
  17. <div
  18. :class="[`${prefixCls}-guide`, `${prefixCls}-guide-prev`]"
  19. @click.stop="showPrev"
  20. >
  21. <i class="el-icon-arrow-left"></i>
  22. </div>
  23. <div
  24. :class="[`${prefixCls}-guide`, `${prefixCls}-guide-next`]"
  25. @click.stop="showNext"
  26. >
  27. <i class="el-icon-arrow-right"></i>
  28. </div>
  29. <div
  30. :class="[
  31. `${prefixCls}-imgs`,
  32. { [`${prefixCls}-imgs-nosition`]: nosition }
  33. ]"
  34. :style="styles"
  35. v-if="modalIsShow"
  36. >
  37. <img
  38. :key="curImage.url"
  39. :src="curImage.url"
  40. :alt="curImage.filename"
  41. ref="PreviewImgDetail"
  42. @load="reizeImage"
  43. />
  44. </div>
  45. <div :class="[`${prefixCls}-none`]" v-if="!curImage.url">
  46. <i class="el-icon-picture"></i>
  47. <p>暂无数据</p>
  48. </div>
  49. <div :class="[`${prefixCls}-loading`]" v-show="loading">
  50. <i class="el-icon-loading"></i>
  51. </div>
  52. </div>
  53. <div :class="[`${prefixCls}-footer`]">
  54. <ul>
  55. <li title="旋转" @click.stop="toRotate">
  56. <i class="el-icon-refresh-right"></i>
  57. </li>
  58. </ul>
  59. </div>
  60. </el-dialog>
  61. </template>
  62. <script>
  63. const prefixCls = "cc-image-preview";
  64. export default {
  65. name: "simple-image-preview",
  66. props: {
  67. curImage: {
  68. type: Object,
  69. default() {
  70. return {};
  71. }
  72. }
  73. },
  74. data() {
  75. return {
  76. prefixCls,
  77. modalIsShow: false,
  78. styles: { width: "", height: "", top: "", left: "", transform: "" },
  79. initWidth: 500,
  80. transform: {
  81. scale: 1,
  82. rotate: 0
  83. },
  84. loading: false,
  85. loadingSetT: null,
  86. nosition: false
  87. };
  88. },
  89. watch: {
  90. "curImage.url": {
  91. handler(val) {
  92. if (val) {
  93. this.loadingSetT = setTimeout(() => {
  94. this.loading = true;
  95. }, 300);
  96. this.styles = {
  97. width: "",
  98. height: "",
  99. top: "",
  100. left: "",
  101. transform: ""
  102. };
  103. }
  104. }
  105. }
  106. },
  107. methods: {
  108. reizeImage() {
  109. if (this.loadingSetT) clearTimeout(this.loadingSetT);
  110. const imgDom = this.$refs.PreviewImgDetail;
  111. const { naturalWidth, naturalHeight } = imgDom;
  112. const imageSize = this.getImageSizePos({
  113. win: {
  114. width: this.$refs.ReviewBody.clientWidth,
  115. height: this.$refs.ReviewBody.clientHeight
  116. },
  117. img: {
  118. width: naturalWidth,
  119. height: naturalHeight
  120. },
  121. rotate: 0
  122. });
  123. this.styles = Object.assign(this.styles, {
  124. width: imageSize.width + "px",
  125. height: imageSize.height + "px",
  126. top: imageSize.top + "px",
  127. left: imageSize.left + "px",
  128. marginLeft: "auto",
  129. transform: "none"
  130. });
  131. this.transform = {
  132. scale: 1,
  133. rotate: 0
  134. };
  135. this.loading = false;
  136. setTimeout(() => {
  137. this.nosition = false;
  138. }, 100);
  139. },
  140. getImageSizePos({ win, img, rotate }) {
  141. const imageSize = {
  142. width: 0,
  143. height: 0,
  144. top: 0,
  145. left: 0
  146. };
  147. const isHorizontal = !!(rotate % 180);
  148. const rateWin = isHorizontal
  149. ? win.height / win.width
  150. : win.width / win.height;
  151. const hwin = isHorizontal
  152. ? {
  153. width: win.height,
  154. height: win.width
  155. }
  156. : win;
  157. const rateImg = img.width / img.height;
  158. if (rateImg <= rateWin) {
  159. imageSize.height = Math.min(hwin.height, img.height);
  160. imageSize.width = Math.floor(
  161. (imageSize.height * img.width) / img.height
  162. );
  163. } else {
  164. imageSize.width = Math.min(hwin.width, img.width);
  165. imageSize.height = Math.floor(
  166. (imageSize.width * img.height) / img.width
  167. );
  168. }
  169. imageSize.left = (win.width - imageSize.width) / 2;
  170. imageSize.top = (win.height - imageSize.height) / 2;
  171. return imageSize;
  172. },
  173. cancel() {
  174. this.modalIsShow = false;
  175. this.$emit("on-close");
  176. },
  177. open() {
  178. this.modalIsShow = true;
  179. },
  180. showPrev() {
  181. this.$emit("on-prev");
  182. // this.initData();
  183. },
  184. showNext() {
  185. this.$emit("on-next");
  186. // this.initData();
  187. },
  188. // dome-move
  189. setStyleTransform() {
  190. const { scale, rotate } = this.transform;
  191. this.styles.transform = `scale(${scale}, ${scale}) rotate(${rotate}deg)`;
  192. },
  193. toRotate() {
  194. this.transform.rotate = this.transform.rotate + 90;
  195. this.setStyleTransform();
  196. // 调整图片尺寸
  197. const { naturalWidth, naturalHeight } = this.$refs.PreviewImgDetail;
  198. const imageSize = this.getImageSizePos({
  199. win: {
  200. width: this.$refs.ReviewBody.clientWidth,
  201. height: this.$refs.ReviewBody.clientHeight
  202. },
  203. img: {
  204. width: naturalWidth,
  205. height: naturalHeight
  206. },
  207. rotate: this.transform.rotate
  208. });
  209. this.styles = Object.assign(this.styles, {
  210. width: imageSize.width + "px",
  211. height: imageSize.height + "px",
  212. top: imageSize.top + "px",
  213. left: imageSize.left + "px"
  214. });
  215. // 360度无缝切换到0度
  216. if (this.transform.rotate >= 360) {
  217. setTimeout(() => {
  218. this.nosition = true;
  219. this.transform.rotate = 0;
  220. this.setStyleTransform();
  221. setTimeout(() => {
  222. this.nosition = false;
  223. }, 100);
  224. }, 200);
  225. // 200ms当次旋转动画持续时间
  226. }
  227. }
  228. }
  229. };
  230. </script>