hookehuyr

fix(PdfViewer): 改进缩放功能以保持视图中心位置

重构缩放逻辑,使用比例计算代替直接缩放比率,确保缩放时视图中心位置保持不变
移除平滑滚动以避免偏移抖动,直接设置滚动位置
...@@ -354,28 +354,40 @@ const handleClose = () => { ...@@ -354,28 +354,40 @@ const handleClose = () => {
354 */ 354 */
355 const zoomIn = () => { 355 const zoomIn = () => {
356 if (zoomLevel.value < 3) { // 最大放大到300% 356 if (zoomLevel.value < 3) { // 最大放大到300%
357 - // 记录缩放前的滚动位置
358 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content'); 357 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content');
359 if (pdfContainer) { 358 if (pdfContainer) {
360 - const centerX = pdfContainer.scrollLeft + pdfContainer.clientWidth / 2; 359 + const oldW = pdfContainer.scrollWidth;
361 - const centerY = pdfContainer.scrollTop + pdfContainer.clientHeight / 2; 360 + const oldH = pdfContainer.scrollHeight;
361 + const viewportW = pdfContainer.clientWidth;
362 + const viewportH = pdfContainer.clientHeight;
363 +
364 + const centerX = pdfContainer.scrollLeft + viewportW / 2;
365 + const centerY = pdfContainer.scrollTop + viewportH / 2;
366 +
367 + const anchorRatioX = oldW > 0 ? centerX / oldW : 0;
368 + const anchorRatioY = oldH > 0 ? centerY / oldH : 0;
362 369
363 - const oldZoom = zoomLevel.value;
364 zoomLevel.value = Math.min(3, zoomLevel.value + 0.25); 370 zoomLevel.value = Math.min(3, zoomLevel.value + 0.25);
365 - const newZoom = zoomLevel.value;
366 371
367 - // 使用nextTick确保DOM更新后再调整滚动位置
368 nextTick(() => { 372 nextTick(() => {
369 - const zoomRatio = newZoom / oldZoom; 373 + const newW = pdfContainer.scrollWidth;
370 - const newScrollLeft = centerX * zoomRatio - pdfContainer.clientWidth / 2; 374 + const newH = pdfContainer.scrollHeight;
371 - const newScrollTop = centerY * zoomRatio - pdfContainer.clientHeight / 2; 375 +
372 - 376 + let targetCenterX = newW * anchorRatioX;
373 - pdfContainer.scrollTo({ 377 + let targetCenterY = newH * anchorRatioY;
374 - left: Math.max(0, newScrollLeft), 378 +
375 - top: Math.max(0, newScrollTop), 379 + let newScrollLeft = Math.max(0, targetCenterX - viewportW / 2);
376 - behavior: 'smooth' 380 + let newScrollTop = Math.max(0, targetCenterY - viewportH / 2);
377 - }); 381 +
382 + newScrollLeft = Math.min(newScrollLeft, Math.max(0, newW - viewportW));
383 + newScrollTop = Math.min(newScrollTop, Math.max(0, newH - viewportH));
384 +
385 + // 直接赋值避免平滑滚动导致的偏移抖动
386 + pdfContainer.scrollLeft = newScrollLeft;
387 + pdfContainer.scrollTop = newScrollTop;
378 }); 388 });
389 + } else {
390 + zoomLevel.value = Math.min(3, zoomLevel.value + 0.25);
379 } 391 }
380 } 392 }
381 }; 393 };
...@@ -385,28 +397,39 @@ const zoomIn = () => { ...@@ -385,28 +397,39 @@ const zoomIn = () => {
385 */ 397 */
386 const zoomOut = () => { 398 const zoomOut = () => {
387 if (zoomLevel.value > 0.5) { // 最小缩小到50% 399 if (zoomLevel.value > 0.5) { // 最小缩小到50%
388 - // 记录缩放前的滚动位置
389 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content'); 400 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content');
390 if (pdfContainer) { 401 if (pdfContainer) {
391 - const centerX = pdfContainer.scrollLeft + pdfContainer.clientWidth / 2; 402 + const oldW = pdfContainer.scrollWidth;
392 - const centerY = pdfContainer.scrollTop + pdfContainer.clientHeight / 2; 403 + const oldH = pdfContainer.scrollHeight;
404 + const viewportW = pdfContainer.clientWidth;
405 + const viewportH = pdfContainer.clientHeight;
406 +
407 + const centerX = pdfContainer.scrollLeft + viewportW / 2;
408 + const centerY = pdfContainer.scrollTop + viewportH / 2;
409 +
410 + const anchorRatioX = oldW > 0 ? centerX / oldW : 0;
411 + const anchorRatioY = oldH > 0 ? centerY / oldH : 0;
393 412
394 - const oldZoom = zoomLevel.value;
395 zoomLevel.value = Math.max(0.5, zoomLevel.value - 0.25); 413 zoomLevel.value = Math.max(0.5, zoomLevel.value - 0.25);
396 - const newZoom = zoomLevel.value;
397 414
398 - // 使用nextTick确保DOM更新后再调整滚动位置
399 nextTick(() => { 415 nextTick(() => {
400 - const zoomRatio = newZoom / oldZoom; 416 + const newW = pdfContainer.scrollWidth;
401 - const newScrollLeft = centerX * zoomRatio - pdfContainer.clientWidth / 2; 417 + const newH = pdfContainer.scrollHeight;
402 - const newScrollTop = centerY * zoomRatio - pdfContainer.clientHeight / 2; 418 +
403 - 419 + let targetCenterX = newW * anchorRatioX;
404 - pdfContainer.scrollTo({ 420 + let targetCenterY = newH * anchorRatioY;
405 - left: Math.max(0, newScrollLeft), 421 +
406 - top: Math.max(0, newScrollTop), 422 + let newScrollLeft = Math.max(0, targetCenterX - viewportW / 2);
407 - behavior: 'smooth' 423 + let newScrollTop = Math.max(0, targetCenterY - viewportH / 2);
408 - }); 424 +
425 + newScrollLeft = Math.min(newScrollLeft, Math.max(0, newW - viewportW));
426 + newScrollTop = Math.min(newScrollTop, Math.max(0, newH - viewportH));
427 +
428 + pdfContainer.scrollLeft = newScrollLeft;
429 + pdfContainer.scrollTop = newScrollTop;
409 }); 430 });
431 + } else {
432 + zoomLevel.value = Math.max(0.5, zoomLevel.value - 0.25);
410 } 433 }
411 } 434 }
412 }; 435 };
...@@ -417,15 +440,10 @@ const zoomOut = () => { ...@@ -417,15 +440,10 @@ const zoomOut = () => {
417 const resetZoom = () => { 440 const resetZoom = () => {
418 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content'); 441 const pdfContainer = document.querySelector('.pdf-viewer-container .pdf-content');
419 if (pdfContainer) { 442 if (pdfContainer) {
420 - // 重置到顶部中央位置
421 zoomLevel.value = 1; 443 zoomLevel.value = 1;
422 -
423 nextTick(() => { 444 nextTick(() => {
424 - pdfContainer.scrollTo({ 445 + pdfContainer.scrollLeft = 0;
425 - left: 0, 446 + pdfContainer.scrollTop = 0;
426 - top: 0,
427 - behavior: 'smooth'
428 - });
429 }); 447 });
430 } else { 448 } else {
431 zoomLevel.value = 1; 449 zoomLevel.value = 1;
......