├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ ├── create-release.yml │ └── gh-pages.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc ├── .npmrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── commitlint.config.cjs ├── example ├── App.vue ├── index.html ├── main.ts ├── public │ └── favicon.ico ├── views │ └── example │ │ ├── ApiExample.vue │ │ ├── ComponentExample.vue │ │ ├── DirectiveExample.vue │ │ └── index.vue └── vite.config.ts ├── package.json ├── pnpm-lock.yaml ├── src ├── api.ts ├── component.vue ├── directive.ts ├── index.ts └── shims-vue.d.ts ├── tsconfig.json ├── tsconfig.node.json ├── types └── index.d.ts └── vite.config.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | public 4 | *.md 5 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@antfu", 3 | "rules": { 4 | "curly": "off", 5 | "no-console": "off", 6 | "no-unused-vars": "off", 7 | "@typescript-eslint/no-unused-vars": "off" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/create-release.yml: -------------------------------------------------------------------------------- 1 | name: CI Create Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | jobs: 8 | build: 9 | name: Create Release 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v3 14 | - name: Create Release 15 | id: create_release 16 | uses: actions/create-release@v1 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | with: 20 | tag_name: ${{ github.ref }} 21 | release_name: Release ${{ github.ref }} 22 | body: | 23 | Please refer to [CHANGELOG.md](https://github.com/mirari/v-viewer/blob/master/CHANGELOG.md) for details. 24 | draft: false 25 | prerelease: false 26 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Github Pages Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build-and-deploy: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 🛎️ 11 | uses: actions/checkout@v3 12 | - name: Install and Build 13 | run: | 14 | npm i pnpm -g 15 | pnpm i 16 | pnpm run build 17 | pnpm run preview:build 18 | - name: Deploy 🚀 19 | uses: JamesIves/github-pages-deploy-action@v4 20 | with: 21 | branch: gh-pages 22 | folder: example/dist 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /example/dist 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 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.ts": [ 3 | "eslint --fix" 4 | ], 5 | "*.vue": [ 6 | "eslint --fix" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | auto-install-peers=true 3 | strict-peer-dependencies=false 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [3.0.21](https://github.com/mirari/v-viewer/compare/v3.0.20...v3.0.21) (2024-11-02) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * fix type declaration ([e16928b](https://github.com/mirari/v-viewer/commit/e16928b3badcdbc2a79f3ab2f06a7feeb0700521)) 11 | 12 | ### [3.0.20](https://github.com/mirari/v-viewer/compare/v3.0.19...v3.0.20) (2024-09-26) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * fix package setting mistake ([6e54d96](https://github.com/mirari/v-viewer/commit/6e54d9643bc015710ca5eb1d971569c1f1336589)) 18 | 19 | ### [3.0.19](https://github.com/mirari/v-viewer/compare/v3.0.18...v3.0.19) (2024-09-26) 20 | 21 | 22 | ### Bug Fixes 23 | 24 | * fix package setting mistake ([f930882](https://github.com/mirari/v-viewer/commit/f930882443b60bd23f62c88c0634692f9237bd5c)) 25 | 26 | ### [3.0.18](https://github.com/mirari/v-viewer/compare/v3.0.17...v3.0.18) (2024-09-26) 27 | 28 | 29 | ### Bug Fixes 30 | 31 | * support iife ([02662af](https://github.com/mirari/v-viewer/commit/02662afd89f8f307a0e825fd601a710939a463d0)) 32 | 33 | ### [3.0.17](https://github.com/mirari/v-viewer/compare/v3.0.16...v3.0.17) (2024-09-26) 34 | 35 | 36 | ### Bug Fixes 37 | 38 | * fix package setting mistake ([4465979](https://github.com/mirari/v-viewer/commit/4465979cc8f07d924300cc7e802f752902f637bb)) 39 | 40 | ### [3.0.16](https://github.com/mirari/v-viewer/compare/v3.0.15...v3.0.16) (2024-09-26) 41 | 42 | ### [3.0.15](https://github.com/mirari/v-viewer/compare/v3.0.14...v3.0.15) (2024-09-26) 43 | 44 | 45 | ### Bug Fixes 46 | 47 | * fix the issue of incorrect entry reference caused by the unspecified type in package.json.[#338](https://github.com/mirari/v-viewer/issues/338) ([f493490](https://github.com/mirari/v-viewer/commit/f4934906d7c90c79571c7bf3edb160cc6b34e2f8)) 48 | 49 | ### [3.0.14](https://github.com/mirari/v-viewer/compare/v3.0.13...v3.0.14) (2024-01-06) 50 | 51 | 52 | ### Bug Fixes 53 | 54 | * update dependencies ([e9003e0](https://github.com/mirari/v-viewer/commit/e9003e0902f7cc8c0d03d9ed9b520580c263ade7)) 55 | 56 | ### [3.0.13](https://github.com/mirari/v-viewer/compare/v3.0.9...v3.0.13) (2024-01-03) 57 | 58 | 59 | ### Bug Fixes 60 | 61 | * **common:** remove unnecessary configuration to fit vite(SSR) correctly ([d8e2100](https://github.com/mirari/v-viewer/commit/d8e2100086b2058bbd8c225ddb5b990a45ea1149)) 62 | * **component:** fix the problem of not updating when changing options ([1b2e3ae](https://github.com/mirari/v-viewer/commit/1b2e3ae26b947d80cbea3f4a25ea2ccf9e59b5fd)), closes [#197](https://github.com/mirari/v-viewer/issues/197) 63 | * modify util function ([d05dd3c](https://github.com/mirari/v-viewer/commit/d05dd3c0a5096e32fce2e4f020fe8775f3dfeb7c)) 64 | 65 | ### [3.0.12](https://github.com/mirari/v-viewer/compare/v3.0.11...v3.0.12) (2024-01-03) 66 | 67 | ### [3.0.11](https://github.com/mirari/v-viewer/compare/v3.0.9...v3.0.11) (2022-10-25) 68 | 69 | 70 | ### Bug Fixes 71 | 72 | * **common:** remove unnecessary configuration to fit vite(SSR) correctly ([d8e2100](https://github.com/mirari/v-viewer/commit/d8e2100086b2058bbd8c225ddb5b990a45ea1149)) 73 | * **component:** fix the problem of not updating when changing options ([1b2e3ae](https://github.com/mirari/v-viewer/commit/1b2e3ae26b947d80cbea3f4a25ea2ccf9e59b5fd)), closes [#197](https://github.com/mirari/v-viewer/issues/197) 74 | 75 | ### [3.0.10](https://github.com/mirari/v-viewer/compare/v3.0.9...v3.0.10) (2021-09-21) 76 | 77 | 78 | ### Bug Fixes 79 | 80 | * **component:** fix the problem of not updating when changing options ([d7afcdb](https://github.com/mirari/v-viewer/commit/d7afcdbf5d597f3971e0bea43ce36f390972e312)), closes [#197](https://github.com/mirari/v-viewer/issues/197) 81 | 82 | ### [3.0.9](https://github.com/mirari/v-viewer/compare/v3.0.8...v3.0.9) (2021-06-02) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * **common:** fix dts file ([f6163ff](https://github.com/mirari/v-viewer/commit/f6163ff5b316a940d70fb842605f220b7f378416)) 88 | 89 | ### [3.0.8](https://github.com/mirari/v-viewer/compare/v3.0.7...v3.0.8) (2021-06-02) 90 | 91 | ### [3.0.7](https://github.com/mirari/v-viewer/compare/v3.0.6...v3.0.7) (2021-06-02) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * **common:** fix tsd file; update readme ([2295dcc](https://github.com/mirari/v-viewer/commit/2295dcc338dfb296f4780542c6d38921284c6c9d)) 97 | 98 | ### [3.0.6](https://github.com/mirari/v-viewer/compare/v3.0.5...v3.0.6) (2021-05-31) 99 | 100 | ### 3.0.5 (2021-05-31) 101 | 102 | 103 | ### Bug Fixes 104 | 105 | * **api:** fix type declaration ([9987966](https://github.com/mirari/v-viewer/commit/9987966db12372186adc95a5b37643c9ce1587bb)) 106 | * **common:** fix api option ([f54bcb2](https://github.com/mirari/v-viewer/commit/f54bcb266c4fa83492a9dfaa2e513960727b9873)) 107 | * **common:** fix umd build config ([3fc6477](https://github.com/mirari/v-viewer/commit/3fc64772fc7b7271f233b239c2c26d39f16d3396)) 108 | * **directive:** fix default options ([c7ffa87](https://github.com/mirari/v-viewer/commit/c7ffa87b6d9259e2f304f85467e1d5609f53e912)) 109 | 110 | ### [3.0.4](https://github.com/mirari/v-viewer/compare/v3.0.3...v3.0.4) (2021-05-30) 111 | 112 | 113 | ### Bug Fixes 114 | 115 | * **api:** fix type declaration ([9987966](https://github.com/mirari/v-viewer/commit/9987966db12372186adc95a5b37643c9ce1587bb)) 116 | 117 | ### [3.0.3](https://github.com/mirari/v-viewer/compare/v3.0.2...v3.0.3) (2021-05-30) 118 | 119 | ### [3.0.2](https://github.com/mirari/v-viewer/compare/v3.0.1...v3.0.2) (2021-05-30) 120 | 121 | 122 | ### Bug Fixes 123 | 124 | * **common:** fix api option ([f54bcb2](https://github.com/mirari/v-viewer/commit/f54bcb266c4fa83492a9dfaa2e513960727b9873)) 125 | 126 | ### [3.0.1](https://github.com/mirari/v-viewer/compare/v3.0.0...v3.0.1) (2021-05-30) 127 | 128 | 129 | ### Bug Fixes 130 | 131 | * **common:** fix umd build config ([3fc6477](https://github.com/mirari/v-viewer/commit/3fc64772fc7b7271f233b239c2c26d39f16d3396)) 132 | 133 | ## 3.0.0 (2021-05-30) 134 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 mirari 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v-viewer 2 | 3 | Image viewer component for vue, supports rotation, scale, zoom and so on, based on [viewer.js](https://github.com/fengyuanchen/viewerjs) 4 | 5 | [![npm version](https://img.shields.io/npm/v/v-viewer.svg)](https://www.npmjs.com/package/v-viewer) 6 | [![language](https://img.shields.io/badge/language-Vue3-brightgreen.svg)](https://www.npmjs.com/package/v-viewer) 7 | 8 | [![npm version](https://img.shields.io/npm/v/v-viewer/legacy.svg)](https://www.npmjs.com/package/v-viewer) 9 | [![language](https://img.shields.io/badge/language-Vue2-brightgreen.svg)](https://www.npmjs.com/package/v-viewer) 10 | 11 | [![npm download](https://img.shields.io/npm/dw/v-viewer.svg)](https://www.npmjs.com/package/v-viewer) 12 | [![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://mit-license.org/) 13 | 14 | ## [v-viewer for vue2](https://github.com/mirari/v-viewer/tree/v2) 15 | 16 | ## [Live demo](https://mirari.github.io/vue3-viewer/) 17 | 18 | ## Quick Example 19 | 20 | - [directive](https://codepen.io/mirari/pen/yLMPPWy) 21 | - [component](https://codepen.io/mirari/pen/ZEeaaWZ) 22 | - [api](https://codepen.io/mirari/pen/qBrVpNV) 23 | - [thumbnail & source](https://codepen.io/mirari/pen/Vwpryax) 24 | - [viewer callback](https://codepen.io/mirari/pen/eYveypz) 25 | - [custom toolbar](https://codepen.io/mirari/pen/ZEXqyPq) 26 | - [filter images](https://codepen.io/mirari/pen/mdWqpwa) 27 | - [change images](https://codepen.io/mirari/pen/ExWbovw) 28 | 29 | ## [中文文档](https://mirari.cc/posts/vue3-viewer) 30 | 31 | ## Installation 32 | 33 | Install from NPM 34 | 35 | ```bash 36 | npm install v-viewer viewerjs 37 | ``` 38 | 39 | ## Usage 40 | 41 | To use `v-viewer`, simply import it and the `css` file, and call `app.use()` to install. 42 | 43 | The component, directive and api will be installed together in the global. 44 | 45 | Two different API styles are both supported: **Options API** and **Composition API**. 46 | 47 | ```ts 48 | import { createApp } from 'vue' 49 | import App from './App.vue' 50 | import 'viewerjs/dist/viewer.css' 51 | import VueViewer from 'v-viewer' 52 | const app = createApp(App) 53 | app.use(VueViewer) 54 | app.mount('#app') 55 | ``` 56 | 57 | ```vue 58 | 72 | 73 | 94 | 95 | 108 | ``` 109 | 110 | ### Support UMD 111 | 112 | #### Browser 113 | 114 | ```html 115 | 116 | 117 | 118 | 119 | 122 | ``` 123 | 124 | #### CommonJS 125 | 126 | ```javascript 127 | var VueViewer = require('VueViewer') 128 | ``` 129 | 130 | #### AMD 131 | 132 | ```javascript 133 | require(['VueViewer'], function (VueViewer) {}); 134 | ``` 135 | 136 | ### Usage of directive 137 | 138 | Just add the directive `v-viewer` to any element, then all `img` elements in it will be handled by `viewer`. 139 | 140 | You can set the options like this: `v-viewer="{inline: true}"` 141 | 142 | Get the element by selector and then use `el.$viewer` to get the `viewer` instance if you need. 143 | 144 | ```vue 145 | 153 | 154 | 181 | 182 | 198 | ``` 199 | 200 | #### Directive modifiers 201 | 202 | ##### static 203 | 204 | The `viewer` instance will be created only once after the directive binded. 205 | 206 | If you're sure the images inside this element won't change again, use it to avoid unnecessary re-render. 207 | 208 | ```vue 209 |
210 | 211 |
212 | ``` 213 | 214 | ##### rebuild 215 | 216 | The `viewer` instance will be updated by `update` method when the source images changed (added, removed or sorted) by default. 217 | 218 | If you encounter any display problems, try rebuilding instead of updating. 219 | 220 | ```vue 221 |
222 | 223 |
224 | ``` 225 | 226 | ### Usage of component 227 | 228 | You can simply import the component and register it locally too. 229 | 230 | ```vue 231 | 246 | 247 | 274 | 275 | 291 | ``` 292 | 293 | #### Component props 294 | 295 | ##### images 296 | 297 | - Type: `Array` 298 | 299 | ##### trigger 300 | 301 | - Type: `Object` 302 | 303 | You can replace `images` with `trigger`, to accept any type of prop. 304 | when the `trigger` changes, the component will re-render the viewer. 305 | 306 | ```vue 307 | 308 |
309 | 310 | ``` 311 | 312 | ##### rebuild 313 | 314 | - Type: `Boolean` 315 | - Default: `false` 316 | 317 | The viewer instance will be updated by `update` method when the source images changed (added, removed or sorted) by default. 318 | 319 | If you encounter any display problems, try rebuilding instead of updating. 320 | 321 | ```vue 322 | 330 | 334 | 335 | ``` 336 | 337 | #### Component events 338 | 339 | ##### inited 340 | 341 | - viewer: `Viewer` 342 | 343 | Listen for the `inited` event to get the `viewer` instance, or use `this.refs.xxx.$viewer`. 344 | 345 | ### Usage of api 346 | 347 | > Only available in modal mode. 348 | 349 | You can call the function: `this.$viewerApi({options: {}, images: []})` to show gallery without rendering the `img` elements yourself. 350 | 351 | The function returns the current viewer instance. 352 | 353 | ```vue 354 | 360 | 361 | 405 | 406 | 441 | ``` 442 | 443 | ## Options & Methods of Viewer 444 | 445 | Refer to [viewer.js](https://github.com/fengyuanchen/viewerjs). 446 | 447 | ## Plugin options 448 | 449 | ### name 450 | 451 | - Type: `String` 452 | - Default: `viewer` 453 | 454 | If you need to avoid name conflict, you can import it like this: 455 | ```ts 456 | import { createApp } from 'vue' 457 | import 'viewerjs/dist/viewer.css' 458 | import VueViewer from 'v-viewer' 459 | import App from './App.vue' 460 | 461 | export const app = createApp(App) 462 | app.use(VueViewer, { 463 | name: 'vuer', 464 | debug: true, 465 | }) 466 | app.mount('#app') 467 | 468 | ``` 469 | 470 | ```vue 471 | 484 | 485 | 510 | 511 | 528 | ``` 529 | 530 | ### defaultOptions 531 | 532 | - Type: `Object` 533 | - Default: `undefined` 534 | 535 | If you need to set the viewer default options, you can import it like this: 536 | 537 | ```ts 538 | import { createApp } from 'vue' 539 | import 'viewerjs/dist/viewer.css' 540 | import VueViewer from 'v-viewer' 541 | import App from './App.vue' 542 | 543 | export const app = createApp(App) 544 | app.use(VueViewer, { 545 | defaultOptions: { 546 | zIndex: 9999 547 | } 548 | }) 549 | app.mount('#app') 550 | ``` 551 | 552 | And you can reset the default options at any other time: 553 | 554 | ```javascript 555 | import VueViewer from 'v-viewer' 556 | 557 | VueViewer.setDefaults({ 558 | zIndexInline: 2021, 559 | }) 560 | ``` 561 | -------------------------------------------------------------------------------- /commitlint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | } 4 | -------------------------------------------------------------------------------- /example/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 71 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | v-viewer 8 | 11 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import VueViewer from '../src' 3 | import App from './App.vue' 4 | 5 | import 'bulma' 6 | import 'viewerjs/dist/viewer.css' 7 | VueViewer.setDefaults({ 8 | zIndexInline: 2021, 9 | focus: false, 10 | }) 11 | export const app = createApp(App) 12 | // app.use(VueViewer, { 13 | // debug: true, 14 | // }) 15 | app.mount('#app') 16 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirari/vue3-viewer/8fd987af20bb7964b83f44d7f48169ac295eedc9/example/public/favicon.ico -------------------------------------------------------------------------------- /example/views/example/ApiExample.vue: -------------------------------------------------------------------------------- 1 | 2 | 53 | 54 | 92 | 93 | 116 | 117 | 122 | -------------------------------------------------------------------------------- /example/views/example/ComponentExample.vue: -------------------------------------------------------------------------------- 1 | 2 | 204 | 205 | 371 | 372 | 726 | 727 | 782 | -------------------------------------------------------------------------------- /example/views/example/DirectiveExample.vue: -------------------------------------------------------------------------------- 1 | 2 | 79 | 80 | 135 | 136 | 210 | 211 | 219 | -------------------------------------------------------------------------------- /example/views/example/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 22 | 23 | 67 | -------------------------------------------------------------------------------- /example/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | base: './', 7 | plugins: [vue()], 8 | }) 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v-viewer", 3 | "scope": "VueViewer", 4 | "version": "3.0.21", 5 | "description": "Image viewer component for vue, supports rotation, scale, zoom and so on, based on viewer.js", 6 | "author": "mirari", 7 | "license": "MIT", 8 | "homepage": "https://github.com/mirari/v-viewer#readme", 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mirari/v-viewer.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/mirari/v-viewer/issues" 15 | }, 16 | "keywords": [ 17 | "vue", 18 | "viewer", 19 | "gallery", 20 | "picture", 21 | "img", 22 | "image" 23 | ], 24 | "main": "./dist/index.umd.cjs", 25 | "module": "./dist/index.js", 26 | "unpkg": "./dist/index.iife.js", 27 | "types": "./types/index.d.ts", 28 | "type": "module", 29 | "exports": { 30 | ".": { 31 | "types": "./types/index.d.js", 32 | "import": "./dist/index.js", 33 | "require": "./dist/index.umd.cjs" 34 | } 35 | }, 36 | "files": [ 37 | "dist", 38 | "types", 39 | "README.md" 40 | ], 41 | "scripts": { 42 | "prepare": "husky install", 43 | "dev": "vite serve example --config example/vite.config.ts", 44 | "lint": "eslint .", 45 | "lint:fix": "eslint . --fix", 46 | "build": "vue-tsc --noEmit && vite build", 47 | "preview:build": "vite build example --config example/vite.config.ts", 48 | "preview:serve": "vite preview example --config example/vite.config.ts", 49 | "release": "standard-version", 50 | "publish": "npm run build && npm publish", 51 | "publish:next": "npm run build && npm publish --tag next" 52 | }, 53 | "peerDependencies": { 54 | "viewerjs": "^1.11.0", 55 | "vue": "^3.0.0" 56 | }, 57 | "dependencies": { 58 | "viewerjs": "^1.11.6", 59 | "lodash-es": "^4.17.21" 60 | }, 61 | "devDependencies": { 62 | "@antfu/eslint-config": "^0.27.0", 63 | "@commitlint/cli": "^17.1.2", 64 | "@commitlint/config-conventional": "^17.1.0", 65 | "@types/lodash-es": "^4.17.6", 66 | "@vitejs/plugin-vue": "^3.1.0", 67 | "@vue/compiler-sfc": "^3.2.26", 68 | "bulma": "^0.9.4", 69 | "eslint": "^8.26.0", 70 | "husky": "^8.0.1", 71 | "lint-staged": "^15.2.10", 72 | "sass": "^1.55.0", 73 | "standard-version": "^9.5.0", 74 | "typescript": "^4.6.4", 75 | "vite": "^3.1.0", 76 | "vue": "^3.2.37", 77 | "vue-tsc": "^0.40.4" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/api.ts: -------------------------------------------------------------------------------- 1 | import { h, render } from 'vue' 2 | import Viewer from 'viewerjs' 3 | import { assign } from 'lodash-es' 4 | 5 | export interface ViewerApiOptions { 6 | images: Array 7 | options?: Viewer.Options 8 | } 9 | 10 | const api = ({ images = [], options }: ViewerApiOptions) => { 11 | options = assign(options, { 12 | inline: false, // 只能使用modal模式 13 | }) 14 | // 创建存放viewerjs加载所需图片的占位元素,无需实际展现 15 | const token = document.createElement('div') 16 | const ViewerToken = h( 17 | 'div', 18 | { 19 | style: { 20 | display: 'none', 21 | }, 22 | class: ['__viewer-token'], 23 | }, 24 | images.map((attr) => { 25 | return h( 26 | 'img', 27 | typeof attr === 'string' ? { src: attr } : attr, 28 | ) 29 | }), 30 | ) 31 | 32 | render(ViewerToken, token) 33 | const tokenElement = token.firstElementChild as HTMLElement 34 | document.body.appendChild(tokenElement) 35 | 36 | // init viewer 37 | const $viewerJs = new Viewer(tokenElement, options) 38 | const $destroy = $viewerJs.destroy.bind($viewerJs) 39 | $viewerJs.destroy = function (): Viewer { 40 | $destroy() 41 | render(null, token) 42 | return $viewerJs 43 | } 44 | $viewerJs.show() 45 | 46 | // 关闭Viewer模态窗口时,销毁token 47 | tokenElement.addEventListener('hidden', function (this: HTMLElement) { 48 | if (this.viewer === $viewerJs) { 49 | $viewerJs.destroy() 50 | } 51 | }) 52 | 53 | return $viewerJs 54 | } 55 | 56 | export default api 57 | -------------------------------------------------------------------------------- /src/component.vue: -------------------------------------------------------------------------------- 1 | 102 | 103 | 111 | -------------------------------------------------------------------------------- /src/directive.ts: -------------------------------------------------------------------------------- 1 | import Viewer from 'viewerjs' 2 | import { debounce } from 'lodash-es' 3 | import { nextTick, watch } from 'vue' 4 | import type { Directive, DirectiveBinding, VNode } from 'vue' 5 | 6 | export type ICreateViewer = (el: HTMLElement, options: Viewer.Options, rebuild: boolean, observer: boolean) => void 7 | 8 | const directive = ({ name = 'viewer', debug = false } = {}) => { 9 | async function createViewer(el: HTMLElement, options: Viewer.Options, rebuild = false, observer = false) { 10 | await nextTick() 11 | // 如果启用了元素监听,但和上次比较没有变化,就不重新初始化或更新 12 | if (observer && !imageDiff(el)) 13 | return 14 | if (rebuild || !el[`$${name}`]) { 15 | destroyViewer(el) 16 | el[`$${name}`] = new Viewer(el, options) 17 | log('Viewer created') 18 | } 19 | else { 20 | el[`$${name}`].update() 21 | log('Viewer updated') 22 | } 23 | } 24 | 25 | function imageDiff(el: HTMLElement) { 26 | const imageContent = el.innerHTML.match(//g) 27 | const viewerImageText = imageContent ? imageContent.join('') : undefined 28 | if (el.__viewerImageDiffCache === viewerImageText) { 29 | log('Element change detected, but image(s) has not changed') 30 | return false 31 | } 32 | else { 33 | log('Image change detected') 34 | el.__viewerImageDiffCache = viewerImageText 35 | return true 36 | } 37 | } 38 | 39 | function createObserver(el: HTMLElement, options: Viewer.Options, debouncedCreateViewer: ICreateViewer, rebuild: boolean) { 40 | destroyObserver(el) 41 | const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver 42 | if (!MutationObserver) { 43 | log('Observer not supported') 44 | return 45 | } 46 | const observer = new MutationObserver((mutations) => { 47 | mutations.forEach((mutation) => { 48 | log(`Viewer mutation:${mutation.type}`) 49 | debouncedCreateViewer(el, options, rebuild, true) 50 | }) 51 | }) 52 | const config = { attributes: true, childList: true, characterData: true, subtree: true } 53 | observer.observe(el, config) 54 | el.__viewerMutationObserver = observer 55 | log('Observer created') 56 | } 57 | 58 | function createWatcher(el: HTMLElement, binding: DirectiveBinding, vnode: VNode, debouncedCreateViewer: ICreateViewer) { 59 | // const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/ 60 | // if (!binding.value || !simplePathRE.test(binding.value)) { 61 | // log('Only simple dot-delimited paths can create watcher') 62 | // return 63 | // } 64 | el.__viewerUnwatch = watch(() => binding.value, (newVal, oldVal) => { 65 | log('Change detected by watcher: ', binding.value) 66 | debouncedCreateViewer(el, newVal, true, false) 67 | }, { deep: true }) 68 | log('Watcher created, expression: ', binding.value) 69 | } 70 | 71 | function destroyViewer(el: HTMLElement) { 72 | if (!el[`$${name}`]) { 73 | return 74 | } 75 | el[`$${name}`].destroy() 76 | delete el[`$${name}`] 77 | log('Viewer destroyed') 78 | } 79 | 80 | function destroyObserver(el: HTMLElement) { 81 | if (!el.__viewerMutationObserver) { 82 | return 83 | } 84 | el.__viewerMutationObserver.disconnect() 85 | delete el.__viewerMutationObserver 86 | log('observer destroyed') 87 | } 88 | 89 | function destroyWatcher(el: HTMLElement) { 90 | if (!el.__viewerUnwatch) { 91 | return 92 | } 93 | el.__viewerUnwatch() 94 | delete el.__viewerUnwatch 95 | log('Watcher destroyed') 96 | } 97 | 98 | function log(...args: any[]) { 99 | debug && console.log(...args) 100 | } 101 | 102 | const directive: Directive = { 103 | mounted(el, binding, vnode) { 104 | log('Viewer bind') 105 | const debouncedCreateViewer = debounce(createViewer, 50) 106 | debouncedCreateViewer(el, binding.value) 107 | // 创建watch监听options表达式变化 108 | createWatcher(el, binding, vnode, debouncedCreateViewer) 109 | // 是否监听dom变化 110 | if (!binding.modifiers.static) { 111 | // 增加dom变化监听 112 | createObserver(el, binding.value, debouncedCreateViewer, binding.modifiers.rebuild) 113 | } 114 | }, 115 | unmounted(el) { 116 | log('Viewer unbind') 117 | // 销毁dom变化监听 118 | destroyObserver(el) 119 | // 销毁指令表达式监听 120 | destroyWatcher(el) 121 | // 销毁viewer 122 | destroyViewer(el) 123 | }, 124 | } 125 | 126 | return directive 127 | } 128 | 129 | export default directive 130 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { defaults } from 'lodash-es' 3 | import Viewer from 'viewerjs' 4 | import api from './api' 5 | import directive from './directive' 6 | import component from './component.vue' 7 | 8 | export interface InstallationOptions { 9 | name?: string 10 | debug?: boolean 11 | defaultOptions?: Viewer.Options 12 | } 13 | 14 | export { 15 | Viewer, 16 | api, 17 | directive, 18 | component, 19 | } 20 | 21 | export default { 22 | install(app: App, { name = 'viewer', debug = false, defaultOptions }: InstallationOptions = {}) { 23 | if (defaultOptions) { 24 | Viewer.setDefaults(defaultOptions) 25 | } 26 | 27 | app.config.globalProperties[`$${name}Api`] = api 28 | app.component(name, defaults(component, { name })) 29 | app.directive(name, directive({ name, debug })) 30 | }, 31 | setDefaults(defaultOptions: Viewer.Options) { 32 | Viewer.setDefaults(defaultOptions) 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | 7 | declare interface Window { 8 | WebKitMutationObserver: MutationObserver 9 | MozMutationObserver: MutationObserver 10 | } 11 | 12 | declare interface HTMLElement { 13 | [key: string]: any 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "jsx": "preserve", 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "lib": ["ESNext", "DOM"], 14 | "skipLibCheck": true 15 | }, 16 | "include": [ 17 | "src/**/*.ts", 18 | "src/**/*.d.ts", 19 | "src/**/*.tsx", 20 | "src/**/*.vue" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "resolveJsonModule": true, 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { App } from 'vue' 2 | import ViewerJs from 'viewerjs' 3 | import type { Directive, DefineComponent } from 'vue' 4 | 5 | declare namespace VueViewer { 6 | export interface InstallationOptions { 7 | name?: string 8 | debug?: boolean 9 | defaultOptions?: ViewerJs.Options 10 | } 11 | 12 | export interface ViewerApiOptions { 13 | images: Array 14 | options?: ViewerJs.Options 15 | } 16 | 17 | export function install(app: App, options?: InstallationOptions): void 18 | 19 | export function setDefaults(defaultOptions: ViewerJs.Options): void 20 | } 21 | 22 | export declare const Viewer: typeof ViewerJs 23 | 24 | export declare const api: (options: VueViewer.ViewerApiOptions) => ViewerJs 25 | 26 | export declare const directive: (options?: VueViewer.InstallationOptions) => Directive 27 | 28 | export declare const component: DefineComponent<{}, {}, any> 29 | 30 | export default VueViewer 31 | 32 | declare module 'vue' { 33 | interface ComponentCustomProperties { 34 | $viewerApi: typeof api 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import pkg from './package.json' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | build: { 9 | lib: { 10 | entry: 'src/index.ts', 11 | name: pkg.scope, 12 | fileName: 'index', 13 | formats: ['es', 'umd', 'iife'], 14 | }, 15 | rollupOptions: { 16 | output: { 17 | globals: { 18 | vue: 'Vue', 19 | viewerjs: 'Viewer', 20 | }, 21 | }, 22 | external: ['vue', 'viewerjs'], 23 | }, 24 | }, 25 | }) 26 | --------------------------------------------------------------------------------