You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何在纯HTML和JS中展示Firebase Storage中的PDF文件

解决方案:Firebase Storage PDF展示实现

核心思路

  1. 从localStorage读取已上传的PDF文件路径(后续可迁移到Firebase Realtime Database/Firestore实现多端同步)
  2. 通过Firebase Storage API获取PDF的公开下载URL
  3. 使用HTML的<embed>或<iframe>标签在页面嵌入预览,同时提供下载链接
  4. 配置Storage权限确保前端能读取文件

步骤1:修改HTML,添加PDF展示容器

在你的页面(管理员后台或首页)中添加展示PDF的区域:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cloud Storage Application</title>
    <link rel="stylesheet" href="style.css">
    <style>
        /* 简单的PDF卡片样式,可自定义 */
        .pdf-display-container { margin-top: 30px; }
        .pdf-card { display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ddd; }
        .download-btn { display: block; margin-top: 10px; text-align: center; }
    </style>
</head>
<body>
    <h1>Admin Dashboard</h1>
    <!-- 原上传区域保留 -->
    <div class="upload-area">
        <button class="upload">Upload</button>
        <div class="progress-container">
            <div class="progress"></div>
        </div>
        <div class="percent">0%</div>
        <div class="controls">
            <svg class="pause" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
                <path d="M0 0h24v24H0V0z" fill="none" />
                <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
            </svg>
            <svg class="resume" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
                <path
                    d="M8 6.82v10.36c0 .79.87 1.27 1.54.84l8.14-5.18c.62-.39.62-1.29 0-1.69L9.54 5.98C8.87 5.55 8 6.03 8 6.82z" />
            </svg>
            <svg class="cancel" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
                <path d="M0 0h24v24H0V0z" fill="none" />
                <path
                    d="M18.3 5.71c-.39-.39-1.02-.39-1.41 0L12 10.59 7.11 5.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41L10.59 12 5.7 16.89c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 13.41l4.89 4.89c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z" />
            </svg>
        </div>
        <input type="file" class="hidden-upload-btn" style="display: none;">
    </div>

    <!-- 新增PDF展示区域 -->
    <div class="pdf-display-container">
        <h2>已上传PDF预览</h2>
        <div id="pdf-list"></div>
    </div>

    <script src="https://www.gstatic.com/firebasejs/6.0.2/firebase.js"></script>
    <script src="script.js"></script>
</body>
</html>

步骤2:更新JS代码,实现PDF列表渲染

在你的script.js中添加以下函数,并修改现有逻辑:

// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
    apiKey: "你的API密钥",
    authDomain: "你的Auth域名",
    projectId: "你的项目ID",
    storageBucket: "你的存储桶",
    messagingSenderId: "你的Sender ID",
    appId: "你的App ID",
    measurementId: "你的Measurement ID"
};
firebase.initializeApp(firebaseConfig);

// 获取DOM元素
var upload = document.getElementsByClassName('upload')[0];
var hiddenBtn = document.getElementsByClassName('hidden-upload-btn')[0];
var progress = document.getElementsByClassName('progress')[0];
var percent = document.getElementsByClassName('percent')[0];
var pause = document.getElementsByClassName('pause')[0];
var resume = document.getElementsByClassName('resume')[0];
var cancel = document.getElementsByClassName('cancel')[0];

// 触发文件选择
upload.onclick = function () {
    hiddenBtn.click();
}

// 初始化localStorage存储文件元数据
if(!localStorage.getItem("uploaded-metadata")){
    localStorage.setItem('uploaded-metadata', '[]')
}

// 文件上传逻辑
hiddenBtn.onchange = function () {
    var file = hiddenBtn.files[0];
    // 重命名文件避免覆盖
    var name = file.name.split('.').shift() + Math.floor(Math.random() * 10) + 10 + '.' + file.name.split('.').pop();
    var type = file.type.split('/')[0];
    var path = type + '/' + name;
    var storageRef = firebase.storage().ref(path);
    var uploadTask = storageRef.put(file);

    // 上传控制按钮逻辑
    pause.onclick = function () {
        uploadTask.pause();
        resume.style.display = 'inline-block';
        pause.style.display = 'none';
    }
    resume.onclick = function () {
        uploadTask.resume();
        resume.style.display = 'none';
        pause.style.display = 'inline-block';
    }
    cancel.onclick = function () {
        uploadTask.cancel();
        progress.style.width = '0%';
        percent.innerHTML = '0%';
    }

    upload.disabled = true;
    percent.innerHTML = '0%';

    // 上传进度监听
    uploadTask.on('state_changed',
        (snapshot) => {
            var progressValue = String((snapshot.bytesTransferred / snapshot.totalBytes) * 100).split('.')[0];
            progress.style.width = progressValue + '%';
            percent.innerHTML = progressValue + '%';
        },
        (error) => {
            console.log(error)
        },
        () => {
            // 上传完成后更新元数据并重新渲染PDF列表
            var metadata = JSON.parse(localStorage.getItem('uploaded-metadata'));
            metadata.unshift(path);
            localStorage.setItem("uploaded-metadata", JSON.stringify(metadata));
            percent.innerHTML = 'DONE';
            upload.disabled = false;
            hiddenBtn.value = null;
            renderPDFList(); // 上传完成后刷新列表
        }
    )
}

// 页面加载时自动渲染PDF列表
window.onload = function() {
    renderPDFList();
};

// 渲染已上传的PDF列表
function renderPDFList() {
    const pdfListContainer = document.getElementById('pdf-list');
    const uploadedMetadata = JSON.parse(localStorage.getItem('uploaded-metadata')) || [];
    
    // 过滤出PDF格式的文件
    const pdfFiles = uploadedMetadata.filter(filePath => filePath.toLowerCase().endsWith('.pdf'));
    
    if (pdfFiles.length === 0) {
        pdfListContainer.innerHTML = '<p>暂无已上传的PDF文件</p>';
        return;
    }
    
    // 清空容器避免重复渲染
    pdfListContainer.innerHTML = '';
    
    pdfFiles.forEach(filePath => {
        const storageRef = firebase.storage().ref(filePath);
        // 获取PDF的公开下载链接
        storageRef.getDownloadURL()
            .then(downloadUrl => {
                // 创建PDF预览卡片
                const pdfCard = document.createElement('div');
                pdfCard.className = 'pdf-card';
                
                // 嵌入PDF预览
                const pdfEmbed = document.createElement('embed');
                pdfEmbed.src = downloadUrl;
                pdfEmbed.type = 'application/pdf';
                pdfEmbed.width = '300';
                pdfEmbed.height = '400';
                
                // 添加下载按钮
                const downloadBtn = document.createElement('a');
                downloadBtn.href = downloadUrl;
                downloadBtn.download = filePath.split('/').pop(); // 提取文件名
                downloadBtn.textContent = '下载此PDF';
                downloadBtn.className = 'download-btn';
                
                pdfCard.appendChild(pdfEmbed);
                pdfCard.appendChild(downloadBtn);
                pdfListContainer.appendChild(pdfCard);
            })
            .catch(error => {
                console.error('获取PDF链接失败:', error);
                pdfListContainer.innerHTML += `<p>加载文件失败:${filePath}</p>`;
            });
    });
}

// 修复原openUrl函数的未定义变量问题
function openUrl(v) {
    const path = v.parentElement.getAttribute('data-file-name');
    const storageRef = firebase.storage().ref(path);
    storageRef.getDownloadURL()
        .then(url => {
            // 在新窗口打开PDF
            window.open(url, '_blank');
        })
        .catch(error => {
            console.log(error);
        });
}

步骤3:配置Firebase Storage权限

默认情况下,Firebase Storage的文件只有上传者能读取,若要在首页公开展示,需修改Storage规则:

  1. 打开Firebase控制台 -> 存储 -> 规则
  2. 将默认规则替换为:
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read: if true; // 允许公开读取(后续可结合登录限制)
      allow write: if request.auth != null; // 仅登录用户可上传
    }
  }
}

注意:如果后续要做权限控制,可以把allow read: if true;改成基于用户身份的验证规则,比如request.auth != null或更细粒度的权限。


关键说明

  • 当前用localStorage存储文件路径,仅在单设备有效,后续若要多端同步,建议改用Firebase Realtime Database或Firestore存储文件元数据
  • <embed>标签在大部分浏览器支持PDF预览,若需要兼容更多场景,可替换为<iframe>标签
  • 若PDF文件较大,可添加加载状态提示优化用户体验

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 06:08:11