Web uploader上传word,pdf实例

本文介绍使用 WebUploader 实现文件上传的过程。该实现支持自动上传、文件类型限制及大小限制等功能,并通过 JavaScript 和 HTML 构建了友好的用户交互界面。

看了许多,终于自己做了一个。废话不说,直接上代码

html部分

<div id="uploader" class="wu-example">
    <!--用来存放文件信息-->
    <div id="thelist" class="uploader-list"></div>
    <div class="btns">
        <div id="picker">选择文件</div>
        <button id="ctlBtn" class="btn btn-default">开始上传</button>
    </div>
</div>

js部分

//初始化Web Uploader
    var uploader = WebUploader.create({

        auto: false,                                         //自动上传
        swf: '/css/js/plugins/webuploader/Uploader.swf',     // swf文件路径
        server: '/xxxx/upload/xxxxx',                    // 文件接收服务端。
        pick: '#picker',                                     // 选择文件的按钮。可选。
        accept: {  
            title: 'Files',  
            extensions: 'pdf,doc,docx',
            mimeTypes: 'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'  
                       +',application/pdf'  
        },
        fileNumLimit: 10,                              //最大上传数量为10
        fileSingleSizeLimit: 20 * 1024 * 1024,         //限制上传单个文件大小20M
        fileSizeLimit: 200 * 1024 * 1024,              //限制上传所有文件大小200M
        resize: false                                  // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
    });

    //上传前的判断处理
    uploader.on('error', function( type ){
        if ( type === 'Q_EXCEED_NUM_LIMIT' ) {
            layer.msg('最多允许上传10份xxx');
        } 
        if ( type === 'F_DUPLICATE' ) {
            layer.msg('xxx重复,不能上传!');
        }
        if (type=="Q_TYPE_DENIED"){
            layer.msg("请上传doc、pdf格式文件");
        }else if(type=="F_EXCEED_SIZE"){
            layer.msg("文件大小不能超过20M");
        }
    });

    // 当有文件被添加进队列的时候
    var $list = $("#uploader");
    uploader.on( 'fileQueued', function( file ) {
        $list.append( '<div id="' + file.id + '" class="item">' +
            '<h4 class="info">' + file.name + '</h4>' +
            '<p class="state">等待上传...</p>' + 
            '<a class="webuploadDelbtn">删除</a><br/>' +
        '</div>' );
    });

    //点击开始上传
     $("#ctlBtn").on( 'click', function() {  
         uploader.upload();  
     });

    // 文件上传过程中创建进度条实时显示。
    uploader.on( 'uploadProgress', function( file, percentage ) {
        var $li = $( '#'+file.id ),
            $percent = $li.find('.progress .progress-bar');

        // 避免重复创建
        if ( !$percent.length ) {
            $percent = $('<div class="progress progress-striped active">' +
              '<div class="progress-bar" role="progressbar" style="width: 0%">' +
              '</div>' +
            '</div>').appendTo( $li ).find('.progress-bar');
        }
        $li.find('p.state').text('上传中');

        $percent.css( 'width', percentage * 100 + '%' );
    });


    //文件成功、失败处理
    uploader.on( 'uploadSuccess', function( file ) {
        $( '#'+file.id ).find('p.state').text('已上传');
        $( '#'+file.id ).find('a.webuploadDelbtn').remove();
    });
    //上传错误
    uploader.on( 'uploadError', function( file ) {
        $( '#'+file.id ).find('p.state').text('上传出错');
    });
    //上传完成
    uploader.on( 'uploadComplete', function( file ) {
        $( '#'+file.id ).find('.progress').fadeOut();
    });

    //删除
    $list.on("click", ".webuploadDelbtn", function () {
        var $ele = $(this);
        var id = $ele.parent().attr("id");
        var file = uploader.getFile(id);
        uploader.removeFile(file,true);  
    }); 

    //删除时执行的方法
    uploader.on('fileDequeued', function (file) {
        $(file.id).remove();
        $('#'+file.id ).find('span.state').text('已经取消');
        $('#'+file.id).hide();   
        console.log("remove");     
    }); 

java 后台

    @RequestMapping("/xxx")
    @ResponseBody
    public void uploaderResumes(@RequestParam("file") MultipartFile file, HttpServletRequest request) {  
        // 判断文件是否为空  
        if (!file.isEmpty()) {  
            try {  
                // 文件保存路径  
                String filePath = request.getSession().getServletContext().getRealPath("/") + "upload" 
                        + System.getProperty("file.separator") 
                        + file.getOriginalFilename();  
                // 转存文件  
                file.transferTo(new File(filePath));  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }

图片

样式

```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>是否有附件 · 预览附件(PDF/Word/Excel/PPT)</title> <style> :root { --c: #409eff; --bg: #f7f9fc; --card: #fff; --bd: #e6e8ef; --tx: #303133; --mut: #909399; } body { margin: 0; background: var(--bg); font: 14px/1.6, "SF Pro", "PingFang SC", "Microsoft YaHei", Arial; } .wrap { max-width: 1100px; margin: 28px auto; padding: 0 16px; } .card { background: var(--card); border: 1px solid var(--bd); border-radius: 10px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.05); } .hd { padding: 16px 18px; border-bottom: 1px solid var(--bd); display: flex; align-items: center; justify-content: space-between; } .hd h2 { margin: 0; font-size: 18px; } .bd { padding: 18px; } .tips { background: #f0f6ff; border: 1px dashed #cfe2ff; border-radius: 8px; padding: 10px 12px; color: #2b6fe0; margin-bottom: 14px; } .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .item { border: 1px solid var(--bd); border-radius: 8px; overflow: hidden; background: #fff; } .item .meta { padding: 8px 10px; border-bottom: 1px solid var(--bd); display: flex; justify-content: space-between; align-items: center; } .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 70%; } .btn { border: 1px solid var(--bd); background: #fff; border-radius: 6px; padding: 4px 8px; cursor: pointer; } .pre { height: 240px; display: flex; align-items: center; justify-content: center; background: #fafafa; } .pre img, .pre video { max-width: 100%; max-height: 100%; } .pre--doc { color: var(--mut); font-size: 13px; } .ft { padding: 12px 18px; border-top: 1px solid var(--bd); display: flex; gap: 10px; justify-content: flex-end; } input[type="file"] { display: none; } .uploader { display: inline-flex; align-items: center; gap: 8px; color: #fff; background: var(--c); border-radius: 8px; padding: 8px 12px; cursor: pointer; } .note { color: var(--mut); font-size: 12px; margin-left: 8px; } @media (max-width: 900px) { .grid { grid-template-columns: 1fr; } } /* 预览弹窗 */ .modal { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); display: none; align-items: center; justify-content: center; padding: 24px; z-index: 9999; } .modal.show { display: flex; } .modal .box { background: #000; border-radius: 8px; max-width: 96vw; max-height: 90vh; width: 100%; display: flex; flex-direction: column; } .modal .bar { display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; background: #111; color: #fff; } .modal .bar .title { font-size: 13px; opacity: 0.9; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .modal .bar .act button { background: #2b6fe0; color: #fff; border: none; border-radius: 6px; padding: 6px 10px; cursor: pointer; } .modal .cnt { flex: 1; background: #111; } .modal iframe { width: 100%; height: 100%; border: 0; background: #fff; } .modal canvas { display: block; margin: 0 auto; max-width: 100%; height: 100%; } </style> </head> <body> <div class="wrap"> <div class="card"> <div class="hd"> <h2>是否有附件 · 预览附件</h2> <div> <label class="uploader" for="fileInput">选择附件</label> <span class="note" >支持:PDFWord(doc/docx)、Excel(xls/xlsx)、PPT(ppt/pptx)、图片、音视频、TXT</span > <input id="fileInput" type="file" multiple /> </div> </div> <div class="bd"> <div class="tips"> - PDF 将在页面内直接预览(使用内置 PDF 渲染)。<br /> - Word/Excel/PPT 若是在线地址(http/https),使用微软 Office 在线预览;本地文件则建议先上传生成可访问链接,再在线预览,否则只能下载或用本地应用打开。 </div> <div id="list" class="grid"></div> </div> <div class="ft"> <button class="btn" id="clearBtn">清空</button> <button class="btn" id="downloadAllBtn">全部下载(逐个)</button> </div> </div> </div> <!-- 预览弹窗(用于 Office 在线预览 & PDF 全屏) --> <div class="modal" id="previewModal"> <div class="box"> <div class="bar"> <div class="title" id="modalTitle">预览</div> <div class="act"> <button id="openNewTabBtn" title="在新窗口打开">新窗口打开</button> <button id="closeModalBtn" style="margin-left: 8px; background: #444" > 关闭 </button> </div> </div> <div class="cnt" id="modalContent"></div> </div> </div> <!-- pdf.js(本地渲染 PDF) --> <script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@4.8.69/build/pdf.min.js"></script> <script> // pdf.js 基本配置 if (window["pdfjsLib"]) { pdfjsLib.GlobalWorkerOptions.workerSrc = "https://cdn.jsdelivr.net/npm/pdfjs-dist@4.8.69/build/pdf.worker.min.js"; } const fileInput = document.getElementById("fileInput"); const list = document.getElementById("list"); const clearBtn = document.getElementById("clearBtn"); const downloadAllBtn = document.getElementById("downloadAllBtn"); const modal = document.getElementById("previewModal"); const modalTitle = document.getElementById("modalTitle"); const modalContent = document.getElementById("modalContent"); const openNewTabBtn = document.getElementById("openNewTabBtn"); const closeModalBtn = document.getElementById("closeModalBtn"); const docExt = [ "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", ]; const imgExt = ["jpg", "jpeg", "png", "gif", "webp"]; const videoExt = ["mp4", "webm", "ogg"]; const audioExt = ["mp3", "wav", "ogg"]; function extOf(name = "") { const i = name.lastIndexOf("."); return i > -1 ? name.slice(i + 1).toLowerCase() : ""; } const isHttpUrl = (url) => /^https?:\/\//i.test(url); const isDoc = (e) => docExt.includes(e); const isImg = (e) => imgExt.includes(e); const isVideo = (e) => videoExt.includes(e); const isAudio = (e) => audioExt.includes(e); // —— PDF 预览(用 pdf.js 渲染首页,点击可全屏弹窗查看更多页) async function renderPdfToCanvas(url, canvas) { const pdf = await pdfjsLib.getDocument(url).promise; const page = await pdf.getPage(1); const viewport = page.getViewport({ scale: 1.3 }); const ctx = canvas.getContext("2d"); canvas.width = viewport.width; canvas.height = viewport.height; await page.render({ canvasContext: ctx, viewport }).promise; return pdf.numPages; } function openPdfInModal(url, fileName) { // 在弹窗里用 <iframe> 嵌入内置 pdf.js 简单阅读器(使用 data url 会受限,这里直接渲染多页较复杂;简化为嵌入浏览器原生 pdf 查看) modalTitle.textContent = fileName || "PDF 预览"; modalContent.innerHTML = ""; const ifr = document.createElement("iframe"); ifr.src = url; // 大多数现代浏览器可直接显示 PDF modalContent.appendChild(ifr); openNewTabBtn.onclick = () => window.open(url, "_blank"); modal.classList.add("show"); } // —— Office 在线预览(仅对 http/https 可访问链接) function officeViewerUrl(srcUrl) { return `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent( srcUrl )}`; } function openOfficeInModal(srcUrl, fileName) { modalTitle.textContent = fileName || "Office 在线预览"; modalContent.innerHTML = ""; const ifr = document.createElement("iframe"); ifr.src = officeViewerUrl(srcUrl); modalContent.appendChild(ifr); openNewTabBtn.onclick = () => window.open(officeViewerUrl(srcUrl), "_blank"); modal.classList.add("show"); } closeModalBtn.onclick = () => modal.classList.remove("show"); modal.addEventListener("click", (e) => { if (e.target === modal) modal.classList.remove("show"); }); function makeItemFromSource(name, url, isLocalBlob) { const e = extOf(name); const item = document.createElement("div"); item.className = "item"; const meta = document.createElement("div"); meta.className = "meta"; meta.innerHTML = ` <span class="name" title="${name}">${name}</span> <div> <button class="btn" data-act="open">预览/打开</button> <button class="btn" data-act="download">下载</button> </div>`; item.appendChild(meta); const pre = document.createElement("div"); pre.className = "pre"; if (e === "pdf") { // 首屏渲染 PDF 第一页缩略 const canvas = document.createElement("canvas"); pre.appendChild(canvas); renderPdfToCanvas(url, canvas).catch(() => { pre.classList.add("pre--doc"); pre.textContent = "PDF 预览失败(可点击右上角预览/打开)"; }); } else if (isImg(e)) { const img = document.createElement("img"); img.src = url; pre.appendChild(img); } else if (isVideo(e)) { const v = document.createElement("video"); v.src = url; v.controls = true; pre.appendChild(v); } else if (isAudio(e)) { const a = document.createElement("audio"); a.src = url; a.controls = true; pre.appendChild(a); } else if (e === "txt") { pre.classList.add("pre--doc"); fetch(url) .then((r) => r.text()) .then((t) => { pre.textContent = (t || "").slice(0, 300) + (t.length > 300 ? " ..." : ""); }) .catch(() => (pre.textContent = "TXT 预览失败")); } else if (["doc", "docx", "xls", "xlsx", "ppt", "pptx"].includes(e)) { pre.classList.add("pre--doc"); pre.innerHTML = isLocalBlob ? "本地文件无法直接在线预览,请先上传生成可访问链接,或点击“下载”本地打开" : "点击“预览/打开”使用微软 Office 在线预览"; } else { pre.classList.add("pre--doc"); pre.textContent = "不支持预览的文件类型"; } item.appendChild(pre); meta.addEventListener("click", (ev) => { const act = ev.target?.dataset?.act; if (!act) return; if (act === "download") { const a = document.createElement("a"); a.href = url; a.download = name; document.body.appendChild(a); a.click(); a.remove(); } else if (act === "open") { if (e === "pdf") { openPdfInModal(url, name); } else if ( ["doc", "docx", "xls", "xlsx", "ppt", "pptx"].includes(e) ) { if (isLocalBlob) { alert( "本地文件无法使用在线预览,请先上传生成 http/https 可访问链接,或直接下载后在本地 Office 中打开。" ); } else if (isHttpUrl(url)) { openOfficeInModal(url, name); } else { window.open(url, "_blank"); } } else { window.open(url, "_blank"); } } }); return item; } function addFiles(files) { Array.from(files).forEach((file) => { const url = URL.createObjectURL(file); list.appendChild(makeItemFromSource(file.name, url, true)); }); } // 选择文件 fileInput.addEventListener("change", (e) => addFiles(e.target.files)); // 支持拖拽 document.addEventListener("dragover", (e) => e.preventDefault()); document.addEventListener("drop", (e) => { e.preventDefault(); if (e.dataTransfer?.files?.length) addFiles(e.dataTransfer.files); }); // 清空 clearBtn.addEventListener("click", () => { list.innerHTML = ""; fileInput.value = ""; }); // 全部下载 downloadAllBtn.addEventListener("click", () => { list .querySelectorAll('.item .meta [data-act="download"]') .forEach((btn) => btn.click()); }); // =========== 如需预览线上(HTTP/HTTPS)文件,可用此示例追加 =========== // const onlineFiles = [ // { name:'在线-PDF示例.pdf', url:'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' }, // { name:'在线-Word示例.docx', url:'https://file-examples.com/storage/fe5b6e3d3b2b7f1/example.docx' }, // { name:'在线-Excel示例.xlsx', url:'https://file-examples.com/storage/fe5b6e3d3b2b7f1/example.xlsx' }, // { name:'在线-PPT示例.pptx', url:'https://file-examples.com/storage/fe5b6e3d3b2b7f1/example.pptx' } // ]; // onlineFiles.forEach(f => list.appendChild(makeItemFromSource(f.name, f.url, false))); </script> </body> </html> 改成vue实现
10-18
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值