19 changed files with 460 additions and 474 deletions
@ -0,0 +1,436 @@ |
|||
<script lang="tsx"> |
|||
import { defineComponent, ref, unref, computed, reactive, watchEffect } from 'vue'; |
|||
import { Props } from './typing'; |
|||
import { CloseOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; |
|||
import resumeSvg from '/@/assets/svg/preview/resume.svg'; |
|||
import rotateSvg from '/@/assets/svg/preview/p-rotate.svg'; |
|||
import scaleSvg from '/@/assets/svg/preview/scale.svg'; |
|||
import unScaleSvg from '/@/assets/svg/preview/unscale.svg'; |
|||
import unRotateSvg from '/@/assets/svg/preview/unrotate.svg'; |
|||
|
|||
enum StatueEnum { |
|||
LOADING, |
|||
DONE, |
|||
FAIL, |
|||
} |
|||
interface ImgState { |
|||
currentUrl: string; |
|||
imgScale: number; |
|||
imgRotate: number; |
|||
imgTop: number; |
|||
imgLeft: number; |
|||
currentIndex: number; |
|||
status: StatueEnum; |
|||
moveX: number; |
|||
moveY: number; |
|||
show: boolean; |
|||
} |
|||
const props = { |
|||
show: { |
|||
type: Boolean as PropType<boolean>, |
|||
default: false, |
|||
}, |
|||
imageList: { |
|||
type: [Array] as PropType<string[]>, |
|||
default: null, |
|||
}, |
|||
index: { |
|||
type: Number as PropType<number>, |
|||
default: 0, |
|||
}, |
|||
}; |
|||
|
|||
const prefixCls = 'img-preview'; |
|||
export default defineComponent({ |
|||
name: 'ImagePreview', |
|||
props, |
|||
setup(props: Props) { |
|||
const imgState = reactive<ImgState>({ |
|||
currentUrl: '', |
|||
imgScale: 1, |
|||
imgRotate: 0, |
|||
imgTop: 0, |
|||
imgLeft: 0, |
|||
status: StatueEnum.LOADING, |
|||
currentIndex: 0, |
|||
moveX: 0, |
|||
moveY: 0, |
|||
show: props.show, |
|||
}); |
|||
|
|||
const wrapElRef = ref<HTMLDivElement | null>(null); |
|||
const imgElRef = ref<HTMLImageElement | null>(null); |
|||
|
|||
// 初始化 |
|||
function init() { |
|||
initMouseWheel(); |
|||
const { index, imageList } = props; |
|||
|
|||
if (!imageList || !imageList.length) { |
|||
throw new Error('imageList is undefined'); |
|||
} |
|||
imgState.currentIndex = index; |
|||
handleIChangeImage(imageList[index]); |
|||
} |
|||
|
|||
// 重置 |
|||
function initState() { |
|||
imgState.imgScale = 1; |
|||
imgState.imgRotate = 0; |
|||
imgState.imgTop = 0; |
|||
imgState.imgLeft = 0; |
|||
} |
|||
|
|||
// 初始化鼠标滚轮事件 |
|||
function initMouseWheel() { |
|||
const wrapEl = unref(wrapElRef); |
|||
if (!wrapEl) { |
|||
return; |
|||
} |
|||
(wrapEl as any).onmousewheel = scrollFunc; |
|||
// 火狐浏览器没有onmousewheel事件,用DOMMouseScroll代替 |
|||
document.body.addEventListener('DOMMouseScroll', scrollFunc); |
|||
// 禁止火狐浏览器下拖拽图片的默认事件 |
|||
document.ondragstart = function () { |
|||
return false; |
|||
}; |
|||
} |
|||
|
|||
// 监听鼠标滚轮 |
|||
function scrollFunc(e: any) { |
|||
e = e || window.event; |
|||
e.delta = e.wheelDelta || -e.detail; |
|||
|
|||
e.preventDefault(); |
|||
if (e.delta > 0) { |
|||
// 滑轮向上滚动 |
|||
scaleFunc(0.015); |
|||
} |
|||
if (e.delta < 0) { |
|||
// 滑轮向下滚动 |
|||
scaleFunc(-0.015); |
|||
} |
|||
} |
|||
// 缩放函数 |
|||
function scaleFunc(num: number) { |
|||
if (imgState.imgScale <= 0.2 && num < 0) return; |
|||
imgState.imgScale += num; |
|||
} |
|||
|
|||
// 旋转图片 |
|||
function rotateFunc(deg: number) { |
|||
imgState.imgRotate += deg; |
|||
} |
|||
|
|||
// 鼠标事件 |
|||
function handleMouseUp() { |
|||
const imgEl = unref(imgElRef); |
|||
if (!imgEl) return; |
|||
imgEl.onmousemove = null; |
|||
} |
|||
|
|||
// 更换图片 |
|||
function handleIChangeImage(url: string) { |
|||
imgState.status = StatueEnum.LOADING; |
|||
const img = new Image(); |
|||
img.src = url; |
|||
img.onload = () => { |
|||
imgState.currentUrl = url; |
|||
imgState.status = StatueEnum.DONE; |
|||
}; |
|||
img.onerror = () => { |
|||
imgState.status = StatueEnum.FAIL; |
|||
}; |
|||
} |
|||
|
|||
// 关闭 |
|||
function handleClose(e: MouseEvent) { |
|||
e && e.stopPropagation(); |
|||
imgState.show = false; |
|||
// 移除火狐浏览器下的鼠标滚动事件 |
|||
document.body.removeEventListener('DOMMouseScroll', scrollFunc); |
|||
// 恢复火狐及Safari浏览器下的图片拖拽 |
|||
document.ondragstart = null; |
|||
} |
|||
|
|||
// 图片复原 |
|||
function resume() { |
|||
initState(); |
|||
} |
|||
|
|||
// 上一页下一页 |
|||
function handleChange(direction: 'left' | 'right') { |
|||
const { currentIndex } = imgState; |
|||
const { imageList } = props; |
|||
if (direction === 'left') { |
|||
imgState.currentIndex--; |
|||
if (currentIndex <= 0) { |
|||
imgState.currentIndex = imageList.length - 1; |
|||
} |
|||
} |
|||
if (direction === 'right') { |
|||
imgState.currentIndex++; |
|||
if (currentIndex >= imageList.length - 1) { |
|||
imgState.currentIndex = 0; |
|||
} |
|||
} |
|||
handleIChangeImage(imageList[imgState.currentIndex]); |
|||
} |
|||
|
|||
function handleAddMoveListener(e: MouseEvent) { |
|||
e = e || window.event; |
|||
imgState.moveX = e.clientX; |
|||
imgState.moveY = e.clientY; |
|||
const imgEl = unref(imgElRef); |
|||
if (imgEl) { |
|||
imgEl.onmousemove = moveFunc; |
|||
} |
|||
} |
|||
|
|||
function moveFunc(e: MouseEvent) { |
|||
e = e || window.event; |
|||
e.preventDefault(); |
|||
const movementX = e.clientX - imgState.moveX; |
|||
const movementY = e.clientY - imgState.moveY; |
|||
imgState.imgLeft += movementX; |
|||
imgState.imgTop += movementY; |
|||
imgState.moveX = e.clientX; |
|||
imgState.moveY = e.clientY; |
|||
} |
|||
|
|||
// 获取图片样式 |
|||
const getImageStyle = computed(() => { |
|||
const { imgScale, imgRotate, imgTop, imgLeft } = imgState; |
|||
return { |
|||
transform: `scale(${imgScale}) rotate(${imgRotate}deg)`, |
|||
marginTop: `${imgTop}px`, |
|||
marginLeft: `${imgLeft}px`, |
|||
}; |
|||
}); |
|||
|
|||
const getIsMultipleImage = computed(() => { |
|||
const { imageList } = props; |
|||
return imageList.length > 1; |
|||
}); |
|||
|
|||
watchEffect(() => { |
|||
if (props.show) { |
|||
init(); |
|||
} |
|||
if (props.imageList) { |
|||
initState(); |
|||
} |
|||
}); |
|||
|
|||
const renderClose = () => { |
|||
return ( |
|||
<div class={`${prefixCls}__close`} onClick={handleClose}> |
|||
<CloseOutlined class={`${prefixCls}__close-icon`} /> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderIndex = () => { |
|||
if (!unref(getIsMultipleImage)) { |
|||
return null; |
|||
} |
|||
const { currentIndex } = imgState; |
|||
const { imageList } = props; |
|||
return ( |
|||
<div class={`${prefixCls}__index`}> |
|||
{currentIndex + 1} / {imageList.length} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderController = () => { |
|||
return ( |
|||
<div class={`${prefixCls}__controller`}> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => scaleFunc(-0.15)}> |
|||
<img src={unScaleSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => scaleFunc(0.15)}> |
|||
<img src={scaleSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={resume}> |
|||
<img src={resumeSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => rotateFunc(-90)}> |
|||
<img src={unRotateSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => rotateFunc(90)}> |
|||
<img src={rotateSvg} /> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderArrow = (direction: 'left' | 'right') => { |
|||
if (!unref(getIsMultipleImage)) { |
|||
return null; |
|||
} |
|||
return ( |
|||
<div class={[`${prefixCls}__arrow`, direction]} onClick={() => handleChange(direction)}> |
|||
{direction === 'left' ? <LeftOutlined /> : <RightOutlined />} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
return () => { |
|||
return ( |
|||
imgState.show && ( |
|||
<div class={prefixCls} ref={wrapElRef} onMouseup={handleMouseUp}> |
|||
<div class={`${prefixCls}-content`}> |
|||
{/*<Spin*/} |
|||
{/* indicator={<LoadingOutlined style="font-size: 24px" spin />}*/} |
|||
{/* spinning={true}*/} |
|||
{/* class={[*/} |
|||
{/* `${prefixCls}-image`,*/} |
|||
{/* {*/} |
|||
{/* hidden: imgState.status !== StatueEnum.LOADING,*/} |
|||
{/* },*/} |
|||
{/* ]}*/} |
|||
{/*/>*/} |
|||
<img |
|||
style={unref(getImageStyle)} |
|||
class={[ |
|||
`${prefixCls}-image`, |
|||
imgState.status === StatueEnum.DONE ? '' : 'hidden', |
|||
]} |
|||
ref={imgElRef} |
|||
src={imgState.currentUrl} |
|||
onMousedown={handleAddMoveListener} |
|||
/> |
|||
{renderClose()} |
|||
{renderIndex()} |
|||
{renderController()} |
|||
{renderArrow('left')} |
|||
{renderArrow('right')} |
|||
</div> |
|||
</div> |
|||
) |
|||
); |
|||
}; |
|||
}, |
|||
}); |
|||
</script> |
|||
<style lang="less"> |
|||
.img-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: @preview-comp-z-index; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
user-select: none; |
|||
|
|||
&-content { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 100%; |
|||
color: @white; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
&-image { |
|||
cursor: pointer; |
|||
transition: transform 0.3s; |
|||
} |
|||
|
|||
&__close { |
|||
position: absolute; |
|||
top: -40px; |
|||
right: -40px; |
|||
width: 80px; |
|||
height: 80px; |
|||
overflow: hidden; |
|||
color: @white; |
|||
cursor: pointer; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
border-radius: 50%; |
|||
transition: all 0.2s; |
|||
|
|||
&-icon { |
|||
position: absolute; |
|||
top: 46px; |
|||
left: 16px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
&:hover { |
|||
background-color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
|
|||
&__index { |
|||
position: absolute; |
|||
bottom: 5%; |
|||
left: 50%; |
|||
padding: 0 22px; |
|||
font-size: 16px; |
|||
background: rgba(109, 109, 109, 0.6); |
|||
border-radius: 15px; |
|||
transform: translateX(-50%); |
|||
} |
|||
|
|||
&__controller { |
|||
position: absolute; |
|||
bottom: 10%; |
|||
left: 50%; |
|||
display: flex; |
|||
width: 260px; |
|||
height: 44px; |
|||
padding: 0 22px; |
|||
margin-left: -139px; |
|||
background: rgba(109, 109, 109, 0.6); |
|||
border-radius: 22px; |
|||
justify-content: center; |
|||
|
|||
&-item { |
|||
display: flex; |
|||
height: 100%; |
|||
padding: 0 9px; |
|||
font-size: 24px; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
|
|||
&:hover { |
|||
transform: scale(1.2); |
|||
} |
|||
|
|||
img { |
|||
width: 1em; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&__arrow { |
|||
position: absolute; |
|||
top: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 50px; |
|||
height: 50px; |
|||
font-size: 28px; |
|||
cursor: pointer; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
border-radius: 50%; |
|||
transition: all 0.2s; |
|||
|
|||
&:hover { |
|||
background-color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
|
|||
&.left { |
|||
left: 50px; |
|||
} |
|||
|
|||
&.right { |
|||
right: 50px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,118 +0,0 @@ |
|||
.img-preview { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: @preview-comp-z-index; |
|||
background: rgba(0, 0, 0, 0.5); |
|||
user-select: none; |
|||
|
|||
&-content { |
|||
display: flex; |
|||
width: 100%; |
|||
height: 100%; |
|||
color: @white; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
&-image { |
|||
cursor: pointer; |
|||
transition: transform 0.3s; |
|||
} |
|||
|
|||
&__close { |
|||
position: absolute; |
|||
top: -40px; |
|||
right: -40px; |
|||
width: 80px; |
|||
height: 80px; |
|||
overflow: hidden; |
|||
color: @white; |
|||
cursor: pointer; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
border-radius: 50%; |
|||
transition: all 0.2s; |
|||
|
|||
&-icon { |
|||
position: absolute; |
|||
top: 46px; |
|||
left: 16px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
&:hover { |
|||
background-color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
} |
|||
|
|||
&__index { |
|||
position: absolute; |
|||
bottom: 5%; |
|||
left: 50%; |
|||
padding: 0 22px; |
|||
font-size: 16px; |
|||
background: rgba(109, 109, 109, 0.6); |
|||
border-radius: 15px; |
|||
transform: translateX(-50%); |
|||
} |
|||
|
|||
&__controller { |
|||
position: absolute; |
|||
bottom: 10%; |
|||
left: 50%; |
|||
display: flex; |
|||
width: 260px; |
|||
height: 44px; |
|||
padding: 0 22px; |
|||
margin-left: -139px; |
|||
background: rgba(109, 109, 109, 0.6); |
|||
border-radius: 22px; |
|||
justify-content: center; |
|||
|
|||
&-item { |
|||
display: flex; |
|||
height: 100%; |
|||
padding: 0 9px; |
|||
font-size: 24px; |
|||
cursor: pointer; |
|||
transition: all 0.2s; |
|||
|
|||
&:hover { |
|||
transform: scale(1.2); |
|||
} |
|||
|
|||
img { |
|||
width: 1em; |
|||
} |
|||
} |
|||
} |
|||
|
|||
&__arrow { |
|||
position: absolute; |
|||
top: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
width: 50px; |
|||
height: 50px; |
|||
font-size: 28px; |
|||
cursor: pointer; |
|||
background-color: rgba(0, 0, 0, 0.5); |
|||
border-radius: 50%; |
|||
transition: all 0.2s; |
|||
|
|||
&:hover { |
|||
background-color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
|
|||
&.left { |
|||
left: 50px; |
|||
} |
|||
|
|||
&.right { |
|||
right: 50px; |
|||
} |
|||
} |
|||
} |
|||
@ -1,305 +0,0 @@ |
|||
import './index.less'; |
|||
|
|||
import { defineComponent, ref, unref, computed, reactive, watchEffect } from 'vue'; |
|||
|
|||
// @ts-ignore
|
|||
import { basicProps } from './props'; |
|||
// @ts-ignore
|
|||
import { Props } from './types'; |
|||
|
|||
import { CloseOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons-vue'; |
|||
// import { Spin } from 'ant-design-vue';
|
|||
|
|||
import resumeSvg from '/@/assets/svg/preview/resume.svg'; |
|||
import rotateSvg from '/@/assets/svg/preview/p-rotate.svg'; |
|||
import scaleSvg from '/@/assets/svg/preview/scale.svg'; |
|||
import unScaleSvg from '/@/assets/svg/preview/unscale.svg'; |
|||
import unRotateSvg from '/@/assets/svg/preview/unrotate.svg'; |
|||
enum StatueEnum { |
|||
LOADING, |
|||
DONE, |
|||
FAIL, |
|||
} |
|||
interface ImgState { |
|||
currentUrl: string; |
|||
imgScale: number; |
|||
imgRotate: number; |
|||
imgTop: number; |
|||
imgLeft: number; |
|||
currentIndex: number; |
|||
status: StatueEnum; |
|||
moveX: number; |
|||
moveY: number; |
|||
show: boolean; |
|||
} |
|||
|
|||
const prefixCls = 'img-preview'; |
|||
export default defineComponent({ |
|||
name: 'ImagePreview', |
|||
props: basicProps, |
|||
setup(props: Props) { |
|||
const imgState = reactive<ImgState>({ |
|||
currentUrl: '', |
|||
imgScale: 1, |
|||
imgRotate: 0, |
|||
imgTop: 0, |
|||
imgLeft: 0, |
|||
status: StatueEnum.LOADING, |
|||
currentIndex: 0, |
|||
moveX: 0, |
|||
moveY: 0, |
|||
show: props.show, |
|||
}); |
|||
|
|||
const wrapElRef = ref<HTMLDivElement | null>(null); |
|||
const imgElRef = ref<HTMLImageElement | null>(null); |
|||
|
|||
// 初始化
|
|||
function init() { |
|||
initMouseWheel(); |
|||
const { index, imageList } = props; |
|||
|
|||
if (!imageList || !imageList.length) { |
|||
throw new Error('imageList is undefined'); |
|||
} |
|||
imgState.currentIndex = index; |
|||
handleIChangeImage(imageList[index]); |
|||
} |
|||
|
|||
// 重置
|
|||
function initState() { |
|||
imgState.imgScale = 1; |
|||
imgState.imgRotate = 0; |
|||
imgState.imgTop = 0; |
|||
imgState.imgLeft = 0; |
|||
} |
|||
|
|||
// 初始化鼠标滚轮事件
|
|||
function initMouseWheel() { |
|||
const wrapEl = unref(wrapElRef); |
|||
if (!wrapEl) { |
|||
return; |
|||
} |
|||
(wrapEl as any).onmousewheel = scrollFunc; |
|||
// 火狐浏览器没有onmousewheel事件,用DOMMouseScroll代替
|
|||
document.body.addEventListener('DOMMouseScroll', scrollFunc); |
|||
// 禁止火狐浏览器下拖拽图片的默认事件
|
|||
document.ondragstart = function () { |
|||
return false; |
|||
}; |
|||
} |
|||
|
|||
// 监听鼠标滚轮
|
|||
function scrollFunc(e: any) { |
|||
e = e || window.event; |
|||
e.delta = e.wheelDelta || -e.detail; |
|||
|
|||
e.preventDefault(); |
|||
if (e.delta > 0) { |
|||
// 滑轮向上滚动
|
|||
scaleFunc(0.015); |
|||
} |
|||
if (e.delta < 0) { |
|||
// 滑轮向下滚动
|
|||
scaleFunc(-0.015); |
|||
} |
|||
} |
|||
// 缩放函数
|
|||
function scaleFunc(num: number) { |
|||
if (imgState.imgScale <= 0.2 && num < 0) return; |
|||
imgState.imgScale += num; |
|||
} |
|||
|
|||
// 旋转图片
|
|||
function rotateFunc(deg: number) { |
|||
imgState.imgRotate += deg; |
|||
} |
|||
|
|||
// 鼠标事件
|
|||
function handleMouseUp() { |
|||
const imgEl = unref(imgElRef); |
|||
if (!imgEl) return; |
|||
imgEl.onmousemove = null; |
|||
} |
|||
|
|||
// 更换图片
|
|||
function handleIChangeImage(url: string) { |
|||
imgState.status = StatueEnum.LOADING; |
|||
const img = new Image(); |
|||
img.src = url; |
|||
img.onload = () => { |
|||
imgState.currentUrl = url; |
|||
imgState.status = StatueEnum.DONE; |
|||
}; |
|||
img.onerror = () => { |
|||
imgState.status = StatueEnum.FAIL; |
|||
}; |
|||
} |
|||
|
|||
// 关闭
|
|||
function handleClose(e: MouseEvent) { |
|||
e && e.stopPropagation(); |
|||
imgState.show = false; |
|||
// 移除火狐浏览器下的鼠标滚动事件
|
|||
document.body.removeEventListener('DOMMouseScroll', scrollFunc); |
|||
// 恢复火狐及Safari浏览器下的图片拖拽
|
|||
document.ondragstart = null; |
|||
} |
|||
|
|||
// 图片复原
|
|||
function resume() { |
|||
initState(); |
|||
} |
|||
|
|||
// 上一页下一页
|
|||
function handleChange(direction: 'left' | 'right') { |
|||
const { currentIndex } = imgState; |
|||
const { imageList } = props; |
|||
if (direction === 'left') { |
|||
imgState.currentIndex--; |
|||
if (currentIndex <= 0) { |
|||
imgState.currentIndex = imageList.length - 1; |
|||
} |
|||
} |
|||
if (direction === 'right') { |
|||
imgState.currentIndex++; |
|||
if (currentIndex >= imageList.length - 1) { |
|||
imgState.currentIndex = 0; |
|||
} |
|||
} |
|||
handleIChangeImage(imageList[imgState.currentIndex]); |
|||
} |
|||
|
|||
function handleAddMoveListener(e: MouseEvent) { |
|||
e = e || window.event; |
|||
imgState.moveX = e.clientX; |
|||
imgState.moveY = e.clientY; |
|||
const imgEl = unref(imgElRef); |
|||
if (imgEl) { |
|||
imgEl.onmousemove = moveFunc; |
|||
} |
|||
} |
|||
|
|||
function moveFunc(e: MouseEvent) { |
|||
e = e || window.event; |
|||
e.preventDefault(); |
|||
const movementX = e.clientX - imgState.moveX; |
|||
const movementY = e.clientY - imgState.moveY; |
|||
imgState.imgLeft += movementX; |
|||
imgState.imgTop += movementY; |
|||
imgState.moveX = e.clientX; |
|||
imgState.moveY = e.clientY; |
|||
} |
|||
|
|||
// 获取图片样式
|
|||
const getImageStyle = computed(() => { |
|||
const { imgScale, imgRotate, imgTop, imgLeft } = imgState; |
|||
return { |
|||
transform: `scale(${imgScale}) rotate(${imgRotate}deg)`, |
|||
marginTop: `${imgTop}px`, |
|||
marginLeft: `${imgLeft}px`, |
|||
}; |
|||
}); |
|||
|
|||
const getIsMultipleImage = computed(() => { |
|||
const { imageList } = props; |
|||
return imageList.length > 1; |
|||
}); |
|||
|
|||
watchEffect(() => { |
|||
if (props.show) { |
|||
init(); |
|||
} |
|||
if (props.imageList) { |
|||
initState(); |
|||
} |
|||
}); |
|||
|
|||
const renderClose = () => { |
|||
return ( |
|||
<div class={`${prefixCls}__close`} onClick={handleClose}> |
|||
<CloseOutlined class={`${prefixCls}__close-icon`} /> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderIndex = () => { |
|||
if (!unref(getIsMultipleImage)) { |
|||
return null; |
|||
} |
|||
const { currentIndex } = imgState; |
|||
const { imageList } = props; |
|||
return ( |
|||
<div class={`${prefixCls}__index`}> |
|||
{currentIndex + 1} / {imageList.length} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderController = () => { |
|||
return ( |
|||
<div class={`${prefixCls}__controller`}> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => scaleFunc(-0.15)}> |
|||
<img src={unScaleSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => scaleFunc(0.15)}> |
|||
<img src={scaleSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={resume}> |
|||
<img src={resumeSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => rotateFunc(-90)}> |
|||
<img src={unRotateSvg} /> |
|||
</div> |
|||
<div class={`${prefixCls}__controller-item`} onClick={() => rotateFunc(90)}> |
|||
<img src={rotateSvg} /> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderArrow = (direction: 'left' | 'right') => { |
|||
if (!unref(getIsMultipleImage)) { |
|||
return null; |
|||
} |
|||
return ( |
|||
<div class={[`${prefixCls}__arrow`, direction]} onClick={() => handleChange(direction)}> |
|||
{direction === 'left' ? <LeftOutlined /> : <RightOutlined />} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
return () => { |
|||
return ( |
|||
imgState.show && ( |
|||
<div class={prefixCls} ref={wrapElRef} onMouseup={handleMouseUp}> |
|||
<div class={`${prefixCls}-content`}> |
|||
{/*<Spin*/} |
|||
{/* indicator={<LoadingOutlined style="font-size: 24px" spin />}*/} |
|||
{/* spinning={true}*/} |
|||
{/* class={[*/} |
|||
{/* `${prefixCls}-image`,*/} |
|||
{/* {*/} |
|||
{/* hidden: imgState.status !== StatueEnum.LOADING,*/} |
|||
{/* },*/} |
|||
{/* ]}*/} |
|||
{/*/>*/} |
|||
<img |
|||
style={unref(getImageStyle)} |
|||
class={[`${prefixCls}-image`, imgState.status === StatueEnum.DONE ? '' : 'hidden']} |
|||
ref={imgElRef} |
|||
src={imgState.currentUrl} |
|||
onMousedown={handleAddMoveListener} |
|||
/> |
|||
{renderClose()} |
|||
{renderIndex()} |
|||
{renderController()} |
|||
{renderArrow('left')} |
|||
{renderArrow('right')} |
|||
</div> |
|||
</div> |
|||
) |
|||
); |
|||
}; |
|||
}, |
|||
}); |
|||
@ -1,15 +0,0 @@ |
|||
import { PropType } from 'vue'; |
|||
export const basicProps = { |
|||
show: { |
|||
type: Boolean as PropType<boolean>, |
|||
default: false, |
|||
}, |
|||
imageList: { |
|||
type: [Array] as PropType<string[]>, |
|||
default: null, |
|||
}, |
|||
index: { |
|||
type: Number as PropType<number>, |
|||
default: 0, |
|||
}, |
|||
}; |
|||
Loading…
Reference in new issue