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

使用FileReader读取用户上传PDF乱码,求iframe设置src的正确方法

解决上传PDF文件乱码及iframe展示问题

嘿,我来帮你搞定这个问题!首先咱们先搞清楚为什么用FileReader.readAsText()读PDF会乱码——PDF是二进制格式的文件,不是纯文本,用读取文本的方法去读二进制内容,肯定会出现乱码,这完全是正常现象~你想改用iframe展示PDF的思路是对的,下面我给你一步步讲怎么实现:

核心原理:用URL.createObjectURL()生成本地临时URL

浏览器提供了URL.createObjectURL()方法,可以把用户上传的File对象转换成一个临时的本地URL,这个URL可以直接作为iframe的src属性值,让浏览器内置的PDF查看器加载并展示文件内容。

你的代码修改步骤

1. 修正文件选择的保存逻辑

你的uploadFile函数目前只是把事件对象存起来了,应该把选中的文件对象存到file变量里:

uploadFile(ev) {
  // 保存选中的第一个文件
  this.file = ev.target.files[0];
}

2. 重写displayArticle函数

不用再用FileReader读文本了,直接生成临时URL并设置给iframe,同时保留TXT文件的文本展示逻辑:

displayArticle() {
  if (!this.file) {
    alert("请先选择文件!");
    return;
  }
  
  // 获取iframe元素
  const iframe = document.getElementById("frame");
  // 先释放之前的临时URL(避免内存泄漏)
  if (iframe.src) {
    URL.revokeObjectURL(iframe.src);
  }
  
  // 生成当前文件的临时URL
  const fileUrl = URL.createObjectURL(this.file);
  // 设置iframe的src
  iframe.src = fileUrl;
  
  // 如果是TXT文件,依然用原来的方式展示文本
  if (this.file.type === "text/plain") {
    const reader = new FileReader();
    reader.onload = () => {
      document.getElementById("fileContents").textContent = reader.result;
    };
    reader.readAsText(this.file);
  } else {
    // 非TXT文件(比如PDF),清空文本展示区域
    document.getElementById("fileContents").textContent = "";
  }
}

3. 补充内存泄漏处理(可选但推荐)

因为createObjectURL会占用浏览器内存,最好在组件销毁或者用户选择新文件时释放旧的URL。比如在Vue的beforeUnmount钩子中:

beforeUnmount() {
  const iframe = document.getElementById("frame");
  if (iframe.src) {
    URL.revokeObjectURL(iframe.src);
  }
}

完整的代码示例整合

把这些修改整合到你的代码里,最终的关键部分应该是这样的:

<template>
  <div>
    <b-form-file input="file" class="mb-2 m-2" @change="uploadFile"/>
    <b-button class="ml-2" @click="displayArticle">Display Article</b-button>
    
    <!-- PDF展示iframe -->
    <iframe id="frame" src="" style="width: 100%; height: 600px; border: none;"></iframe>
    
    <!-- TXT内容展示区域 -->
    <pre id="fileContents" style="font-size: medium; font-weight: bold; padding: 5px;"></pre>
  </div>
</template>

<script>
export default {
  data() {
    return {
      file: null,
    };
  },
  methods: {
    uploadFile(ev) {
      // 保存选中的第一个文件
      this.file = ev.target.files[0];
    },
    displayArticle() {
      if (!this.file) {
        alert("请先选择文件!");
        return;
      }
      
      const iframe = document.getElementById("frame");
      // 释放旧URL
      if (iframe.src) {
        URL.revokeObjectURL(iframe.src);
      }
      
      const fileUrl = URL.createObjectURL(this.file);
      iframe.src = fileUrl;
      
      // 处理TXT文件的文本展示
      if (this.file.type === "text/plain") {
        const reader = new FileReader();
        reader.onload = () => {
          document.getElementById("fileContents").textContent = reader.result;
        };
        reader.readAsText(this.file);
      } else {
        document.getElementById("fileContents").textContent = "";
      }
    },
  },
  beforeUnmount() {
    // 组件销毁时释放URL
    const iframe = document.getElementById("frame");
    if (iframe.src) {
      URL.revokeObjectURL(iframe.src);
    }
  },
};
</script>

注意事项

  • 这个方法依赖浏览器的内置PDF查看器,现代主流浏览器(Chrome、Firefox、Edge等)都支持,如果你需要兼容非常老的浏览器,可能需要额外的PDF渲染库(比如PDF.js)。
  • 临时URL只在当前页面会话中有效,页面刷新后就会失效,这完全符合上传文件的展示场景。

内容的提问来源于stack exchange,提问作者Esraa Saad

火山引擎 最新活动