You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过ngx-extended-pdf-viewer提取PDF中非HTTPS协议的本地链接以实现Angular应用内部路由?

解决方案:提取并处理ngx-extended-pdf-viewer中的内部ID链接

既然官方文档明确表示这类纯ID格式的内部链接不受支持,我们可以绕过组件的默认处理逻辑,直接借助PDF.js(ngx-extended-pdf-viewer的底层依赖)来提取链接,再结合Angular的路由实现跳转。以下是几个可行的方案:

方案1:预解析PDF提取所有内部链接

这个方法会先加载PDF文档,遍历所有页面提取注释中的链接,筛选出非HTTPS的内部ID,之后可以将这些链接和对应的页面位置关联起来,用于后续的跳转逻辑。

步骤:

  1. 确保项目中已安装pdfjs-dist(ngx-extended-pdf-viewer通常已经包含这个依赖,若没有则手动安装:npm install pdfjs-dist
  2. 在Angular组件或服务中编写解析逻辑:
import { Component, OnInit } from '@angular/core';
import * as pdfjsLib from 'pdfjs-dist';
import { PDFDocumentProxy, PDFPageProxy } from 'pdfjs-dist';

// 配置PDF.js的worker路径(根据你的项目结构调整)
pdfjsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';

@Component({
  selector: 'app-pdf-viewer',
  templateUrl: './pdf-viewer.component.html',
  styleUrls: ['./pdf-viewer.component.css']
})
export class PdfViewerComponent implements OnInit {
  public internalLinks: Array<{ id: string; pageNumber: number; rect: number[] }> = [];
  public pdfUrl = '/assets/your-document.pdf'; // 替换为你的PDF路径

  ngOnInit(): void {
    this.extractInternalLinks();
  }

  private async extractInternalLinks(): Promise<void> {
    const pdf: PDFDocumentProxy = await pdfjsLib.getDocument(this.pdfUrl).promise;
    const numPages = pdf.numPages;

    for (let pageNum = 1; pageNum <= numPages; pageNum++) {
      const page: PDFPageProxy = await pdf.getPage(pageNum);
      const annotations = await page.getAnnotations();

      // 筛选出非HTTPS的链接(这里判断链接是否不以https://开头)
      const pageInternalLinks = annotations
        .filter(ann => ann.subtype === 'Link' && ann.url && !ann.url.startsWith('https://'))
        .map(ann => ({
          id: ann.url.replace('file:///', ''), // 去掉file:///前缀,获取纯ID
          pageNumber: pageNum,
          rect: ann.rect // 链接的位置矩形,用于后续定位
        }));

      this.internalLinks.push(...pageInternalLinks);
    }

    console.log('提取到的内部链接:', this.internalLinks);
  }
}

方案2:拦截PDF渲染后的点击事件

提取链接后,我们可以监听ngx-extended-pdf-viewer容器的点击事件,判断点击位置是否对应某个内部链接,然后触发Angular路由跳转。

步骤:

  1. 在组件模板中给PDF viewer添加模板引用:
<ngx-extended-pdf-viewer
  #pdfViewer
  [src]="pdfUrl"
  [useBrowserLocale]="true"
></ngx-extended-pdf-viewer>
  1. 在组件中监听点击事件,并匹配内部链接:
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Router } from '@angular/router';

// ... 其他代码 ...

@Component({
  // ... 组件配置 ...
})
export class PdfViewerComponent implements OnInit, AfterViewInit {
  @ViewChild('pdfViewer') pdfViewer!: ElementRef;

  constructor(private router: Router) {}

  ngAfterViewInit(): void {
    const viewerContainer = this.pdfViewer.nativeElement.querySelector('.pdfViewer');
    if (viewerContainer) {
      viewerContainer.addEventListener('click', (event: MouseEvent) => {
        // 获取点击位置相对于PDF容器的坐标
        const rect = viewerContainer.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;

        // 匹配点击位置对应的内部链接
        const matchedLink = this.internalLinks.find(link => {
          const [x1, y1, x2, y2] = link.rect;
          // 注意PDF的坐标系统是从左下角开始,需要转换为容器的坐标系
          const containerY = viewerContainer.clientHeight - y;
          return x >= x1 && x <= x2 && containerY >= y1 && containerY <= y2;
        });

        if (matchedLink) {
          event.preventDefault();
          event.stopPropagation();
          // 跳转到Angular内部路由,比如 /detail/:id
          this.router.navigate(['/detail', matchedLink.id]);
        }
      });
    }
  }
}

方案3:自定义链接处理函数(如果组件支持)

部分版本的ngx-extended-pdf-viewer提供了customLinkHandler配置项,可以直接覆盖默认的链接处理逻辑。你可以尝试这个配置:

<ngx-extended-pdf-viewer
  [src]="pdfUrl"
  [customLinkHandler]="handleCustomLink"
></ngx-extended-pdf-viewer>

在组件中定义处理函数:

handleCustomLink(url: string): boolean {
  if (!url.startsWith('https://')) {
    // 处理内部ID链接
    const internalId = url.replace('file:///', '');
    this.router.navigate(['/detail', internalId]);
    return true; // 返回true表示已处理,阻止默认行为
  }
  return false; // 返回false使用默认处理(打开新标签)
}

注意事项:

  • PDF的坐标系统和浏览器的坐标系不同(PDF从左下角开始,浏览器从左上角开始),所以在匹配点击位置时需要做坐标转换,方案2中已经处理了这一点。
  • 如果你的PDF内部链接不是通过注释而是其他方式定义的,可能需要调整解析逻辑,比如解析PDF的大纲(Bookmark)或者其他结构。
  • 确保PDF.js的worker路径配置正确,否则会导致解析失败。

内容的提问来源于stack exchange,提问作者Tom I.

火山引擎 最新活动