From 0895b61ccbac13e04bf6b3dfd8162518f1eb250b Mon Sep 17 00:00:00 2001 From: chenjiajian <770230504@qq.com> Date: Wed, 29 Mar 2023 19:31:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=9B=BE=E7=89=87=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/icon/svg.js | 15 ++- src/image/preview.js | 266 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 src/image/preview.js diff --git a/src/icon/svg.js b/src/icon/svg.js index bb45ddc..ff0d112 100644 --- a/src/icon/svg.js +++ b/src/icon/svg.js @@ -155,7 +155,20 @@ const SVG_PATH = { wallet: 'M384.5 682.6V341.4c0-47 39.4-85.4 88.5-85.4h408.1v-42.6c0-47-39.2-85.4-87.6-85.4H155.2c-49.1 0-91.2 37-91.2 84v600c0 47 42.1 84 91.2 84h638.1c48.7 0 87.6-38.4 87.6-85.4V768H472.7c-48.9 0-88.2-38.4-88.2-85.4zM448 355.7v312.6c0 19.6 16.8 35.7 37.4 35.7h437.2c20.6 0 37.4-16.1 37.4-35.7V355.7c0-19.6-16.8-35.7-37.4-35.7H485.4c-20.6 0-37.4 16.1-37.4 35.7z m195.9 227.4c-43 2.7-78.4-32.8-75.8-75.8 2.2-35.4 31-64.2 66.6-66.7 43-2.7 78.4 32.8 75.8 75.8-2.5 35.7-31.2 64.5-66.6 66.7z', windows: - 'M431.2 491.5H64V187.3l367.2-50.6v354.8z m0 395.8L64 836.7V536.8h367.2v350.5zM960 491.5H471.6V131.3L960 64v427.5z m0 468.5l-488.4-67.3V536.8H960V960z' + 'M431.2 491.5H64V187.3l367.2-50.6v354.8z m0 395.8L64 836.7V536.8h367.2v350.5zM960 491.5H471.6V131.3L960 64v427.5z m0 468.5l-488.4-67.3V536.8H960V960z', + zoomOut: + 'm795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704zM352 448h256a32 32 0 0 1 0 64H352a32 32 0 0 1 0-64z', + zoomIn: + 'm795.904 750.72 124.992 124.928a32 32 0 0 1-45.248 45.248L750.656 795.904a416 416 0 1 1 45.248-45.248zM480 832a352 352 0 1 0 0-704 352 352 0 0 0 0 704zm-32-384v-96a32 32 0 0 1 64 0v96h96a32 32 0 0 1 0 64h-96v96a32 32 0 0 1-64 0v-96h-96a32 32 0 0 1 0-64h96z', + + refreshRight: + 'M784.512 230.272v-50.56a32 32 0 1 1 64 0v149.056a32 32 0 0 1-32 32H667.52a32 32 0 1 1 0-64h92.992A320 320 0 1 0 524.8 833.152a320 320 0 0 0 320-320h64a384 384 0 0 1-384 384 384 384 0 0 1-384-384 384 384 0 0 1 643.712-282.88z', + refreshLeft: + 'M289.088 296.704h92.992a32 32 0 0 1 0 64H232.96a32 32 0 0 1-32-32V179.712a32 32 0 0 1 64 0v50.56a384 384 0 0 1 643.84 282.88 384 384 0 0 1-383.936 384 384 384 0 0 1-384-384h64a320 320 0 1 0 640 0 320 320 0 0 0-555.712-216.448z', + fullScreen: + 'm160 96.064 192 .192a32 32 0 0 1 0 64l-192-.192V352a32 32 0 0 1-64 0V96h64v.064zm0 831.872V928H96V672a32 32 0 1 1 64 0v191.936l192-.192a32 32 0 1 1 0 64l-192 .192zM864 96.064V96h64v256a32 32 0 1 1-64 0V160.064l-192 .192a32 32 0 1 1 0-64l192-.192zm0 831.872-192-.192a32 32 0 0 1 0-64l192 .192V672a32 32 0 1 1 64 0v256h-64v-.064z', + scaleToOriginal: + 'M813.176 180.706a60.235 60.235 0 0 1 60.236 60.235v481.883a60.235 60.235 0 0 1-60.236 60.235H210.824a60.235 60.235 0 0 1-60.236-60.235V240.94a60.235 60.235 0 0 1 60.236-60.235h602.352zm0-60.235H210.824A120.47 120.47 0 0 0 90.353 240.94v481.883a120.47 120.47 0 0 0 120.47 120.47h602.353a120.47 120.47 0 0 0 120.471-120.47V240.94a120.47 120.47 0 0 0-120.47-120.47zm-120.47 180.705a30.118 30.118 0 0 0-30.118 30.118v301.177a30.118 30.118 0 0 0 60.236 0V331.294a30.118 30.118 0 0 0-30.118-30.118zm-361.412 0a30.118 30.118 0 0 0-30.118 30.118v301.177a30.118 30.118 0 1 0 60.236 0V331.294a30.118 30.118 0 0 0-30.118-30.118zM512 361.412a30.118 30.118 0 0 0-30.118 30.117v30.118a30.118 30.118 0 0 0 60.236 0V391.53A30.118 30.118 0 0 0 512 361.412zM512 512a30.118 30.118 0 0 0-30.118 30.118v30.117a30.118 30.118 0 0 0 60.236 0v-30.117A30.118 30.118 0 0 0 512 512z' } export default SVG_PATH diff --git a/src/image/preview.js b/src/image/preview.js new file mode 100644 index 0000000..9489c06 --- /dev/null +++ b/src/image/preview.js @@ -0,0 +1,266 @@ +/** + * {图片预览组件} + * @author chensbox + * @date 2023/03/06 15:17:25 + */ + +import { css, html, Component, styleMap, bind, unbind } from '@bd/core' +import '../icon/index.js' +class ImagePreview extends Component { + static props = { + list: { + type: Array, + default: [], + attribute: false + }, + visible: false, + maxZoom: 3, + minZoom: 1 / 3 + } + active = 0 + static styles = css` + :host { + z-index: 1000; + position: fixed; + display: none; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.5); + } + :host([visible]) { + display: block; + } + .wrapper { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + } + img { + user-select: none; + max-height: 100%; + max-width: 100%; + &.show { + display: block; + } + &.hide { + display: none; + } + } + .toggle-btn { + user-select: none; + z-index: 100; + cursor: pointer; + position: absolute; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.8; + width: 44px; + height: 44px; + font-size: 24px; + color: #fff; + background-color: #606266; + border-color: #fff; + border-radius: 50%; + --size: 22px; + } + .left, + .right { + top: 50%; + transform: translateY(-50%); + } + .left { + left: 5%; + } + .right { + right: 5%; + } + .close { + top: 5%; + right: 5%; + } + .tools-bar { + display: flex; + align-items: center; + justify-content: space-around; + position: absolute; + bottom: 30px; + left: 50%; + width: 282px; + height: 44px; + padding: 0 23px; + background-color: #606266; + border-color: #fff; + color: #e5e5e5; + border-radius: 22px; + transform: translateX(-50%); + --size: 22px; + wc-icon { + cursor: pointer; + } + } + ` + pre() { + this.toggleImage(this.active - 1) + } + next() { + this.toggleImage(this.active + 1) + } + toggleImage(index) { + this.active = index + if (this.active < 0) { + this.active = this.list.length - 1 + } + if (this.active > this.list.length - 1) { + this.active = 0 + } + this.resetState() + } + zoomIn() { + this.#state.duration = 0.2 + this.setZoom(this.#state.scale * 1.2) + } + zoomOut() { + this.#state.duration = 0.2 + this.setZoom(this.#state.scale / 1.2) + } + setZoom(val) { + const { maxZoom, minZoom } = this + val = Math.max(val, minZoom) + val = Math.min(val, maxZoom) + val = val.toFixed(2) + this.#state.scale = val + this.$requestUpdate() + } + resetState() { + this.#setState({ + scale: 1, + rotate: 0, + duration: 0, + x: 0, + y: 0 + }) + this.$refs.resetBtn.name = + this.$refs.resetBtn.name === 'fullScreen' + ? 'scaleToOriginal' + : 'fullScreen' + this.$requestUpdate() + } + rotateLeft() { + this.setRotate(this.#state.rotate - 90) + } + rotateRight() { + this.setRotate(this.#state.rotate + 90) + } + setRotate(val) { + this.#setState({ + duration: 0.2, + rotate: val + }) + } + + close() { + this.visible = false + } + #state = { + scale: 1, + rotate: 0, + duration: 0.2, + x: 0, + y: 0 + } + #setState(data) { + Object.assign(this.#state, data) + this.$requestUpdate() + } + mounted() { + this.$on('wheel', e => { + e.preventDefault() + let { scale } = this.#state + this.#setState({ + duration: 0 + }) + scale = e.wheelDelta > 0 ? +scale + 0.08 : scale - 0.08 + this.setZoom(scale) + }) + + bind(this.$refs.images, 'mousedown', e => { + let { clientX: startX, clientY: startY } = e + let { x, y } = this.#state + const onmousemove = bind(document, 'mousemove', e => { + e.preventDefault() + let { clientX, clientY } = e + let deltaX = clientX - startX + let deltaY = clientY - startY + + this.#setState({ + x: deltaX + x, + y: deltaY + y + }) + }) + const onmouseup = bind(document, 'mouseup', _ => { + unbind(document, 'mousemove', onmousemove) + unbind(document, 'mouseup', onmouseup) + }) + }) + } + render() { + let { scale, rotate, duration, x, y } = this.#state + let styles = styleMap({ + transform: `scale(${scale}) rotate(${rotate}deg) `, + transition: `transform ${duration}s ease-in-out` + }) + let translate = styleMap({ + transform: `translate(${x}px, ${y}px)` + }) + return html` +
+
+ +
+
+ +
+
+ +
+
+ ${this.list.map( + (url, index) => + html`` + )} +
+
+ + + + + +
+
+ ` + } +} +ImagePreview.reg('image-preview') +const instance = new ImagePreview() +document.body.appendChild(instance) + +window.imagePreview = function (list) { + instance.list = list + instance.visible = true + return instance +}