├── .gitignore
├── README.md
├── babel.config.js
├── examples
├── App.vue
└── main.js
├── index.html
├── lib
└── vue3-preview-image.min.js
├── package.json
├── src
├── assets
│ ├── add.png
│ ├── arrow-left.png
│ ├── arrow-right.png
│ ├── close.png
│ ├── real-size.png
│ ├── reduce.png
│ ├── refresh-left.png
│ └── refresh-right.png
├── index.js
└── index.vue
├── webpack.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue3-preview-image
2 |
3 | 一个基于 vue3 的图片预览插件,可以缩放图片,移动图片,旋转图片,目前只支持 pc 端。
4 |
5 | 因为之前做管理后台时,经常有图片需要预览,使用 element 的图片预览必须基于它的 image 组件,
6 | 我觉得不够方便,所以模仿它的样式封装了这个图片预览插件,可在任何 vue3 的 pc 项目使用。
7 |
8 | 该预览插件使用非常简单、方便!
9 |
10 | 如果您使用过程中发现有问题或者可优化的地方都果断提出来!
11 |
12 | 如果对您有帮助,麻烦给个 Star!
13 |
14 | [github]: https://github.com/zhangchuqiang/vue3-preview-image
15 |
16 | ### 当前插件不再维护,请使用新插件[v-preview-image](https://github.com/zhangchuqiang/v-preview-image)。新插件功能一致,使用 ts 编写,且增加了 vue2 版本。
17 |
18 | ## npm 安装
19 |
20 | ```bash
21 | npm install vue3-preview-image -S
22 | ```
23 |
24 | ## 在 main.js 引入
25 |
26 | ```javascript
27 | import vue3PreviewImage from 'vue3-preview-image'
28 | app.use(vue3PreviewImage)
29 | ```
30 |
31 | ## 调用方式
32 |
33 | 可在模板中直接调用
34 |
35 | ```html
36 |
37 | ```
38 |
39 | 也可在 js 中通过实例调用:
40 |
41 | ```javascript
42 | this.$preview(current, list, key)
43 | ```
44 |
45 | 组合式 api 中引入方法调用
46 |
47 | ```javascript
48 | import { preview } from 'vue3-preview-image'
49 | preview(current, list, key)
50 | ```
51 |
52 | | 参数 | 说明 | 类型 |
53 | | ------- | ------------------------------------------------------------------------------------- | ------------- |
54 | | current | 当前预览的图片索引或者 url | String/Number |
55 | | list | 需要预览的图片数组,非必传。如果不传的话,current 必须为 url,不能为索引。 | Array |
56 | | key | 如果 list 里面的 item 是图片的 url 则不需要,如果是对象的话,需传图片的在对象中的 key | String |
57 |
58 | 关闭预览
59 |
60 | ```javascript
61 | import { closePreview } from 'vue3-preview-image'
62 | closePreview()
63 | ```
64 |
65 | 修改默认配置
66 |
67 | ```javascript
68 | // 方式一:引入方法传入配置
69 | import { setPreviewDefaultOptions } from 'vue3-preview-image'
70 |
71 | setPreviewDefaultOptions({
72 | enabledMaskClose: false, // 是否开启点击遮罩关闭(默认为true)
73 | enabledEscClose: false, // 是否开启esc按键关闭(默认为true)
74 | enabledMouseZoom: false, // 是否开启鼠标滚轮缩放(默认为true)
75 | activeColor: 'green' // 预览图中选中图片的背景颜色(默认为rgba(239, 84, 78, 0.7))
76 | })
77 |
78 | // 方式二:在app.use时传入配置
79 | import vue3PreviewImage from 'vue3-preview-image'
80 | app.use(vue3PreviewImage, { activeColor: '#ff0033' })
81 | ```
82 |
83 | ### 示例
84 |
85 | ```html
86 |
87 |
88 |
示例:
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
139 | ```
140 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | '@babel/preset-env',
5 | {
6 | targets: {
7 | chrome: '49',
8 | ios: '10'
9 | }
10 | }
11 | ]
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/examples/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
示例:
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
54 |
--------------------------------------------------------------------------------
/examples/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | import Vue3PreviewImage, { setPreviewDefaultOptions } from '../src/index'
4 |
5 | createApp(App).use(Vue3PreviewImage).mount('#app')
6 |
7 | setPreviewDefaultOptions({
8 | enabledMaskClose: false, // 开启点击遮罩关闭
9 | enabledEscClose: false, // 开启esc按键关闭
10 | enabledMouseZoom: false, // 开启鼠标滚轮缩放
11 | activeColor: 'green' // 预览图中选中图片的背景颜色
12 | })
13 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= htmlWebpackPlugin.options.title %>
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/vue3-preview-image.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("vue")):"function"==typeof define&&define.amd?define("Vue3PreviewImage",["vue"],t):"object"==typeof exports?exports.Vue3PreviewImage=t(require("vue")):e.Vue3PreviewImage=t(e.vue)}(self,(function(e){return(()=>{"use strict";var t={393:(e,t,n)=>{n.d(t,{Z:()=>l});var r=n(81),o=n.n(r),i=n(645),a=n.n(i)()(o());a.push([e.id,".preview-wrap[data-v-57b725c0] {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 99999;\n background: rgba(0, 0, 0, 0.5);\n user-select: none;\n}\n.preview-wrap li[data-v-57b725c0] {\n list-style: none;\n}\n.preview-wrap .preview[data-v-57b725c0] {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100vw;\n height: 100vh;\n}\n.preview-wrap .preview-content[data-v-57b725c0] {\n position: relative;\n cursor: move;\n transition: 0.2s transform;\n max-height: 100vh;\n}\n.preview-wrap .preview-footer[data-v-57b725c0] {\n position: absolute;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n}\n.preview-wrap .preview-footer-tools[data-v-57b725c0] {\n display: flex;\n justify-content: center;\n}\n.preview-wrap .preview-footer-tools li[data-v-57b725c0] {\n margin-right: 10px;\n padding: 10px;\n border-radius: 50%;\n background: rgba(110, 110, 110, 0.7);\n cursor: pointer;\n}\n.preview-wrap .preview-footer-tools li[data-v-57b725c0]:active {\n filter: brightness(0.8);\n}\n.preview-wrap .preview-footer-tools li[data-v-57b725c0]:hover {\n filter: brightness(1.2);\n}\n.preview-wrap .preview-footer-tools li > img[data-v-57b725c0] {\n display: block;\n width: 30px;\n height: 30px;\n}\n.preview-wrap .preview-footer-tools li:hover i[data-v-57b725c0] {\n color: #ef544e;\n}\n.preview-wrap .preview-footer-thumbs[data-v-57b725c0] {\n margin-top: 20px;\n max-width: 700px;\n overflow-x: auto;\n white-space: nowrap;\n}\n.preview-wrap .preview-footer-thumbs .thumb-item[data-v-57b725c0] {\n padding: 10px;\n margin-right: 10px;\n display: inline-block;\n background: rgba(102, 102, 102, 0.7);\n border-radius: 5px;\n cursor: pointer;\n}\n.preview-wrap .preview-footer-thumbs .thumb-item img[data-v-57b725c0] {\n width: 60px;\n height: 60px;\n object-fit: cover;\n}\n.preview-wrap .preview-footer-thumbs[data-v-57b725c0]::-webkit-scrollbar {\n height: 10px;\n}\n.preview-wrap .preview-footer-thumbs[data-v-57b725c0]::-webkit-scrollbar-thumb {\n border-radius: 10px;\n -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);\n background: #d2d2d2;\n cursor: pointer;\n}\n.preview-wrap .preview-footer-thumbs[data-v-57b725c0]::-webkit-scrollbar-track {\n border-radius: 10px;\n background: #fff;\n}\n.preview-wrap .preview .close-icon[data-v-57b725c0] {\n padding: 10px;\n position: absolute;\n top: 30px;\n right: 30px;\n border-radius: 50%;\n background: rgba(110, 110, 110, 0.7);\n cursor: pointer;\n}\n.preview-wrap .preview .close-icon > img[data-v-57b725c0] {\n display: block;\n width: 30px;\n height: 30px;\n}\n.preview-wrap .preview .close-icon[data-v-57b725c0]:active {\n filter: brightness(0.8);\n}\n.preview-wrap .preview .close-icon[data-v-57b725c0]:hover {\n filter: brightness(1.2);\n}\n",""]);const l=a},645:e=>{e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",r=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),r&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,o,i){"string"==typeof e&&(e=[[null,e,void 0]]);var a={};if(r)for(var l=0;l0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=i),n&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=n):c[2]=n),o&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=o):c[4]="".concat(o)),t.push(c))}},t}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var t=[];function n(e){for(var n=-1,r=0;r{var t={};e.exports=function(e,n){var r=function(e){if(void 0===t[e]){var n=document.querySelector(e);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}t[e]=n}return t[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(n)}},216:e=>{e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var r="";n.supports&&(r+="@supports (".concat(n.supports,") {")),n.media&&(r+="@media ".concat(n.media," {"));var o=void 0!==n.layer;o&&(r+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),r+=n.css,o&&(r+="}"),n.media&&(r+="}"),n.supports&&(r+="}");var i=n.sourceMap;i&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(i))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}},744:(e,t)=>{t.Z=(e,t)=>{const n=e.__vccOpts||e;for(const[e,r]of t)n[e]=r;return n}},748:t=>{t.exports=e}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,exports:{}};return t[e](i,i.exports,r),i.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{r.r(o),r.d(o,{closePreview:()=>H,default:()=>R,preview:()=>Z,setPreviewDefaultOptions:()=>T});var e=r(748),t=t=>((0,e.pushScopeId)("data-v-57b725c0"),t=t(),(0,e.popScopeId)(),t),n=["src"],i={class:"preview-footer-tools"},a=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAA80lEQVRoQ+3YwQrDMAwD0PrL1355RkoPpaTgYknG4F52yYKelZUw24o/Vjz/1oDsBruBbiA4gT5CwQGGv94NhEcY3EDawBhjn3nN7PxEPDLAFf53hT5QCAngEX4a6gCY4c/jiDiHb3uww1MBivA0gCo8BbAIv5vZwTqq0N+AOjy0gYzwMEBWeAggM3wYkB2eAYBdEbxvrfBbSPnOX6HCgLlpJgICyETAAFkIKCADAQeoERSAEkEDqBBUgAJBB7AREsACAbtyyAA3RM0/tryXs6/rpA18DedZ3wDPlJhrugHmdD17dwOeKTHXdAPM6Xr2Lt/AH0f9gDGCNz2CAAAAAElFTkSuQmCC"},null,-1)))],l=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADC0lEQVRoQ+2YzYtNcRjHP98/wCBKokzEiNl5yUaZFCJkY2Eh8rJAFmQzFl7CKIqMUKORIgvlvbCQyYLIToOYjZewQAallB49+Z06jblz7+/ec7i3zlOn2zn3d36/5/N8fy/Pc0SDmxrcfwqA/61goUChQI0RKKZQTADNbDTQKqkn5r2h2v4zBcxsPbADmALskbQ7C4jcAcxsLNAFLAkO3wW2SHpa9wBmtgtIIv0T2AsclPQrC+e9j1wUCFF/AEwIjt4EDkny6GdqmQOY2TSgN3jZDxwFngMfgPuSXInMLA+AeUCpSD8DzgGnJH3OgiJzAHfKzLqBtcBl4A0wBpgJTApOu0Idks7XCpEXgO88vsuMADZLOhHApvoO5M+C412SNtYCkQtAcLYd2A+8BuZL6kscNbPVwNlw3yOprVqI3AACxCNgFtAtaV3aSTObATwOzzZJOlkNRN4APpXeBcdWSro4AGI48BBoAZZKuhELkStAUMEPMj/QeiW1DnTQzGYHiOuSltUdQIA4AvSXyn/M7B4wF1gsyQ+9ii13BSrxxMy2A4eBTklbK3knaVMvAMOAr0CfpMkNBxCm2S1gIdAk6VulEHWhQAA4DfhW2yLpRSMCJLtVW0zFVk8KnAHWNLICnsF6Jtt4a8DMxgFvSx12Q62HuphCZubZ6XHggKSdlS5gbxcNYGa+2D5J6owZqFRbM2vySg2YDiySdDum32oALAywQtKVmMEGaxsC4rnSBUmrYvurBmAfkMg8UtKX2EGT9ma2AEgiPkeSZ6ZRFg0QDp0kz/fbZkmvokb9U3ami/92SR2xfVS1BlLR81p3fLiveO6GOb8tpNj+ek1f6apSIAXhU8mnlNs14Kr/Svo4MJpm1gwsBzaEBetN/ipyYlWoCSBMJ194HlEvEd1+AC89swSehI9b7rwfUondAY5JcuiarGaAlBr+dcGvBGQwx7xYuSTJE7dMLDOAFMhEILlGAe9DXexf5b5n4nWqk8wBsnawXH8FQLkI5f1/oUDeES7Xf6FAuQjl/X/DK/AbtZPzMdM3hhkAAAAASUVORK5CYII="},null,-1)))],s=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAA2klEQVRoQ+2SwQnCUBAF36tA67EAQdCjlViHlXhUECzAerSCL1awKxMIwZfrz06yM99a+OOF/7+ywNwFUyAFoIFcISgQj6cAVggBKQAF4vEUwAohIAWgQDyeAlghBKQAFIjH/6fAGOOIdf0AsH3pvN4qMMa4Stp3gBO+c7N9qHjdBV6SVhVs4vO37XXF7C6wkXSStJV0r6DwfCfpIels+1mxWgtUkDnPs8Cc9r/fToEUgAZyhaBAPJ4CWCEEpAAUiMdTACuEgBSAAvF4CmCFEJACUCAeTwGsEAI+mZoVMWVj79AAAAAASUVORK5CYII="},null,-1)))],A=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAB0UlEQVRoQ+2ZMUsdQRSFv1OlMZAfkE5bIRgrm2ijYG/aWCRNUEggffQXJBBtBEHbhNSBNFpZxRAQLC38BSnSWB0Z2CeTl6fsvLfzdOJMt+ydM/fcc/fM7qwofKjw/KkEblvBqkBVYMQKDGwh29PAM+AJMDniGqNOPwV+AceSfvaD/UPA9iLwFZgYdeWO518A7yRtxbh/EbC9BnyKAs6A844TSYV7DExFk5Ykfe9dXxGwPQMcAQ+am7OSjlNXyxFvewX43GD/AeYknYTrmMArYKcJei7pS45khsW0/RT40cxf77VSTGAbeA18k7Q87EI559k+AOaBXUkv+xXo3dyUtJEzkWGxbYe83gOHkhbuNwHbq8BDSbFrJRc3BaczBWyHPgwtF8aCpMPkzIFUnEqgV+XUyl2nTirOWBWw/Qh40SS/L+l3P5G7TuAN8KFJ+q2kj5VAV/tAG+mbFgpWG8ZecS3UxlbbFCLGGetDXDyB6kIDJBxrC9ku3kbDRlZdqLrQIDtM9e879zIXEkr5ELlpT0jB6cyF2mxSOWL+ewLFH6sUf7BV9tFi4yzlHu5GH+zlHq9HJMr9wZHDv3Ni1r+UOavbBrsq0KZKOWOqAjmr2wb7Ev2uGk/D5C02AAAAAElFTkSuQmCC"},null,-1)))],c=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABIklEQVRoQ+1Xu60CMRCcKQBEQgEkRGQUAAkpvVABUAZ1kJEAOcEr4cUveQHki5AuAImT16wtdNIQnneHnY99PqLjP3Z8fojAtx2UA3IgqIAiFBQw3F7VATM7AhiSnIQnbQGoRsDM1gA2zf9uSG5rkBCBNlXlgDNvipAi5IxKW5kipAgpQkEFOhEhM+sBmGZynT3fhQCcM/svJG+pHtcpZGYHAIsUWOH1PcllCtNL4O9xLU6BFV7/JTlKYXoJjAHsUmBv1ufNs9MHvSuSP6k+F4EUyLt13UadqsmBTrwHnG6+lGkPOFXTHtAecEZFX2S5QukUcipW8xQaAPhv5uiTvDpnyiqrRiBrikCxCATEK9IqB4rIGACRAwHxirTKgSIyBkDu/L2YMUQkwrYAAAAASUVORK5CYII="},null,-1)))],d=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADI0lEQVRoQ+2YW4hOURTHf/+UUqSQIpfIKDN5mygPMilDuUQoUSL3mLwol4mZh5lH5ZpGU6I8KA8ooWTKi2I8CJGI8EDxoDwvrWkfHZrp+/a5zDdT36qv0z7f3uv8/+u/1957bTHKTaMcP3UCtVawrkBdgZwRqE+hdADNbBnwQtLPnIGtenhhCphZB3AKeAV0S7peNYocHYsk0AicB1oCnmuByJsc+CoOLYyAf8nMxgBHgZPAWOB7IHGmIpKMHQolkGAwM1fhCLAqvLsXiDzOiHPIYYUTMDOP/ApgLjAJOAxMDAhaJPUVSaIwAmbmYPcB24AFQ4AcmQTMbCtwDGgKwN8Dz4BvwExgPXBJ0v4io+++citgZj3A7gDsgq9EkgZWHjM7APi7j8BSSZ9HFAEzewT45uW2XdLVVCLPAx4Cs4A9ki4XDT6XAmbm0+FiANUsqf+/XbkX2AnclLSxDPCZCZjZauBOADVHkk+Rv2Zmm4AbwO8wdZ6PNAK3gTXAXkmeA/9YamqdkNRdFvhMCpiZb053gX5JzYOBC+eiRkmbywSflcBZ4BDQJulc2QAr+Y9eRs3sHeArzOThPDYPRSSKgJlNAH4B9yWtrBSd4fg/lsB84C3QK2nXcACs9I1YAr5p+ebVKckLmJpbLIFEgSuSdtQcfexZKJUDfZKSyqumPKIUcKRm9jKcOmdI+lpT9LEKBAJdwHHgoCQ/adbUsijQCniJ6LcPSyT5sprbQk3RELs4RBMIKviVyRagQ1JnXvRm1gYMFP6SojBFdU6Amtli4Elot0p6kJWEmU0NlZu76JLUHuMrE4GggpeQyUmzSdLrmA8HH7NDtebNp5IWxfrITCAASG7jvOlT6XS1OWFmSS752C+SvHaOtlwEAomkePGmJ7aXjrf+L3JC3ynAWmBdePrrdkm+smWy3AQCMAflibg8hcLvf7xS+wQsDCfYBmBc6OMlqCuW6w61EAKp5PYD3obUjdxgUXXgPYNVclkkKJRAish43yOA6cA04AfwwX+S/FmYlUKgMHRVOKoTqCJIpXapK1BqeKtwXlegiiCV2mXUK/AHaODuMa3oHxAAAAAASUVORK5CYII="},null,-1)))],p=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABS0lEQVRoQ+3YIW8CQRAF4Le/sgKBIKlAICoQCAoCgUBUVDSpqKjgX77myAiyocklO2/IJHMGcyzvm7njZq8h+dGS50cBnt3B6kB1YLACdQkNFnD469WB4RIOLuDWAZKHKUtr7fYZdbgALPy7hT5GIrwARwD7u6qHIVwAU3CSJwC7aIQbwBBnANtIhCvAEBcAb1EId4AhPgBs7hCH1tp0n7gfEoAhPgGs1QgZwBBfAF6VCCnAEN8AViqEHGCIHwBLBSIEYIhfAAtvRBjAEFcAL56IZwOGR44wAMn+EhoOf5t+3Z8sDxYk2d/ELuFDACT7v1G38HIAyf5B5hpeCiDZjxLu4WUAkv0wJwkvAZDMO06TzLuhSb2lJJl7U5/+tYoNanlfbEWMI//9RsgspAQWQFndOWtXB+ZUSXlOdUBZ3TlrVwfmVEl5TvoO/AFnAoAxEk6FgQAAAABJRU5ErkJggg=="},null,-1)))],u={key:0,class:"preview-footer-thumbs"},m=["id","onClick"],g=["src"],v=[t((()=>(0,e.createElementVNode)("img",{src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4wJK5AAABzUlEQVRoQ+3YXSsFURQG4Pf9ay79AET5KqIQUcQFR/kqQhRRRFHyH72amlPr4syxZ/aaOXOOPdcza9az1p6ZNZsYgYMjYEBCtKWLqROpE44VSMvJsZhRof5nJyStABgjORFVvoKLJXUAiORRaPxSnZC0B+AsD/7tDZF0AmA/j98JhZRFZNU5NBVyg0g6B7BrYh+TtPcqbEwpRBZFkjtE0iWAbZPlKcmDWpZTN6gnRNI1gE2T8AXJbNkGH6U74QmRdAdgzWR7RXInOPv8xMqI2KUl6QFA9qbrHjckt8oCsvOjEFUhkp4ALJmE70muVwG4IMpCJL0AWDAJP5JcrQpwQ4RCJL0BmDUJP5NcjgG4Iv6CSPoAMG0SfiW5GAtwRxRBAPwAmDQJv5Oc8wDUgiiA2Hw/Sc54AWpD9IF8kZzyBCREv2r2GEuGazn1mquG6sHuNxgOxSs2ZLJt9ccuBNB9KFo5dpQBGEh7BsAqAAMZ/CgeAzCQwf0UeQAMpPnfU0+AgTS3UVAHwECa2bKRtAHgNr+x256TgdS/eZZPp/MAxr13/wyk3m1M7xHaK170bodXIjFxEiKmep7Xpk54VjMmVupETPU8r02d8KxmTKxfONz8MSXjQ6gAAAAASUVORK5CYII="},null,-1)))];const h={data:()=>({defaultOptions:{enabledMaskClose:!0,enabledEscClose:!0,enabledMouseZoom:!0,activeColor:"rgba(239, 84, 78, 0.7)"},show:!1,currentImg:"",currentIndex:0,imgList:[],imgKey:"",imgTop:0,imgLeft:0,startPageX:0,startPageY:0,imgScale:1,imgRotate:0}),watch:{show:{handler(e){e?(document.body.style.overflow="hidden",document.addEventListener("mousemove",this.preventDefault,!1),document.addEventListener("keydown",this.listenerKeydown,!1)):(document.body.style.overflow="",document.removeEventListener("mousemove",this.preventDefault,!1),document.removeEventListener("mouseup",this.clearEvent,!1),document.removeEventListener("keydown",this.listenerKeydown,!1),this.reset())},immediate:!0},currentIndex(){this.imgTop=0,this.imgLeft=0,this.imgScale=1,this.imgRotate=0}},methods:{reset(){this.imgList=[],this.currentImg="",this.currentIndex=0,this.imgKey="",this.imgTop=0,this.imgLeft=0,this.startPageX=0,this.startPageY=0,this.imgScale=1,this.imgRotate=0},handleRotate(e){"left"===e?this.imgRotate-=90:this.imgRotate+=90},handleCut(e){if(!(this.imgList.length<2)){var t=null;"last"===e&&(t=0===this.currentIndex?this.imgList.length-1:this.currentIndex-1),"next"===e&&(t=this.currentIndex===this.imgList.length-1?0:this.currentIndex+1);var n=this.imgList[t];this.currentImg=this.imgKey?n[this.imgKey]:n,this.currentIndex=t,this.handleXScroll(t)}},handleXScroll(e){e=e<4?0:e-4;var t=document.querySelector(".preview-footer-thumbs"),n=document.querySelector("#thumb-item-"+e);t.scrollLeft=n.offsetLeft},handleClickThumb(e,t){var n=this.imgKey?e[this.imgKey]:e;this.currentImg=n,this.currentIndex=t,this.handleXScroll(t)},handleClickMask(){this.defaultOptions.enabledMaskClose&&(this.show=!1)},handerMousewheel(e){this.defaultOptions.enabledMouseZoom&&(e.wheelDelta>0||e.detail>0?this.handleScale(1):(e.wheelDelta<0||e.detail<0)&&this.handleScale(2))},handleScale(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;1===e&&this.imgScale<4?this.imgScale+=.1:2===e&&this.imgScale>.5&&(this.imgScale-=.1)},handleMoveStart(e){var t=e.pageX,n=e.pageY;this.startPageX=t-this.imgLeft,this.startPageY=n-this.imgTop,document.addEventListener("mousemove",this.handleMore,!1),document.addEventListener("mouseup",this.clearEvent,!1),e.preventDefault()},listenerKeydown(e){27===e.keyCode&&this.defaultOptions.enabledEscClose&&(this.show=!1)},clearEvent(){document.removeEventListener("mousemove",this.handleMore,!1)},handleMore(e){var t=e.pageX,n=e.pageY;this.imgTop=n-this.startPageY,this.imgLeft=t-this.startPageX,e.preventDefault()},preventDefault(e){e.preventDefault()}}};var f=r(379),w=r.n(f),b=r(795),C=r.n(b),B=r(569),E=r.n(B),k=r(565),S=r.n(k),y=r(216),O=r.n(y),I=r(589),x=r.n(I),D=r(393),M={};M.styleTagTransform=x(),M.setAttributes=S(),M.insert=E().bind(null,"head"),M.domAPI=C(),M.insertStyleElement=O(),w()(D.Z,M),D.Z&&D.Z.locals&&D.Z.locals;const U=(0,r(744).Z)(h,[["render",function(t,r,o,h,f,w){return f.show?((0,e.openBlock)(),(0,e.createElementBlock)("div",{key:0,class:"preview-wrap",onMousewheel:r[12]||(r[12]=function(){return w.handerMousewheel&&w.handerMousewheel(...arguments)})},[(0,e.createElementVNode)("div",{class:"preview",onClick:r[11]||(r[11]=function(){return w.handleClickMask&&w.handleClickMask(...arguments)})},[(0,e.createElementVNode)("img",{class:"preview-content",src:f.currentImg,style:(0,e.normalizeStyle)({top:f.imgTop+"px",left:f.imgLeft+"px",transform:"scale(".concat(f.imgScale,") rotateZ(").concat(f.imgRotate,"deg)")}),onClick:r[0]||(r[0]=(0,e.withModifiers)((function(){return w.preventDefault&&w.preventDefault(...arguments)}),["stop"])),onMousedown:r[1]||(r[1]=function(){return w.handleMoveStart&&w.handleMoveStart(...arguments)})},null,44,n),(0,e.createElementVNode)("div",{class:"preview-footer",onClick:r[9]||(r[9]=(0,e.withModifiers)((function(){return w.preventDefault&&w.preventDefault(...arguments)}),["stop"]))},[(0,e.createElementVNode)("ul",i,[f.imgList.length?((0,e.openBlock)(),(0,e.createElementBlock)("li",{key:0,onClick:r[2]||(r[2]=e=>w.handleCut("last"))},a)):(0,e.createCommentVNode)("v-if",!0),(0,e.createElementVNode)("li",{onClick:r[3]||(r[3]=e=>w.handleRotate("left"))},l),(0,e.createElementVNode)("li",{onClick:r[4]||(r[4]=e=>w.handleScale(2))},s),(0,e.createElementVNode)("li",{onClick:r[5]||(r[5]=e=>f.imgScale=1)},A),(0,e.createElementVNode)("li",{onClick:r[6]||(r[6]=e=>w.handleScale(1))},c),(0,e.createElementVNode)("li",{onClick:r[7]||(r[7]=e=>w.handleRotate("right"))},d),f.imgList.length?((0,e.openBlock)(),(0,e.createElementBlock)("li",{key:1,onClick:r[8]||(r[8]=e=>w.handleCut("next"))},p)):(0,e.createCommentVNode)("v-if",!0)]),f.imgList.length?((0,e.openBlock)(),(0,e.createElementBlock)("div",u,[((0,e.openBlock)(!0),(0,e.createElementBlock)(e.Fragment,null,(0,e.renderList)(f.imgList,((t,n)=>((0,e.openBlock)(),(0,e.createElementBlock)("div",{id:"thumb-item-"+n,key:n,class:"thumb-item",style:(0,e.normalizeStyle)({background:f.currentIndex===n?f.defaultOptions.activeColor:""}),onClick:e=>w.handleClickThumb(t,n)},[(0,e.createElementVNode)("img",{src:f.imgKey?t[f.imgKey]:t},null,8,g)],12,m)))),128))])):(0,e.createCommentVNode)("v-if",!0)]),(0,e.createElementVNode)("span",{class:"close-icon",onClick:r[10]||(r[10]=e=>f.show=!1)},v)])],32)):(0,e.createCommentVNode)("v-if",!0)}],["__scopeId","data-v-57b725c0"]]),Q=U;function L(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function P(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";if(null===K&&F(),""===e||null==e)throw"Vue3PreviewImage:请传入参数";if("number"==typeof e){if(!t||!t.length)throw"Vue3PreviewImage:参数错误,第一个参数为索引时,请在第二个参数中传入数组";K.currentImg=n?t[e][n]:t[e],K.currentIndex=e}else K.currentImg=e,t.length||(K.imgList=[e]);K.imgList=t,K.imgKey=n,K.show=!0}function H(){null!==K&&K.show&&(K.show=!1)}function T(e){"[object Object]"===Object.prototype.toString.call(e)&&(null!==K?K.defaultOptions=P(P({},K.defaultOptions),e):N=e)}function F(t){var n=(0,e.createApp)(Q),r=document.createElement("div");document.body.appendChild(r),(K=n.mount(r)).defaultOptions=P(P({},K.defaultOptions),N)}})(),o})()}));
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-preview-image",
3 | "version": "1.2.3",
4 | "desription": "基于vue3的图片预览插件",
5 | "keywords": [
6 | "vue",
7 | "vue3",
8 | "image",
9 | "preview"
10 | ],
11 | "homepage": "https://github.com/zhangchuqiang/vue3-preview-image",
12 | "author": "zhangchuqiang",
13 | "private": false,
14 | "main": "lib/vue3-preview-image.min.js",
15 | "files": [
16 | "lib"
17 | ],
18 | "scripts": {
19 | "dev": "webpack serve --mode development --progress --config ./webpack.config.js",
20 | "lib": "webpack --mode production --config ./webpack.config.js"
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7.17.5",
24 | "@babel/preset-env": "^7.16.11",
25 | "babel-loader": "^8.2.3",
26 | "clean-webpack-plugin": "^4.0.0",
27 | "css-loader": "^6.6.0",
28 | "friendly-errors-webpack-plugin": "^1.7.0",
29 | "html-webpack-plugin": "^5.5.0",
30 | "less": "^4.1.2",
31 | "less-loader": "^10.2.0",
32 | "style-loader": "^3.3.1",
33 | "url-loader": "^4.1.1",
34 | "vue-loader": "^17.0.0",
35 | "vue-template-compiler": "^2.6.14",
36 | "webpack": "^5.69.1",
37 | "webpack-cli": "^4.9.2",
38 | "webpack-dev-server": "^4.7.4"
39 | },
40 | "dependencies": {
41 | "vue": "^3.2.31"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/assets/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/add.png
--------------------------------------------------------------------------------
/src/assets/arrow-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/arrow-left.png
--------------------------------------------------------------------------------
/src/assets/arrow-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/arrow-right.png
--------------------------------------------------------------------------------
/src/assets/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/close.png
--------------------------------------------------------------------------------
/src/assets/real-size.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/real-size.png
--------------------------------------------------------------------------------
/src/assets/reduce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/reduce.png
--------------------------------------------------------------------------------
/src/assets/refresh-left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/refresh-left.png
--------------------------------------------------------------------------------
/src/assets/refresh-right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhangchuqiang/vue3-preview-image/d19aa94cb52f8b4d932927d3894c657e4478e21b/src/assets/refresh-right.png
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import PreviewContent from './index.vue'
3 |
4 | let state = null // 预览组件内部的状态数据
5 | let defaultOptions = {} // 默认配置
6 |
7 | /**
8 | * 通过use调用时挂载到vue实例
9 | * @param {Object} App
10 | * @param {Object} options
11 | */
12 | export default function install(App, options = {}) {
13 | if (isObj(options)) {
14 | defaultOptions = options
15 | }
16 | initialize()
17 | App.config.globalProperties.$preview = preview
18 | }
19 | /**
20 | * @param {String|Number} current 当前预览的图片索引或者url
21 | * @param {Array} list 需要预览的图片数组 非必传 如果不传的话 current必须为url 不能为索引
22 | * @param {String} key 如果list里面的item是图片的url 则不需要,如果是对象的话,需传图片的在对象中的key。
23 | */
24 | export function preview(current = '', list = [], key = '') {
25 | if (state === null) {
26 | initialize()
27 | }
28 | if (current === '' || current === null || current === undefined) {
29 | throw 'Vue3PreviewImage:请传入参数'
30 | } else if (typeof current === 'number') {
31 | if (!list || !list.length) {
32 | throw 'Vue3PreviewImage:参数错误,第一个参数为索引时,请在第二个参数中传入数组'
33 | }
34 | state.currentImg = key ? list[current][key] : list[current]
35 | state.currentIndex = current
36 | } else {
37 | state.currentImg = current
38 | if (!list.length) {
39 | state.imgList = [current]
40 | }
41 | }
42 | state.imgList = list
43 | state.imgKey = key
44 | state.show = true
45 | }
46 |
47 | /**
48 | * 关闭预览
49 | */
50 | export function closePreview() {
51 | if (state !== null && state.show) {
52 | state.show = false
53 | }
54 | }
55 |
56 | /**
57 | * 设置预览默认配置
58 | */
59 | export function setPreviewDefaultOptions(options) {
60 | if (isObj(options)) {
61 | if (state !== null) {
62 | state.defaultOptions = { ...state.defaultOptions, ...options }
63 | } else {
64 | defaultOptions = options
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * 初始化
71 | * @param options 配置
72 | */
73 | function initialize() {
74 | const instance = createApp(PreviewContent)
75 | const box = document.createElement('div')
76 | document.body.appendChild(box)
77 | state = instance.mount(box)
78 | state.defaultOptions = { ...state.defaultOptions, ...defaultOptions }
79 | }
80 |
81 | /**
82 | * 是否是对象
83 | */
84 | function isObj(obj) {
85 | return Object.prototype.toString.call(obj) === '[object Object]'
86 | }
87 |
--------------------------------------------------------------------------------
/src/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
11 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
209 |
210 |
329 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin')
2 | const { VueLoaderPlugin } = require('vue-loader/dist/index')
3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin')
4 |
5 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
6 | const path = require('path')
7 |
8 | const config = {
9 | module: {
10 | rules: [
11 | {
12 | test: /\.js$/,
13 | exclude: /node_modules/,
14 | loader: 'babel-loader',
15 | },
16 | {
17 | test: /\.vue$/,
18 | use: ['vue-loader'],
19 | },
20 | {
21 | test: /\.css$/,
22 | use: ['style-loader', 'css-loader'],
23 | },
24 | {
25 | test: /\.less$/,
26 | use: [
27 | {
28 | loader: 'style-loader',
29 | },
30 | {
31 | loader: 'css-loader',
32 | },
33 | {
34 | loader: 'less-loader',
35 | },
36 | ],
37 | },
38 | { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader' },
39 | ],
40 | },
41 | plugins: [new CleanWebpackPlugin(), new VueLoaderPlugin()],
42 | }
43 |
44 | module.exports = (env, { mode }) => {
45 | if (mode === 'development') {
46 | config.entry = path.resolve(__dirname, './examples/main.js')
47 | config.output = {
48 | path: path.resolve(__dirname, 'dist'),
49 | filename: 'js/[name].js',
50 | }
51 | config.devServer = {
52 | port: 9527,
53 | open: false,
54 | client: {
55 | logging: 'error',
56 | overlay: {
57 | errors: true,
58 | warnings: false,
59 | },
60 | },
61 | }
62 | config.plugins = [
63 | ...config.plugins,
64 | new HtmlWebpackPlugin({
65 | template: path.resolve(__dirname, './index.html'),
66 | filename: 'index.html',
67 | title: 'Vue3PreviewImage',
68 | }),
69 | new FriendlyErrorsPlugin({
70 | compilationSuccessInfo: {
71 | messages: [`You application is running here http://localhost:${config.devServer.port}`]
72 | },
73 | }),
74 | ]
75 | config.stats = 'errors-only'
76 | }
77 | if (mode === 'production') {
78 | config.entry = path.resolve(__dirname, './src/index.js')
79 | config.output = {
80 | path: path.resolve(__dirname, './lib'),
81 | filename: 'vue3-preview-image.min.js',
82 | library: 'Vue3PreviewImage',
83 | libraryTarget: 'umd',
84 | umdNamedDefine: true,
85 | }
86 | config.externals = {
87 | vue: 'vue',
88 | }
89 | }
90 | return config
91 | }
92 |
--------------------------------------------------------------------------------