feat(ImagePreview): optimize the preview effect of long images (#11857)

* feat(ImagePreview): optimize the preview effect of long images

* fix: optimize logic

* fix: optimize logic
This commit is contained in:
inottn 2023-05-21 10:10:59 +08:00 committed by GitHub
parent 08f82392b7
commit fe2335eb09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -40,6 +40,8 @@ const getCenter = (touches: TouchList) => ({
const bem = createNamespace('image-preview')[1];
const longImageRatio = 2.6;
export default defineComponent({
props: {
src: String,
@ -69,12 +71,10 @@ export default defineComponent({
const touch = useTouch();
const imageRef = ref<ComponentInstance>();
const swipeItem = ref<ComponentInstance>();
const vertical = ref(false);
const isLongImage = ref(false);
const vertical = computed(() => {
const { rootWidth, rootHeight } = props;
const rootRatio = rootHeight / rootWidth;
return state.imageRatio > rootRatio;
});
let initialMoveY = 0;
const imageStyle = computed(() => {
const { scale, moveX, moveY, moving, zooming } = state;
@ -82,7 +82,7 @@ export default defineComponent({
transitionDuration: zooming || moving ? '0s' : '.3s',
};
if (scale !== 1) {
if (scale !== 1 || isLongImage.value) {
// use matrix to solve the problem of elements not rendering due to safari optimization
style.transform = `matrix(${scale}, 0, 0, ${scale}, ${moveX}, ${moveY})`;
}
@ -138,7 +138,7 @@ export default defineComponent({
state.moveY = clamp(moveY, -maxMoveY.value, maxMoveY.value);
} else {
state.moveX = 0;
state.moveY = 0;
state.moveY = isLongImage.value ? initialMoveY : 0;
}
emit('scale', {
@ -157,7 +157,7 @@ export default defineComponent({
setScale(
scale,
scale === 2
scale === 2 || isLongImage.value
? { x: touch.startX.value, y: touch.startY.value }
: undefined
);
@ -192,7 +192,8 @@ export default defineComponent({
// whether the image position is moved after scaling
isImageMoved = false;
state.moving = fingerNum === 1 && state.scale !== 1;
state.moving =
fingerNum === 1 && (state.scale !== 1 || isLongImage.value);
state.zooming = fingerNum === 2 && !offsetX.value;
if (state.zooming) {
@ -318,9 +319,28 @@ export default defineComponent({
touch.reset();
};
const resize = () => {
const { rootWidth, rootHeight } = props;
const rootRatio = rootHeight / rootWidth;
const { imageRatio } = state;
vertical.value =
state.imageRatio > rootRatio && imageRatio < longImageRatio;
isLongImage.value =
state.imageRatio > rootRatio && imageRatio >= longImageRatio;
if (isLongImage.value) {
initialMoveY = (imageRatio * rootWidth - rootHeight) / 2;
state.moveY = initialMoveY;
}
resetScale();
};
const onLoad = (event: Event) => {
const { naturalWidth, naturalHeight } = event.target as HTMLImageElement;
state.imageRatio = naturalHeight / naturalWidth;
resize();
};
watch(() => props.active, resetScale);
@ -332,6 +352,7 @@ export default defineComponent({
}
}
);
watch(() => [props.rootWidth, props.rootHeight], resize);
// useEventListener will set passive to `false` to eliminate the warning of Chrome
useEventListener('touchmove', onTouchMove, {