完成图片预览组件
parent
bdc2653350
commit
0895b61ccb
|
@ -155,7 +155,20 @@ const SVG_PATH = {
|
||||||
wallet:
|
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',
|
'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:
|
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
|
export default SVG_PATH
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
/**
|
||||||
|
* {图片预览组件}
|
||||||
|
* @author chensbox<chensbox@foxmail.com>
|
||||||
|
* @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`
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="left toggle-btn" @click=${this.pre}>
|
||||||
|
<wc-icon name="left"></wc-icon>
|
||||||
|
</div>
|
||||||
|
<div class="right toggle-btn" @click=${this.next}>
|
||||||
|
<wc-icon name="right"></wc-icon>
|
||||||
|
</div>
|
||||||
|
<div class="close toggle-btn" @click=${this.close}>
|
||||||
|
<wc-icon name="close"></wc-icon>
|
||||||
|
</div>
|
||||||
|
<div class="images" ref="images" style=${translate}>
|
||||||
|
${this.list.map(
|
||||||
|
(url, index) =>
|
||||||
|
html`<img
|
||||||
|
class="img"
|
||||||
|
loading="auto"
|
||||||
|
style=${index === this.active ? styles : ''}
|
||||||
|
class=${index === this.active ? 'show' : 'hide'}
|
||||||
|
src=${url}
|
||||||
|
/>`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div class="tools-bar">
|
||||||
|
<wc-icon name="zoomIn" @click=${this.zoomIn}></wc-icon>
|
||||||
|
<wc-icon name="zoomOut" @click=${this.zoomOut}></wc-icon>
|
||||||
|
<wc-icon
|
||||||
|
name="fullScreen"
|
||||||
|
ref="resetBtn"
|
||||||
|
@click=${this.resetState}
|
||||||
|
></wc-icon>
|
||||||
|
<wc-icon name="refreshLeft" @click=${this.rotateLeft}></wc-icon>
|
||||||
|
<wc-icon name="refreshRight" @click=${this.rotateRight}></wc-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImagePreview.reg('image-preview')
|
||||||
|
const instance = new ImagePreview()
|
||||||
|
document.body.appendChild(instance)
|
||||||
|
|
||||||
|
window.imagePreview = function (list) {
|
||||||
|
instance.list = list
|
||||||
|
instance.visible = true
|
||||||
|
return instance
|
||||||
|
}
|
Loading…
Reference in New Issue