UNPKG

@aplus-frontend/antdv

Version:

Vue basic component library maintained based on ant-design-vue

406 lines 13.3 kB
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import { createVNode as _createVNode, Fragment as _Fragment } from "vue"; import _extends from "@babel/runtime/helpers/esm/extends"; import { computed, defineComponent, onMounted, onUnmounted, reactive, shallowRef, watch, cloneVNode, unref } from 'vue'; import classnames from '../../_util/classNames'; import Dialog from '../../vc-dialog'; import { dialogPropTypes } from '../../vc-dialog/IDialogPropTypes'; import addEventListener from '../../vc-util/Dom/addEventListener'; import KeyCode from '../../_util/KeyCode'; import { warning } from '../../vc-util/warning'; import useFrameSetState from './hooks/useFrameSetState'; import getFixScaleEleTransPosition from './getFixScaleEleTransPosition'; import { context } from './PreviewGroup'; const initialPosition = { x: 0, y: 0 }; export const previewProps = _extends(_extends({}, dialogPropTypes()), { src: String, alt: String, rootClassName: String, icons: { type: Object, default: () => ({}) }, minScale: Number, maxScale: Number, imageInfo: Object }); const Preview = defineComponent({ compatConfig: { MODE: 3 }, name: 'Preview', inheritAttrs: false, props: previewProps, emits: ['close', 'afterClose'], slots: Object, setup(props, _ref) { let { emit, attrs, slots } = _ref; const { rotateLeft, rotateRight, zoomIn, zoomOut, close, left, right, flipX, flipY } = reactive(props.icons); const { minScale = 1, maxScale = 50, imageInfo = {} } = reactive(props); const scale = shallowRef(1); const rotate = shallowRef(0); const flip = reactive({ x: 1, y: 1 }); const [position, setPosition] = useFrameSetState(initialPosition); const onClose = () => emit('close'); const imgRef = shallowRef(); const originPositionRef = reactive({ originX: 0, originY: 0, deltaX: 0, deltaY: 0 }); const isMoving = shallowRef(false); const groupContext = context.inject(); const { previewUrls, current, isPreviewGroup, setCurrent } = groupContext; const previewGroupCount = computed(() => previewUrls.value.size); const previewUrlsKeys = computed(() => Array.from(previewUrls.value.keys())); const currentPreviewIndex = computed(() => previewUrlsKeys.value.indexOf(current.value)); const combinationSrc = computed(() => { return isPreviewGroup.value ? previewUrls.value.get(current.value) : props.src; }); const showLeftOrRightSwitches = computed(() => isPreviewGroup.value && previewGroupCount.value > 1); const showOperationsProgress = computed(() => isPreviewGroup.value && previewGroupCount.value >= 1); const lastWheelZoomDirection = shallowRef({ wheelDirection: 0 }); const image = computed(() => _extends({ url: combinationSrc.value, alt: props.alt }, imageInfo)); const onAfterClose = () => { scale.value = 1; rotate.value = 0; flip.x = 1; flip.y = 1; setPosition(initialPosition); emit('afterClose'); }; const onZoomIn = isWheel => { if (!isWheel) { scale.value++; } else { scale.value += 0.5; } setPosition(initialPosition); }; const onZoomOut = isWheel => { if (scale.value > 1) { if (!isWheel) { scale.value--; } else { scale.value -= 0.5; } } setPosition(initialPosition); }; const onRotateRight = () => { rotate.value += 90; }; const onRotateLeft = () => { rotate.value -= 90; }; const onFlipX = () => { flip.x = -flip.x; }; const onFlipY = () => { flip.y = -flip.y; }; const onSwitchLeft = event => { event.preventDefault(); // Without this mask close will abnormal event.stopPropagation(); if (currentPreviewIndex.value > 0) { setCurrent(previewUrlsKeys.value[currentPreviewIndex.value - 1]); } }; const onSwitchRight = event => { event.preventDefault(); // Without this mask close will abnormal event.stopPropagation(); if (currentPreviewIndex.value < previewGroupCount.value - 1) { setCurrent(previewUrlsKeys.value[currentPreviewIndex.value + 1]); } }; const wrapClassName = classnames({ [`${props.prefixCls}-moving`]: isMoving.value }); const toolClassName = `${props.prefixCls}-operations-operation`; const iconClassName = `${props.prefixCls}-operations-icon`; const tools = [{ icon: flipY, onClick: onFlipY, type: 'flipY' }, { icon: flipX, onClick: onFlipX, type: 'flipX' }, { icon: rotateLeft, onClick: onRotateLeft, type: 'rotateLeft' }, { icon: rotateRight, onClick: onRotateRight, type: 'rotateRight' }, { icon: zoomOut, onClick: onZoomOut, type: 'zoomOut', disabled: computed(() => scale.value === minScale) }, { icon: zoomIn, onClick: onZoomIn, type: 'zoomIn', disabled: computed(() => scale.value === maxScale) }]; const onMouseUp = () => { if (props.visible && isMoving.value) { const width = imgRef.value.offsetWidth * scale.value; const height = imgRef.value.offsetHeight * scale.value; const { left, top } = imgRef.value.getBoundingClientRect(); const isRotate = rotate.value % 180 !== 0; isMoving.value = false; const fixState = getFixScaleEleTransPosition(isRotate ? height : width, isRotate ? width : height, left, top); if (fixState) { setPosition(_extends({}, fixState)); } } }; const onMouseDown = event => { // Only allow main button if (event.button !== 0) return; event.preventDefault(); // Without this mask close will abnormal event.stopPropagation(); originPositionRef.deltaX = event.pageX - position.x; originPositionRef.deltaY = event.pageY - position.y; originPositionRef.originX = position.x; originPositionRef.originY = position.y; isMoving.value = true; }; const onMouseMove = event => { if (props.visible && isMoving.value) { setPosition({ x: event.pageX - originPositionRef.deltaX, y: event.pageY - originPositionRef.deltaY }); } }; const onWheelMove = event => { if (!props.visible) return; event.preventDefault(); const wheelDirection = event.deltaY; lastWheelZoomDirection.value = { wheelDirection }; }; const onKeyDown = event => { if (!props.visible || !showLeftOrRightSwitches.value) return; event.preventDefault(); if (event.keyCode === KeyCode.LEFT) { if (currentPreviewIndex.value > 0) { setCurrent(previewUrlsKeys.value[currentPreviewIndex.value - 1]); } } else if (event.keyCode === KeyCode.RIGHT) { if (currentPreviewIndex.value < previewGroupCount.value - 1) { setCurrent(previewUrlsKeys.value[currentPreviewIndex.value + 1]); } } }; const onDoubleClick = () => { if (props.visible) { if (scale.value !== 1) { scale.value = 1; } if (position.x !== initialPosition.x || position.y !== initialPosition.y) { setPosition(initialPosition); } } }; let removeListeners = () => {}; onMounted(() => { watch([() => props.visible, isMoving, imgRef], () => { removeListeners(); let onTopMouseUpListener; let onTopMouseMoveListener; const onMouseUpListener = addEventListener(imgRef.value, 'mouseup', onMouseUp, false); const onMouseMoveListener = addEventListener(imgRef.value, 'mousemove', onMouseMove, false); const onScrollWheelListener = addEventListener(imgRef.value, 'wheel', onWheelMove, { passive: false }); const onKeyDownListener = addEventListener(window, 'keydown', onKeyDown, false); try { // Resolve if in iframe lost event /* istanbul ignore next */ if (window.top !== window.self) { onTopMouseUpListener = addEventListener(window.top, 'mouseup', onMouseUp, false); onTopMouseMoveListener = addEventListener(window.top, 'mousemove', onMouseMove, false); } } catch (error) { /* istanbul ignore next */ warning(false, `[vc-image] ${error}`); } removeListeners = () => { onMouseUpListener.remove(); onMouseMoveListener.remove(); onScrollWheelListener.remove(); onKeyDownListener.remove(); /* istanbul ignore next */ if (onTopMouseUpListener) onTopMouseUpListener.remove(); /* istanbul ignore next */ if (onTopMouseMoveListener) onTopMouseMoveListener.remove(); }; }, { flush: 'post', immediate: true }); watch([lastWheelZoomDirection], () => { const { wheelDirection } = lastWheelZoomDirection.value; if (wheelDirection > 0) { onZoomOut(true); } else if (wheelDirection < 0) { onZoomIn(true); } }); }); onUnmounted(() => { removeListeners(); }); return () => { var _a, _b; const { visible, prefixCls, rootClassName } = props; const toolsNode = tools.map(_ref2 => { let { icon: IconType, onClick, type, disabled } = _ref2; return _createVNode("div", { "class": classnames(toolClassName, { [`${props.prefixCls}-operations-operation-${type}`]: true, [`${props.prefixCls}-operations-operation-disabled`]: disabled && (disabled === null || disabled === void 0 ? void 0 : disabled.value) }), "onClick": onClick, "key": type }, [cloneVNode(IconType, { class: iconClassName })]); }); const toolbarNode = _createVNode("div", { "class": `${props.prefixCls}-operations` }, [toolsNode]); return _createVNode(_Fragment, null, [_createVNode(Dialog, _objectSpread(_objectSpread({}, attrs), {}, { "transitionName": props.transitionName, "maskTransitionName": props.maskTransitionName, "closable": false, "keyboard": true, "prefixCls": prefixCls, "onClose": onClose, "afterClose": onAfterClose, "visible": visible, "wrapClassName": wrapClassName, "rootClassName": rootClassName, "getContainer": props.getContainer }), { default: () => [_createVNode("div", { "class": `${props.prefixCls}-img-wrapper`, "style": { transform: `translate3d(${position.x}px, ${position.y}px, 0)` } }, [_createVNode("img", { "onMousedown": onMouseDown, "onDblclick": onDoubleClick, "ref": imgRef, "class": `${props.prefixCls}-img`, "src": combinationSrc.value, "alt": props.alt, "style": { transform: `scale3d(${flip.x * scale.value}, ${flip.y * scale.value}, 1) rotate(${rotate.value}deg)` } }, null)])] }), visible && _createVNode("div", { "class": classnames(`${props.prefixCls}-operations-wrapper`, rootClassName) }, [_createVNode("button", { "class": `${props.prefixCls}-close`, "onClick": onClose }, [((_a = slots.closeIcon) === null || _a === void 0 ? void 0 : _a.call(slots, { onClose })) || close]), showLeftOrRightSwitches.value && _createVNode(_Fragment, null, [_createVNode("div", { "class": classnames(`${prefixCls}-switch-left`, { [`${props.prefixCls}-switch-left-disabled`]: currentPreviewIndex.value === 0 }), "onClick": onSwitchLeft }, [left]), _createVNode("div", { "class": classnames(`${prefixCls}-switch-right`, { [`${props.prefixCls}-switch-right-disabled`]: currentPreviewIndex.value === previewGroupCount.value - 1 }), "onClick": onSwitchRight }, [right])]), _createVNode("div", { "class": [`${props.prefixCls}-footer`] }, [showOperationsProgress.value && _createVNode("div", { "class": `${props.prefixCls}-progress` }, [`${currentPreviewIndex.value + 1} / ${previewGroupCount.value}`]), slots.toolbarRender ? (_b = slots.toolbarRender) === null || _b === void 0 ? void 0 : _b.call(slots, _extends({ originalNodes: toolsNode, actions: { onFlipY, onFlipX, onRotateLeft, onRotateRight, onZoomOut, onZoomIn }, transform: { x: position.x, y: position.y, scale: scale.value, rotate, flip }, image: unref(image) }, groupContext ? { current: currentPreviewIndex.value, total: previewGroupCount.value } : {})) : toolbarNode])])]); }; } }); export default Preview;