├── .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 | 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 | 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 | 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 | --------------------------------------------------------------------------------