乐于分享
好东西不私藏

基于Canvas与jsPDF的图片合并PDF方案:从拖拽排序到流式生成

基于Canvas与jsPDF的图片合并PDF方案:从拖拽排序到流式生成
点击上方蓝字订阅!

在Web端处理文档生成任务时,将多张图片合并为一个PDF文件是常见需求,其应用场景覆盖电子相册、作品集、扫描件归档等。本文构建一个完整、可运行的HTML工具,它不仅支持图片的上传、预览、拖拽排序,还通过jsPDFCanvas实现高质量PDF导出。核心设计兼顾用户体验与性能,对图片格式统一、内存管理、页面适配等关键问题给出了实用解法。


完整代码

<!DOCTYPE html>
<htmllang="zh-CN">
<head>
<metacharset="UTF-8" />
<metaname="viewport"content="width=device-width, initial-scale=1.0" />
<title>图片合并PDF工具</title>
<!-- jsPDF CDN -->
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js">
</script>
<!-- Sortable.js CDN (拖拽排序) -->
<scriptsrc="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js">
</script>
<style>
        * {
margin0;
padding0;
box-sizing: border-box;
        }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background#f0f4ff;
min-height100vh;
display: flex;
justify-content: center;
align-items: center;
padding20px;
        }
.app {
max-width1100px;
width100%;
background#ffffff;
border-radius24px;
box-shadow020px60pxrgba(911272550.15);
padding32px36px40px;
transition: box-shadow 0.3s;
        }
.app-header {
display: flex;
align-items: center;
gap14px;
margin-bottom24px;
flex-wrap: wrap;
        }
.app-header.icon {
font-size32px;
line-height1;
        }
.app-headerh1 {
font-size26px;
font-weight700;
color#1a2332;
letter-spacing: -0.5px;
        }
.app-header.sub {
margin-left: auto;
font-size14px;
color#8b9ab5;
background#f0f4ff;
padding4px16px;
border-radius30px;
font-weight500;
        }
.drop-zone {
border2.5px dashed #d0d9e8;
border-radius18px;
padding48px20px;
text-align: center;
cursor: pointer;
transition: all 0.25s ease;
background#fafcff;
position: relative;
        }
.drop-zone:hover,
.drop-zone.dragover {
border-color#5b7fff;
background#f0f6ff;
transformscale(1.005);
        }
.drop-zone.upload-icon {
font-size52px;
display: block;
margin-bottom12px;
        }
.drop-zone.main-text {
font-size18px;
font-weight600;
color#1a2332;
        }
.drop-zone.sub-text {
font-size14px;
color#8b9ab5;
margin-top6px;
        }
.drop-zone.hint {
font-size13px;
color#b0c0d8;
margin-top12px;
background#f0f4ff;
display: inline-block;
padding4px18px;
border-radius30px;
        }
.drop-zoneinput[type="file"] {
position: absolute;
inset0;
opacity0;
cursor: pointer;
        }
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-top24px;
margin-bottom18px;
flex-wrap: wrap;
gap12px;
        }
.toolbar.info {
font-size15px;
color#1a2332;
font-weight500;
background#f0f4ff;
padding6px18px;
border-radius30px;
        }
.toolbar.infospan {
font-weight700;
color#5b7fff;
        }
.toolbar.actions {
display: flex;
gap10px;
flex-wrap: wrap;
        }
.btn {
display: inline-flex;
align-items: center;
gap8px;
padding10px24px;
border: none;
border-radius40px;
font-size15px;
font-weight600;
cursor: pointer;
transition: all 0.2s ease;
background#f0f4ff;
color#1a2332;
        }
.btn:hover {
transformtranslateY(-2px);
box-shadow06px20pxrgba(0000.06);
        }
.btn:active {
transformtranslateY(0);
        }
.btn-primary {
background#5b7fff;
color#fff;
box-shadow04px14pxrgba(911272550.30);
        }
.btn-primary:hover {
background#4a6de8;
box-shadow08px24pxrgba(911272550.40);
        }
.btn-primary:disabled {
opacity0.5;
cursor: not-allowed;
transform: none;
box-shadow: none;
        }
.btn-danger {
background#fee8e8;
color#c0392b;
        }
.btn-danger:hover {
background#fdd5d5;
        }
.btn-outline {
background: transparent;
border1.5px solid #d0d9e8;
        }
.btn-outline:hover {
border-color#5b7fff;
color#5b7fff;
background#f0f6ff;
        }
.image-grid {
display: grid;
grid-template-columnsrepeat(auto-fill, minmax(160px1fr));
gap16px;
margin-top6px;
min-height80px;
padding6px2px;
        }
.image-grid-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color#b0c0d8;
font-size15px;
padding40px0;
grid-column1 / -1;
        }
.image-grid-empty.empty-icon {
font-size48px;
margin-bottom10px;
opacity0.6;
        }
.image-card {
background#ffffff;
border-radius16px;
box-shadow02px12pxrgba(0000.04);
border1px solid #eef2f8;
overflow: hidden;
position: relative;
transition: all 0.2s ease;
cursor: grab;
user-select: none;
        }
.image-card:hover {
box-shadow08px28pxrgba(0000.08);
border-color#d0d9e8;
        }
.image-card.sortable-ghost {
opacity0.3;
border-color#5b7fff;
transformscale(0.96);
        }
.image-card.card-thumb {
width100%;
aspect-ratio1 / 1;
object-fit: cover;
display: block;
background#f5f8ff;
        }
.image-card.card-index {
position: absolute;
top8px;
left8px;
backgroundrgba(2635500.72);
backdrop-filterblur(6px);
color#fff;
font-size12px;
font-weight700;
width26px;
height26px;
border-radius50%;
display: flex;
align-items: center;
justify-content: center;
letter-spacing0.5px;
box-shadow02px8pxrgba(0000.12);
        }
.image-card.card-name {
padding10px12px8px;
font-size13px;
font-weight500;
color#1a2332;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
background#fafcff;
border-top1px solid #f0f4ff;
        }
.image-card.card-size {
padding012px10px;
font-size11px;
color#a0b0c8;
background#fafcff;
        }
.image-card.card-delete {
position: absolute;
top8px;
right8px;
width28px;
height28px;
border-radius50%;
border: none;
backgroundrgba(2552552550.85);
backdrop-filterblur(6px);
color#e74c3c;
font-size16px;
line-height1;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
box-shadow02px8pxrgba(0000.06);
font-weight700;
        }
.image-card.card-delete:hover {
background#fee8e8;
transformscale(1.08);
        }
.image-card.drag-handle {
position: absolute;
bottom8px;
right8px;
color#b0c0d8;
font-size14px;
cursor: grab;
opacity0.5;
transition: opacity 0.2s;
backgroundrgba(2552552550.7);
padding2px6px;
border-radius12px;
backdrop-filterblur(4px);
        }
.image-card:hover.drag-handle {
opacity0.9;
        }
.loading-overlay {
position: fixed;
inset0;
backgroundrgba(2635500.55);
backdrop-filterblur(6px);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index999;
opacity0;
pointer-events: none;
transition: opacity 0.3s ease;
        }
.loading-overlay.active {
opacity1;
pointer-events: auto;
        }
.loading-box {
background#ffffff;
padding40px48px36px;
border-radius24px;
box-shadow030px80pxrgba(0000.25);
text-align: center;
max-width400px;
width90%;
        }
.loading-box.spinner {
display: inline-block;
width52px;
height52px;
border-radius50%;
border4px solid #eef2f8;
border-top-color#5b7fff;
animation: spin 0.9s linear infinite;
margin-bottom18px;
        }
@keyframes spin {
to { transformrotate(360deg); }
        }
.loading-box.load-title {
font-size20px;
font-weight700;
color#1a2332;
        }
.loading-box.load-desc {
font-size14px;
color#8b9ab5;
margin-top6px;
        }
.loading-box.load-progress {
margin-top18px;
height6px;
background#eef2f8;
border-radius10px;
overflow: hidden;
        }
.loading-box.load-progress.bar {
height100%;
width0%;
backgroundlinear-gradient(90deg#5b7fff#7c99ff);
border-radius10px;
transition: width 0.3s ease;
        }
@media (max-width700px) {
.app { padding20px18px28px; }
.app-headerh1 { font-size21px; }
.app-header.sub { font-size12pxpadding2px12px; }
.drop-zone { padding32px16px; }
.drop-zone.upload-icon { font-size40px; }
.drop-zone.main-text { font-size16px; }
.image-grid { grid-template-columnsrepeat(auto-fill, minmax(130px1fr)); gap12px; }
.btn { padding8px18pxfont-size14px; }
.toolbar { flex-direction: column; align-items: stretch; }
.toolbar.actions { justify-content: stretch; }
.toolbar.actions.btn { flex1justify-content: center; }
.loading-box { padding28px20px24px; }
        }
@media (max-width480px) {
.image-grid { grid-template-columnsrepeat(auto-fill, minmax(100px1fr)); gap10px; }
.app-header.icon { font-size26px; }
.app-headerh1 { font-size18px; }
        }
        ::-webkit-scrollbar { width6pxheight6px; }
        ::-webkit-scrollbar-track { background#f0f4ffborder-radius10px; }
        ::-webkit-scrollbar-thumb { background#d0d9e8border-radius10px; }
        ::-webkit-scrollbar-thumb:hover { background#b0c0d8; }
</style>
</head>
<body>
<divclass="app"id="app">
<headerclass="app-header">
<spanclass="icon">📄</span>
<h1>图片合并 PDF</h1>
<spanclass="sub">拖拽排序 · 一键导出</span>
</header>
<divclass="drop-zone"id="dropZone">
<spanclass="upload-icon">🖼️</span>
<divclass="main-text">点击上传或拖拽图片到此处</div>
<divclass="sub-text">支持 JPG / PNG / BMP / WebP 等格式</div>
<divclass="hint">📎 可选择多张图片,按顺序合并</div>
<inputtype="file"id="fileInput"accept="image/*"multiple />
</div>
<divclass="toolbar">
<divclass="info">📦 已上传 <spanid="imageCount">0</span> 张</div>
<divclass="actions">
<buttonclass="btn btn-outline"id="clearBtn"disabled>🗑️ 清空</button>
<buttonclass="btn btn-primary"id="mergeBtn"disabled>📥 合并 PDF</button>
</div>
</div>
<divclass="image-grid"id="imageGrid">
<divclass="image-grid-empty">
<spanclass="empty-icon">🖼️</span>
<span>暂无图片,请上传</span>
</div>
</div>
</div>
<divclass="loading-overlay"id="loadingOverlay">
<divclass="loading-box">
<divclass="spinner"></div>
<divclass="load-title"id="loadTitle">正在生成 PDF…</div>
<divclass="load-desc"id="loadDesc">请稍候,正在处理图片</div>
<divclass="load-progress">
<divclass="bar"id="progressBar"></div>
</div>
</div>
</div>
<script>
        (function() {
'use strict';
const state = { images: [], idCounter0 };
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const imageGrid = document.getElementById('imageGrid');
const imageCount = document.getElementById('imageCount');
const mergeBtn = document.getElementById('mergeBtn');
const clearBtn = document.getElementById('clearBtn');
const loadingOverlay = document.getElementById('loadingOverlay');
const loadTitle = document.getElementById('loadTitle');
const loadDesc = document.getElementById('loadDesc');
const progressBar = document.getElementById('progressBar');

functionformatFileSize(bytes) {
if (bytes < 1024return bytes + ' B';
if (bytes < 1048576return (bytes / 1024).toFixed(1) + ' KB';
return (bytes / 1048576).toFixed(1) + ' MB';
            }

functionreadFileAsDataURL(file) {
returnnewPromise((resolve, reject) => {
const reader = newFileReader();
                    reader.onload = () =>resolve(reader.result);
                    reader.onerror = () =>reject(reader.error);
                    reader.readAsDataURL(file);
                });
            }

functiongetImageDimensions(dataURL) {
returnnewPromise((resolve, reject) => {
const img = newImage();
                    img.onload = () =>resolve({ width: img.widthheight: img.height });
                    img.onerror = () =>reject(newError('图片加载失败'));
                    img.src = dataURL;
                });
            }

functionconvertToJPEG(dataURL, quality = 0.92) {
returnnewPromise((resolve, reject) => {
const img = newImage();
                    img.onload = function() {
try {
const canvas = document.createElement('canvas');
                            canvas.width = img.width;
                            canvas.height = img.height;
const ctx = canvas.getContext('2d');
                            ctx.drawImage(img, 00);
resolve(canvas.toDataURL('image/jpeg', quality));
                        } catch (err) { reject(err); }
                    };
                    img.onerror = () =>reject(newError('图片转换失败'));
                    img.src = dataURL;
                });
            }

functionrender() {
const items = state.images;
const count = items.length;
                imageCount.textContent = count;
                mergeBtn.disabled = count === 0;
                clearBtn.disabled = count === 0;
                imageGrid.innerHTML = '';
if (count === 0) {
                    imageGrid.innerHTML = `
                        <div class="image-grid-empty">
                            <span class="empty-icon">🖼️</span>
                            <span>暂无图片,请上传</span>
                        </div>
                    `
;
return;
                }
                items.forEach((img, index) => {
const card = document.createElement('div');
                    card.className = 'image-card';
                    card.dataset.id = img.id;
const thumb = document.createElement('img');
                    thumb.className = 'card-thumb';
                    thumb.src = img.dataURL;
                    thumb.alt = img.name;
                    thumb.loading = 'lazy';
const indexBadge = document.createElement('div');
                    indexBadge.className = 'card-index';
                    indexBadge.textContent = index + 1;
const nameDiv = document.createElement('div');
                    nameDiv.className = 'card-name';
                    nameDiv.textContent = img.name;
const sizeDiv = document.createElement('div');
                    sizeDiv.className = 'card-size';
                    sizeDiv.textContent = `${img.width}×${img.height} · ${formatFileSize(img.fileSize)}`;
const delBtn = document.createElement('button');
                    delBtn.className = 'card-delete';
                    delBtn.innerHTML = '×';
                    delBtn.title = '删除此图片';
                    delBtn.addEventListener('click'(e) => {
                        e.stopPropagation();
deleteImage(img.id);
                    });
const handle = document.createElement('div');
                    handle.className = 'drag-handle';
                    handle.textContent = '⠿';
                    handle.title = '拖拽调整顺序';
                    card.appendChild(thumb);
                    card.appendChild(indexBadge);
                    card.appendChild(nameDiv);
                    card.appendChild(sizeDiv);
                    card.appendChild(delBtn);
                    card.appendChild(handle);
                    imageGrid.appendChild(card);
                });
initSortable();
            }

let sortableInstance = null;

functioninitSortable() {
if (sortableInstance) { sortableInstance.destroy(); sortableInstance = null; }
if (state.images.length === 0return;
                sortableInstance = newSortable(imageGrid, {
animation200,
easing'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
handle'.drag-handle',
ghostClass'sortable-ghost',
onEndfunction(evt) {
constfrom = evt.oldIndex;
const to = evt.newIndex;
if (from === to) return;
const moved = state.images.splice(from1)[0];
                        state.images.splice(to, 0, moved);
render();
                    },
                });
            }

asyncfunctionuploadImages(files) {
const validFiles = [];
for (const file of files) {
if (!file.type.startsWith('image/')) continue;
                    validFiles.push(file);
                }
if (validFiles.length === 0) {
showToast('⚠️ 未选择有效的图片文件''warning');
return;
                }
for (const file of validFiles) {
try {
const dataURL = awaitreadFileAsDataURL(file);
const dims = awaitgetImageDimensions(dataURL);
const jpegData = awaitconvertToJPEG(dataURL, 0.92);
                        state.images.push({
id: ++state.idCounter,
dataURL: jpegData,
name: file.name || `image_${state.idCounter}.jpg`,
width: dims.width,
height: dims.height,
fileSize: file.size,
                        });
                        imageCount.textContent = state.images.length;
                    } catch (err) {
console.warn('跳过图片:', file.name, err);
                    }
                }
render();
showToast(`✅ 成功上传 ${state.images.length} 张图片`'success');
            }

functiondeleteImage(id) {
const idx = state.images.findIndex(img => img.id === id);
if (idx === -1return;
                state.images.splice(idx, 1);
render();
if (state.images.length === 0showToast('已清空所有图片''info');
            }

functionclearAll() {
if (state.images.length === 0return;
if (!confirm('确定要清空所有图片吗?')) return;
                state.images = [];
render();
showToast('已清空所有图片''info');
            }

asyncfunctionmergeToPDF() {
const count = state.images.length;
if (count === 0) {
showToast('⚠️ 请先上传图片''warning');
return;
                }
                loadingOverlay.classList.add('active');
                loadTitle.textContent = '正在生成 PDF…';
                loadDesc.textContent = `共 ${count} 张图片,请稍候`;
                progressBar.style.width = '0%';
try {
const { jsPDF } = window.jspdf;
const pdf = newjsPDF('p''mm''a4');
const pageWidth = pdf.internal.pageSize.getWidth();
const pageHeight = pdf.internal.pageSize.getHeight();
const margin = 8;
for (let i = 0; i < count; i++) {
const pct = ((i / count) * 100).toFixed(0);
                        progressBar.style.width = pct + '%';
                        loadDesc.textContent = `正在处理第 ${i + 1}/${count} 张图片`;
const img = state.images[i];
const imgObj = newImage();
                        imgObj.src = img.dataURL;
awaitnewPromise((resolve, reject) => {
                            imgObj.onload = resolve;
                            imgObj.onerror = reject;
                        });
const maxW = pageWidth - margin * 2;
const maxH = pageHeight - margin * 2;
const ratio = Math.min(maxW / imgObj.width, maxH / imgObj.height1);
let drawW = imgObj.width * ratio;
let drawH = imgObj.height * ratio;
if (ratio >= 1) {
                            drawW = Math.min(imgObj.width, maxW);
                            drawH = Math.min(imgObj.height, maxH);
if (imgObj.width > maxW || imgObj.height > maxH) {
const r2 = Math.min(maxW / imgObj.width, maxH / imgObj.height);
                                drawW = imgObj.width * r2;
                                drawH = imgObj.height * r2;
                            }
                        }
const x = (pageWidth - drawW) / 2;
const y = (pageHeight - drawH) / 2;
if (i > 0) pdf.addPage();
                        pdf.addImage(img.dataURL'JPEG', x, y, drawW, drawH);
                    }
                    progressBar.style.width = '100%';
                    loadDesc.textContent = '✅ PDF 生成完成,即将下载';
const now = newDate();
const ts = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}-${String(now.getDate()).padStart(2,'0')}`;
const fileName = `合并图片_${ts}.pdf`;
                    pdf.save(fileName);
awaitnewPromise(r =>setTimeout(r, 600));
                } catch (err) {
console.error('PDF 生成失败:', err);
                    loadTitle.textContent = '❌ 生成失败';
                    loadDesc.textContent = err.message || '未知错误,请重试';
awaitnewPromise(r =>setTimeout(r, 1500));
                } finally {
                    loadingOverlay.classList.remove('active');
                    progressBar.style.width = '0%';
                }
            }

functionshowToast(msg, type = 'info') {
const old = document.querySelector('.custom-toast');
if (old) old.remove();
const toast = document.createElement('div');
                toast.className = 'custom-toast';
                toast.textContent = msg;
Object.assign(toast.style, {
position'fixed',
bottom'30px',
left'50%',
transform'translateX(-50%)',
background: type === 'warning' ? '#f39c12' :
                        type === 'success' ? '#2ecc71' :
                        type === 'error' ? '#e74c3c' : '#34495e',
color'#fff',
padding'12px 28px',
borderRadius'40px',
fontSize'15px',
fontWeight'600',
boxShadow'0 8px 30px rgba(0,0,0,0.18)',
zIndex'1000',
maxWidth'90%',
textAlign'center',
fontFamily'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
opacity'0',
transition'opacity 0.4s ease, transform 0.4s ease',
transform'translateX(-50%) translateY(20px)',
pointerEvents'none',
                });
document.body.appendChild(toast);
requestAnimationFrame(() => {
                    toast.style.opacity = '1';
                    toast.style.transform = 'translateX(-50%) translateY(0)';
                });
setTimeout(() => {
                    toast.style.opacity = '0';
                    toast.style.transform = 'translateX(-50%) translateY(20px)';
setTimeout(() => toast.remove(), 400);
                }, 2800);
            }

            fileInput.addEventListener('change'(e) => {
if (e.target.files.length > 0) {
uploadImages(e.target.files);
                }
                fileInput.value = '';
            });
            dropZone.addEventListener('dragover'(e) => {
                e.preventDefault();
                dropZone.classList.add('dragover');
            });
            dropZone.addEventListener('dragleave'(e) => {
                e.preventDefault();
                dropZone.classList.remove('dragover');
            });
            dropZone.addEventListener('drop'(e) => {
                e.preventDefault();
                dropZone.classList.remove('dragover');
if (e.dataTransfer.files.length > 0) {
uploadImages(e.dataTransfer.files);
                }
            });
            dropZone.addEventListener('click'(e) => {
if (e.target.tagName === 'INPUT'return;
                fileInput.click();
            });
            mergeBtn.addEventListener('click', mergeToPDF);
            clearBtn.addEventListener('click', clearAll);
document.addEventListener('keydown'(e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                    e.preventDefault();
if (!mergeBtn.disabled) mergeBtn.click();
                }
            });
render();
if (window.File && window.FileReader && window.FileList) { } else {
showToast('⚠️ 您的浏览器不支持此功能,请使用现代浏览器''warning');
            }
        })();
</script>
</body>
</html>

技术剖析与设计考量

浏览器端生成PDF并非简单地将图片“粘贴”进文档,而是涉及图像解码、尺寸适配、压缩编码以及内存管理等一系列底层操作。本工具以jsPDF为PDF生成引擎,但jsPDFaddImage方法接受DataURL或Image对象,其内部依赖Canvas绘制。为了确保兼容性,我们先将所有图片通过Canvas转换为JPEG格式,JPEG是PDF规范中最广泛支持的图像格式,且可调节压缩质量(本工具设为0.92),在文件大小与视觉保真度间取得平衡。这一转换过程的数学本质是离散余弦变换(DCT)与量化,但使用者无需关心细节,我们将其封装在convertToJPEG函数中。

PDF页面尺寸固定为A4(),每张图片独立成页,且需居中显示。这里的关键在于计算图片在页面上的绘制尺寸。设图片原始宽度为 ,高度为 ,页面可用宽度为 ,可用高度为 ,其中  为边距。缩放比例  取 ,使得图片在不超出页面的前提下尽可能放大,但不会超过原始尺寸(即不放大模糊)。最终绘制尺寸为 ,左上角坐标 ,实现完美居中。代码中还额外处理了图片本身小于页面但宽高比导致某一维度超出的情况,确保所有图片均完整可见。

拖拽排序采用Sortable.js库,其通过CSS transform实现平滑动画。我们将其限制在.drag-handle元素上,避免误触。排序完成后,底层数组state.images重新排列并触发重新渲染,序号自动更新,PDF输出的顺序也随之同步。这一过程体现了“数据驱动视图”的思想,所有UI状态均由state派生,保证一致性。

上传流程采用异步流式处理,每张图片经历读取、解码、转换、存储四个阶段。为了提升用户体验,我们实时更新计数,并在合并时显示加载遮罩与进度条。进度计算基于循环索引,虽然实际PDF生成耗时远低于图像转换,但进度反馈能有效缓解用户焦虑。键盘快捷键(Ctrl+Enter)的加入进一步提升了操作效率,符合专业工具的习惯。

内存管理方面,所有图片数据以DataURL形式保存在内存中,对于大量图片可能引发内存压力。但考虑到浏览器端通常处理几十张以内的图片,且DataURL经过JPEG压缩后体积可控,此设计足以满足常见需求。若需优化,可考虑将图片转为Blob URL或使用IndexedDB缓存,但会牺牲简便性。

最后,界面设计采用毛玻璃效果、柔和阴影与圆角卡片,视觉上贴近现代应用审美。响应式布局适配移动设备,确保在手机端也能完成上传与合并操作。整个工具无需任何后端服务,完全运行于客户端,保护用户数据隐私,这也是Web端文档处理的一大优势。

通过上述实现,我们获得了一个功能完备、代码健壮且易于扩展的图片合并PDF工具。其核心逻辑可复用于电子发票合并、扫描件整理、报告生成等更复杂的业务场景,仅需在此基础上调整页面尺寸、添加水印或元数据即可。

 • end • 

陪伴是最长情的告白

 为你推送最实用的资讯 

识别二维码 关注我们 

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-08-11 13:20:49 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/881371.html
  2. 运行时间 : 0.273173s [ 吞吐率:3.66req/s ] 内存消耗:4,886.09kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=246e9dee3e520d0652a35244d0d0ad3c
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 4.22 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.11 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000821s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001377s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.005388s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.002960s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001513s ]
  6. SELECT * FROM `set` [ RunTime:0.003855s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001773s ]
  8. SELECT * FROM `article` WHERE `id` = 881371 LIMIT 1 [ RunTime:0.004056s ]
  9. UPDATE `article` SET `lasttime` = 1786425649 WHERE `id` = 881371 [ RunTime:0.012198s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000741s ]
  11. SELECT * FROM `article` WHERE `id` < 881371 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001335s ]
  12. SELECT * FROM `article` WHERE `id` > 881371 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003092s ]
  13. SELECT * FROM `article` WHERE `id` < 881371 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001793s ]
  14. SELECT * FROM `article` WHERE `id` < 881371 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.007409s ]
  15. SELECT * FROM `article` WHERE `id` < 881371 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.027347s ]
0.276875s