在實際環境中測試
在生產環境中測試無浮水印。
在任何需要的地方都能運作。
檔案上傳是網頁應用程式中常見的功能,讓它使用方便對於良好的用戶體驗至關重要。 一個受歡迎的函式庫可以簡化此過程的選擇是 Dropzone.js. 結合時 React, Dropzone 可以作為實現拖放檔案上傳的強大工具。 react-dropzone 與最少的開發工作完美無縫整合。 這篇文章將指導您整合 投放區 使用 react-dropzone 套件與 React 應用程式搭配使用,這是 Dropzone.js 函式庫的優秀封裝。
在本文中,我們還將探討 IronPDF NPM 套件用於生成、編輯和管理 PDF 文件。
Dropzone 提供了各種功能,使文件上傳變得更加順暢:
允許用戶拖放文件以啟用文件選擇。 以程式方式新增檔案對話框。
顯示從拖放文件中預設的圖片縮圖預覽。 顯示檔案預覽有助於提升使用者介面的可讀性。
支持同時上傳多個檔案。
高度可自訂,提供多種選項和回調。 可以自定義文件對話框打開或文件選擇對話框
使用分段上傳上傳大檔案。
可以處理檔案對話框取消回調以及瀏覽器圖像調整大小事件。
在整合 Dropzone 之前,請確保您已經設置好 React 應用程序。如果您還沒有,可以使用创建一個新的 React 專案 創建 React 應用程式:
npx create-react-app dropzone-demo
cd dropzone-demo
npx create-react-app dropzone-demo
cd dropzone-demo
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'npx create-react-app dropzone-demo cd dropzone-demo
要在您的 React 項目中使用 Dropzone,您需要安裝 react-dropzone 套件:
npm install react-dropzone
or
yarn add react-dropzone
npm install react-dropzone
or
yarn add react-dropzone
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'npm install react-dropzone @or yarn add react-dropzone
這是一個在 React 組件中使用 react-dropzone 的簡單範例:
import React, { useCallback } from 'react';
import { useDropzone } from 'react-dropzone'; // import dropzone
const DropzoneComponent = () => {
const onDrop = useCallback((acceptedFiles) => {
console.log(acceptedFiles);
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
return (
<div {...getRootProps()} style={dropzoneStyle}>
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
);
};
const dropzoneStyle = {
border: '2px dashed #0087F7',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer'
};
export default DropzoneComponent;
import React, { useCallback } from 'react';
import { useDropzone } from 'react-dropzone'; // import dropzone
const DropzoneComponent = () => {
const onDrop = useCallback((acceptedFiles) => {
console.log(acceptedFiles);
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
return (
<div {...getRootProps()} style={dropzoneStyle}>
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
);
};
const dropzoneStyle = {
border: '2px dashed #0087F7',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer'
};
export default DropzoneComponent;
'INSTANT VB TODO TASK: The following line could not be converted:
import React,
If True Then
useCallback
End If
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'from 'react'; import { useDropzone } from 'react-dropzone'; const DropzoneComponent = () => { const onDrop = useCallback((acceptedFiles) => { console.log(acceptedFiles); }, []); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }); Return(<div {...getRootProps()} style={dropzoneStyle}> { isDragActive ? <p> Drop the files here...</p> : <p> Drag "n"c drop some files here, @or click @to select files</p> } </div>); }; const dropzoneStyle = { border: '2px dashed #0087F7', borderRadius: '5px', padding: '20px', textAlign: 'center', cursor: 'pointer' }; export default DropzoneComponent;
當檔案被拖放或選擇時,onDrop 回調將接收到一個接受的檔案數組。 然後,您就可以處理這些文件,例如將它們上傳到伺服器。 以下是如何擴展 onDrop 回調來使用 fetch 上傳文件的方法:
const onDrop = useCallback((acceptedFiles) => {
const formData = new FormData();
acceptedFiles.forEach((file) => {
formData.append('files', file);
});
fetch('https://your-upload-endpoint', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
}, []);
const onDrop = useCallback((acceptedFiles) => {
const formData = new FormData();
acceptedFiles.forEach((file) => {
formData.append('files', file);
});
fetch('https://your-upload-endpoint', {
method: 'POST',
body: formData,
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
}, []);
'INSTANT VB TODO TASK: Lambda expressions and anonymous methods are not converted by Instant VB if local variables of the outer method are referenced within the anonymous method:
const onDrop = useCallback((acceptedFiles) =>
If True Then
const formData = New FormData()
'INSTANT VB TODO TASK: Lambda expressions and anonymous methods are not converted by Instant VB if local variables of the outer method are referenced within the anonymous method:
acceptedFiles.forEach((file) =>
If True Then
formData.append( 'files', file);
End If
)
fetch( 'https: method: 'POST', body: formData}).@then(response => response.json()).@then(data => console.log(data)).catch(@error => console.@error('@Error:', @error));
End If
, ())
您還可以顯示上傳文件的預覽。 這是一個如何做到這一點的範例:
import React, { useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
const DropzoneComponent = () => {
const [files, setFiles] = useState([]);
const onDrop = useCallback((acceptedFiles) => {
setFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
const thumbs = files.map(file => (
<div key={file.name}>
<img
src={file.preview}
style={{ width: '100px', height: '100px' }}
alt={file.name}
/>
</div>
));
return (
<div>
<div {...getRootProps()} style={dropzoneStyle}>
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
<div>
{thumbs}
</div>
</div>
);
};
const dropzoneStyle = {
border: '2px dashed #0087F7',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer'
};
export default DropzoneComponent;
import React, { useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
const DropzoneComponent = () => {
const [files, setFiles] = useState([]);
const onDrop = useCallback((acceptedFiles) => {
setFiles(acceptedFiles.map(file => Object.assign(file, {
preview: URL.createObjectURL(file)
})));
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
const thumbs = files.map(file => (
<div key={file.name}>
<img
src={file.preview}
style={{ width: '100px', height: '100px' }}
alt={file.name}
/>
</div>
));
return (
<div>
<div {...getRootProps()} style={dropzoneStyle}>
{
isDragActive ?
<p>Drop the files here ...</p> :
<p>Drag 'n' drop some files here, or click to select files</p>
}
</div>
<div>
{thumbs}
</div>
</div>
);
};
const dropzoneStyle = {
border: '2px dashed #0087F7',
borderRadius: '5px',
padding: '20px',
textAlign: 'center',
cursor: 'pointer'
};
export default DropzoneComponent;
'INSTANT VB TODO TASK: The following line could not be converted:
import React,
If True Then
useCallback, useState
End If
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'from 'react'; import { useDropzone } from 'react-dropzone'; const DropzoneComponent = () => { const [files, setFiles] = useState([]); const onDrop = useCallback((acceptedFiles) => { setFiles(acceptedFiles.map(file => Object.assign(file, { preview: URL.createObjectURL(file) }))); }, []); const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop }); const thumbs = files.map(file => (<div key={file.name}> <img src={file.preview} style={{ width: '100px', height: '100px' }} alt={file.name} /> </div>)); Return(<div> <div {...getRootProps()} style={dropzoneStyle}> { isDragActive ? <p> Drop the files here...</p> : <p> Drag "n"c drop some files here, @or click @to select files</p> } </div> <div> {thumbs} </div> </div>); }; const dropzoneStyle = { border: '2px dashed #0087F7', borderRadius: '5px', padding: '20px', textAlign: 'center', cursor: 'pointer' }; export default DropzoneComponent;
撤銷對象 URL 以避免記憶體洩漏是至關重要的。 您可以使用 useEffect 掛鉤來實現此目的:
import { useEffect } from 'react';
useEffect(() => {
// Make sure to revoke the data uris to avoid memory leaks
return () => files.forEach(file => URL.revokeObjectURL(file.preview));
}, [files]);
import { useEffect } from 'react';
useEffect(() => {
// Make sure to revoke the data uris to avoid memory leaks
return () => files.forEach(file => URL.revokeObjectURL(file.preview));
}, [files]);
import
If True Then
useEffect
End If
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'from 'react'; useEffect(() => { Return() => files.forEach(file => URL.revokeObjectURL(file.preview)); }, [files]);
IronPDF 是一個強大的 npm 套件,旨在促進 Node.js 應用程式中的 PDF 生成。 它允許您從中創建 PDF 文件 HTML 內容, 網址,甚至是現有的 PDF 文件。 無論您是在生成發票、報告,還是任何其他類型的文件,IronPDF 都能通過其直觀的設計簡化過程。 API 和強大的功能集。
輕鬆將 HTML 內容轉換成 PDF 文件。 此功能特別適合從網頁內容生成動態 PDF。
直接從網址生成 PDF。 這使您能夠以程式化方式捕獲網頁內容並將其保存為 PDF 檔案。
輕鬆合併、拆分和操作現有的 PDF 文件。 IronPDF 提供操作 PDF 文件的功能,例如添加頁面、拆分文檔等。
透過加密密碼或應用數位簽章來保護您的 PDF 文件。 IronPDF 提供選項來保護您的敏感文件免受未經授權的訪問。
生成高品質的 PDF 文件,精確還原文字、圖像和格式。 IronPDF 確保您生成的 PDF 保持對原始內容的忠實性。
IronPDF 與多種平台兼容,包括 Windows、Linux 和 macOS,這使得它適合廣泛的開發環境。
輕鬆使用其 npm 套件將 IronPDF 集成到您的 Node.js 應用程式中。 API 有完善的文檔,使將 PDF 生成功能融入您的項目變得簡單明瞭。
無論您是在構建網頁應用程式、伺服器端腳本,還是命令列工具, IronPDF 讓您能夠有效且可靠地創建專業級PDF文件。
安裝依賴項:首先,創建一個新的 Next.js 專案 (如果您還沒有) 使用以下命令:參考設置 頁面.
npx create-next-app@latest demo-dropzone-ironpdf --use-npm --example "https://github.com/vercel/next-learn/tree/main/basics/learn-starter"
npx create-next-app@latest demo-dropzone-ironpdf --use-npm --example "https://github.com/vercel/next-learn/tree/main/basics/learn-starter"
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'npx create-@next-app@latest demo-dropzone-ironpdf --use-npm --example "https://github.com/vercel/next-learn/tree/main/basics/learn-starter"
接著,導航至您的專案目錄:
cd demo-dropzone-ironpdf
cd demo-dropzone-ironpdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'cd demo-dropzone-ironpdf
安裝所需的軟體包:
npm install @ironsoftware/ironpdf
npm install react-dropzone
npm install @ironsoftware/ironpdf
npm install react-dropzone
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'npm install @ironsoftware/ironpdf npm install react-dropzone
建立 PDF:現在,讓我們使用 IronPDF 生成 PDF 的簡單示例。 在您的 Next.js 組件中 (例如,pages/index.tsx),新增以下代碼:
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import {ToastContainer, toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {useState} from "react";
import DropzoneComponent from "../components/mydropzone";
export default function Home() {
const [textInput, setTextInput] = useState('');
const notify = () => {
toast.success("Success! This is a success message.", {
position: "top-right"
});
toast.info("Information message", {
position: "bottom-left"
});
toast.warn("Warning message", {
autoClose: 5000
});
toast.error("Error message", {
className: 'custom-toast',
style: {background: 'red', color: 'white'}
});
};
const generatePdf = async () => {
try {
const response = await fetch('/api/pdf?url='+textInput);
const blob = await response.blob();
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'awesomeIron.pdf');
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
} catch (error) {
console.error('Error generating PDF:', error);
}
};
const handleChange = (event) => {
setTextInput(event.target.value);
}
return (
<div className={styles.container}>
<Head>
<title>Generate PDF Using IronPDF</title>
<link rel="icon" href="/favicon.ico"/>
</Head>
<main>
<h1>Demo Drop Zone and Generate PDF Using IronPDF</h1>
<DropzoneComponent/>
<p>
<span>Enter Url To Convert to PDF:</span>{" "}
</p>
<button style={{margin:20, padding:5}} onClick={generatePdf}>Generate PDF</button>
</main>
<style jsx>{`
main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
footer {
width: 100%;
height: 100px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
}
footer img {
margin-left: 0.5rem;
}
footer a {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: inherit;
}
code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo,
Monaco,
Lucida Console,
Liberation Mono,
DejaVu Sans Mono,
Bitstream Vera Sans Mono,
Courier New,
monospace;
}
`}</style>
<style jsx global>{`
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system,
BlinkMacSystemFont,
Segoe UI,
Roboto,
Oxygen,
Ubuntu,
Cantarell,
Fira Sans,
Droid Sans,
Helvetica Neue,
sans-serif;
}
* {
box-sizing: border-box;
}
`}</style>
</div>
);
}
import Head from 'next/head';
import styles from '../styles/Home.module.css';
import {ToastContainer, toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {useState} from "react";
import DropzoneComponent from "../components/mydropzone";
export default function Home() {
const [textInput, setTextInput] = useState('');
const notify = () => {
toast.success("Success! This is a success message.", {
position: "top-right"
});
toast.info("Information message", {
position: "bottom-left"
});
toast.warn("Warning message", {
autoClose: 5000
});
toast.error("Error message", {
className: 'custom-toast',
style: {background: 'red', color: 'white'}
});
};
const generatePdf = async () => {
try {
const response = await fetch('/api/pdf?url='+textInput);
const blob = await response.blob();
const url = window.URL.createObjectURL(new Blob([blob]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'awesomeIron.pdf');
document.body.appendChild(link);
link.click();
link.parentNode.removeChild(link);
} catch (error) {
console.error('Error generating PDF:', error);
}
};
const handleChange = (event) => {
setTextInput(event.target.value);
}
return (
<div className={styles.container}>
<Head>
<title>Generate PDF Using IronPDF</title>
<link rel="icon" href="/favicon.ico"/>
</Head>
<main>
<h1>Demo Drop Zone and Generate PDF Using IronPDF</h1>
<DropzoneComponent/>
<p>
<span>Enter Url To Convert to PDF:</span>{" "}
</p>
<button style={{margin:20, padding:5}} onClick={generatePdf}>Generate PDF</button>
</main>
<style jsx>{`
main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
footer {
width: 100%;
height: 100px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
}
footer img {
margin-left: 0.5rem;
}
footer a {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: inherit;
}
code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo,
Monaco,
Lucida Console,
Liberation Mono,
DejaVu Sans Mono,
Bitstream Vera Sans Mono,
Courier New,
monospace;
}
`}</style>
<style jsx global>{`
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system,
BlinkMacSystemFont,
Segoe UI,
Roboto,
Oxygen,
Ubuntu,
Cantarell,
Fira Sans,
Droid Sans,
Helvetica Neue,
sans-serif;
}
* {
box-sizing: border-box;
}
`}</style>
</div>
);
}
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'import Head from '@next/head'; import styles from '../styles/Home.@module.css'; import {ToastContainer, toast} from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import {useState} from "react"; import DropzoneComponent from "../components/mydropzone"; export default @function Home() { const [textInput, setTextInput] = useState(''); const notify = () => { toast.success("Success! This is a success message.", { position: "top-right" }); toast.info("Information message", { position: "bottom-left" }); toast.warn("Warning message", { autoClose: 5000 }); toast.@error("Error message", { className: 'custom-toast', style: {background: 'red', color: 'white'} }); }; const generatePdf = async() => { try { const response = await fetch('/api/System.Nullable<pdf>url='+textInput); const blob = await response.blob(); const url = window.URL.createObjectURL(New Blob([blob])); const link = document.createElement("a"c); link.href = url; link.setAttribute('download', 'awesomeIron.pdf'); document.body.appendChild(link); link.click(); link.parentNode.removeChild(link); } catch(@error) { console.@error('@Error generating PDF:', @error); } }; const handleChange = (event) => { setTextInput(event.target.value); } Return(<div className={styles.container}> <Head> <title> Generate PDF @Using IronPDF</title> <link rel="icon" href="/favicon.ico"/> </Head> <main> <h1> Demo Drop Zone @and Generate PDF @Using IronPDF</h1> <DropzoneComponent/> <p> <span> Enter Url @To Convert @to PDF:</span>{" "} </p> <button style={{margin:20, padding:5}} onClick={generatePdf}> Generate PDF</button> </main> <style jsx>{` main { padding: 5rem 0; flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } footer { width: 100%; height: 100px; border-top: 1px solid #eaeaea; display: flex; justify-content: center; align-items: center; } footer img { margin-left: 0.5rem; } footer a { display: flex; justify-content: center; align-items: center; text-decoration: none; color: inherit; } code { background: #fafafa; border-radius: 5px; padding: 0.75rem; font-size: 1.1rem; font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier @New, monospace; } `}</style> <style jsx global>{` html, body { padding: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } * { box-sizing: border-box; } `}</style> </div>); }
由於 IronPDF 僅在 Node.js 上運行,接下來為應用程式新增一個在 Node.js 上生成 PDF 的 API。
在 pages/api
資料夾中創建一個 pdf.js
檔案,並添加以下源程式碼。
// pages/api/pdf.js
import {IronPdfGlobalConfig, PdfDocument} from "@ironsoftware/ironpdf";
// Apply your IronPDF license key
IronPdfGlobalConfig.getConfig().licenseKey = "Add Your key here";
export default async function handler(req, res) {
try {
const url = req.query.url
const pdf = await PdfDocument.fromUrl(url);
const data = await pdf.saveAsBuffer();
console.error('data PDF:', data);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=awesomeIron.pdf');
res.send(data);
} catch (error) {
console.error('Error generating PDF:', error);
res.status(500).end();
}
}
// pages/api/pdf.js
import {IronPdfGlobalConfig, PdfDocument} from "@ironsoftware/ironpdf";
// Apply your IronPDF license key
IronPdfGlobalConfig.getConfig().licenseKey = "Add Your key here";
export default async function handler(req, res) {
try {
const url = req.query.url
const pdf = await PdfDocument.fromUrl(url);
const data = await pdf.saveAsBuffer();
console.error('data PDF:', data);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename=awesomeIron.pdf');
res.send(data);
} catch (error) {
console.error('Error generating PDF:', error);
res.status(500).end();
}
}
' pages/api/pdf.js
import
If True Then
IronPdfGlobalConfig, PdfDocument
End If
from "@ironsoftware/ironpdf"
' Apply your IronPDF license key
IronPdfGlobalConfig.getConfig().licenseKey = "Add Your key here"
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'export default async @function handler(req, res)
'{
' try
' {
' const url = req.query.url const pdf = await PdfDocument.fromUrl(url);
' const data = await pdf.saveAsBuffer();
' console.@error('data PDF:', data);
' res.setHeader('Content-Type', 'application/pdf');
' res.setHeader('Content-Disposition', 'attachment; filename=awesomeIron.pdf');
' res.send(data);
' }
' catch (@error)
' {
' console.@error('@Error generating PDF:', @error);
' res.status(500).@end();
' }
'}
注意:在上述代碼中添加您自己的授權密鑰
運行您的應用程式:啟動您的 Next.js 應用程式:
npm run dev
or
yarn dev
npm run dev
or
yarn dev
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'npm run dev @or yarn dev
現在輸入網站 URL 生成 PDF,然後點擊生成 PDF。 如下所示的名為 awesomeIron.pdf 的檔案將被下載。
現在點擊下傳區,然後選擇下載的文件。這將顯示文件的預覽,名稱顯示在底部:awesomeIron.pdf
IronPDF 頁面。
將授權密鑰放置在應用程式中,如下所示:
import {IronPdfGlobalConfig, PdfDocument} from "@ironsoftware/ironpdf";
// Apply your IronPDF license key
IronPdfGlobalConfig.getConfig().licenseKey = "Add Your key here";
import {IronPdfGlobalConfig, PdfDocument} from "@ironsoftware/ironpdf";
// Apply your IronPDF license key
IronPdfGlobalConfig.getConfig().licenseKey = "Add Your key here";
IRON VB CONVERTER ERROR developers@ironsoftware.com
整合 Dropzone 使用 React 进行 react-dropzone 是一個簡單的過程,顯著提升檔案上傳體驗。 擁有拖放、文件預覽和多樣化自訂選項等功能,react-dropzone 可以成為您 React 專案中的寶貴工具。 開始探索其功能,並根據您的應用程式需求進行調整。!
IronPDF另一方面,它是一個多功能的 PDF 生成和操作庫,使得集成到應用程式中變得容易。 IronPDF提供全面 文檔 和 程式碼範例 幫助開發人員入門。
透過遵循本文中概述的步驟,您可以在您的 React 應用程式中建立一個強大的檔案上傳元件,同時將 PDF 檔案生成功能整合到現代應用程式中。