Test dans un environnement réel
Test en production sans filigrane.
Fonctionne partout où vous en avez besoin.
Bienvenue dans le tutoriel sur la création de documents PDF à partir d'une application React! Dans ce tutoriel, nous allons explorer différentes bibliothèques pour générer des PDF et apprendre à utiliser la populaire bibliothèque jsPDF pour créer des fichiers PDF directement à partir de vos composants React. Alors, plongeons dans le vif du sujet!
PDF (EN ANGLAIS) (Format de document portable) est un format de fichier largement utilisé pour partager et imprimer des documents tout en préservant leur mise en page et leur formatage. En tant que développeur web React, vous pouvez rencontrer des scénarios dans lesquels vous avez besoin de générer des documents PDF, tels que des factures, des rapports ou des contrats de vente, directement à partir de votre application React.
Créer des documents PDF dans une application React peut être une tâche décourageante, surtout si vous êtes nouveau dans le paysage. Heureusement, nous disposons de plusieurs bibliothèques tierces qui simplifient considérablement ce processus. Chaque bibliothèque possède ses propres caractéristiques et utilités, répondant à des cas d'utilisation différents. Examinons ces bibliothèques un peu plus en détail.
jsPDF est une bibliothèque très populaire parmi les développeurs pour générer des fichiers PDF à partir de JavaScript. L'un de ses principaux arguments de vente est sa simplicité. Sa syntaxe et son utilisation sont assez simples, ce qui vous permet de transformer votre contenu HTML en fichier PDF en un rien de temps.
Il vous permet de contrôler le formatage et la mise en page de vos PDF, qu'il s'agisse de modifier la taille et la couleur des polices ou d'ajuster l'orientation et la taille des pages. jsPDF est une solution robuste qui fonctionne à la fois dans les environnements de navigateur et de serveur, ce qui en fait un excellent choix pour un large éventail d'applications JavaScript.
pdfmake se distingue comme une solution d'impression PDF client/serveur en JavaScript pur. Cette bibliothèque est un excellent choix pour créer des PDF plus complexes, grâce à son API complète et à ses options de mise en page flexibles. Avec pdfmake, vous pouvez définir le contenu et la structure de votre document à l'aide d'un simple objet JavaScript, puis le transformer en un document PDF valide.
React-PDF est une bibliothèque unique qui fournit des fonctionnalités puissantes pour créer des fichiers PDF à l'aide de composants React. Au lieu d'écrire manuellement la structure de votre document dans un objet JavaScript, vous pouvez créer votre PDF comme vous le feriez pour une application React classique - à l'aide de composants et d'accessoires réutilisables. Le site web d'IronPDF propose un tutoriel sur la création de PDF à l'aide de la bibliothèque React-PDF.
Bien que ces trois bibliothèques fournissent des outils puissants pour générer des documents PDF dans React, nous utiliserons jsPDF dans ce tutoriel en raison de sa simplicité, de sa flexibilité et de sa large adoption par la communauté. Il constitue une barrière d'entrée moins élevée pour les débutants, et son ensemble de fonctionnalités robustes en fait un choix approprié pour de nombreux cas d'utilisation. Les principes que nous allons explorer avec jsPDF vous donneront une base solide pour générer des PDF, et vous serez en mesure d'utiliser d'autres bibliothèques plus facilement si votre projet l'exige.
Avant de plonger dans ce tutoriel, il est essentiel de s'assurer que vous disposez des outils et des connaissances nécessaires pour le suivre sans problème. Les conditions préalables à ce tutoriel sont les suivantes :
Avant tout, vous devez avoir une compréhension de base de React, une bibliothèque JavaScript populaire pour la construction d'interfaces utilisateur, en particulier les applications à page unique. Vous devez être familiarisé avec des concepts tels que JSX (JavaScript XML)les composants, l'état et les accessoires dans React.
Vous devez également disposer d'un environnement de développement sur votre ordinateur pour créer des applications React. Il peut s'agir d'un éditeur de texte ou d'un environnement de développement intégré (L'IDE). Les éditeurs de texte tels que Visual Studio Code, Atom ou Sublime Text sont de bonnes options.
Pour gérer notre projet et ses dépendances, nous utiliserons Node.js et npm (Gestionnaire de paquets Node). Assurez-vous que Node.js est installé sur votre ordinateur. Node.js est un moteur d'exécution JavaScript qui permet d'exécuter du JavaScript sur nos serveurs. Il est livré avec npm installé, ce qui vous permet de gérer les bibliothèques nécessaires à votre projet.
Vous pouvez vérifier si Node.js et npm sont installés en exécutant les commandes suivantes dans le terminal :
node -v
npm -v
Ces commandes affichent respectivement la version de Node.js et de npm installée sur votre système. Si vous ne les avez pas installées ou si vos versions sont obsolètes, vous devez télécharger et installer les dernières versions du support à long terme (LTS) de Node.js à partir de leur site web site officiel.
Commençons par mettre en place notre projet React. Ouvrez votre terminal et naviguez jusqu'au répertoire où vous souhaitez créer votre projet. Exécutez la commande suivante pour créer une nouvelle application React :
npx create-react-app pdf-from-react
Cette commande va créer un nouveau répertoire appelé pdf-from-react
avec une structure de projet React basique.
Ensuite, naviguez dans le répertoire du projet :
cd pdf-from-react
Nous pouvons maintenant ouvrir le projet dans notre éditeur de code et procéder à la mise en œuvre.
Tout d'abord, nous devons installer les paquets nécessaires. Installez react
, react-dom
, @mui/material
, et jspdf
en utilisant la commande de terminal suivante.
npm install jspdf @mui/material @emotion/react @emotion/styled @mui/icons-material
Nous commençons par importer les dépendances nécessaires à notre application. Il s'agit notamment de divers composants de la bibliothèque Material-UI, de la bibliothèque jsPDF
pour la génération de PDF et d'utilitaires de style.
import React, { useState } from "react";
import "./App.css";
import {
Button,
TextField,
Box,
Container,
Typography,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
IconButton,
Snackbar,
Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";
Pour ajouter un comportement cohérent entre les navigateurs à notre application, nous avons utilisé l'utilitaire styled
de la bibliothèque MUI pour créer StyledTableCell
et StyledTableRow
.
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover,
},
"&:last-child td, &:last-child th": {
border: 0,
},
}));
Le composant principal de notre application est le composant App
. Nous avons quatre variables d'état : customerName
et customerAddress
pour garder une trace des données du client, items
pour garder une trace de la liste des articles de la facture, et error
pour afficher un message d'erreur si nécessaire.
function App() {
// State variables
const [customerName, setCustomerName] = useState("");
const [customerAddress, setCustomerAddress] = useState("");
const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
const [error, setError] = useState(false);
Dans ce bloc de code, nous avons défini des fonctions pour gérer les interactions avec l'utilisateur : modification des détails d'un élément, ajout d'un nouvel élément et suppression d'un élément. La fonction handleItemChange
met à jour les propriétés d'un élément lorsqu'un utilisateur les modifie. La fonction addItem
ajoute un nouvel élément à la liste. La fonction deleteItem
supprime un élément de la liste.
const handleItemChange = (index, event) => {
let newItems = [...items];
newItems [index][event.target.name] = event.target.value;
setItems(newItems);
};
const addItem = () => {
setItems([...items, { name: "", quantity: "", price: "" }]);
};
const deleteItem = (index) => {
let newItems = [...items];
newItems.splice(index, 1);
setItems(newItems);
};
Voici le code de la fonction generateInvoice
:
// Generate invoice
const generateInvoice = () => {
// Validate the input fields
if (
!customerName
!customerAddress
items.some((item) => !item.name
!item.quantity
!item.price)
) {
setError(true);
return;
}
// Create a new jsPDF instance
let doc = new jsPDF("p", "pt");
// Add invoice header
doc.setFontSize(24);
doc.text("Invoice", 40, 60);
doc.setFontSize(10);
doc.text("Invoice Number: 123456", 40, 90);
doc.text("Date: " + new Date().toDateString(), 40, 110);
doc.text(`Customer Name: ${customerName}`, 40, 130);
doc.text(`Customer Address: ${customerAddress}`, 40, 150);
// Add items section
doc.setFontSize(14);
doc.text("Items:", 40, 200);
doc.line(40, 210, 550, 210);
// Add item details
doc.setFontSize(12);
let yOffset = 240;
let total = 0;
items.forEach((item) => {
let itemTotal = item.quantity * item.price;
total += itemTotal;
doc.text(`Item: ${item.name}`, 40, yOffset);
doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
doc.text(`Price: $${item.price}`, 300, yOffset);
doc.text(`Total: $${itemTotal}`, 400, yOffset);
yOffset += 20;
});
// Add total
doc.line(40, yOffset, 550, yOffset);
doc.setFontSize(14);
doc.text(`Total: $${total}`, 400, yOffset + 30);
// Save the generated PDF as "invoice.pdf"
doc.save("invoice.pdf");
// Reset error state
setError(false);
};
Dans la fonction generateInvoice
, nous commençons par valider les champs de saisie pour nous assurer que le nom et l'adresse du client, ainsi que les détails de l'article, sont bien renseignés. Si l'un de ces champs est vide, nous mettons l'état error
à true
et nous retournons prématurément.
Ensuite, nous créons une nouvelle instance de jsPDF
en appelant new jsPDF
("p", "pt"). Le premier argument "
p" spécifie l'orientation de la page (portrait) et le second argument "
pt`" spécifie l'unité de mesure (points).
Nous commençons ensuite à ajouter le contenu à notre document PDF. Nous définissons la taille de la police à l'aide de doc.setFontSize
et utilisons la méthode doc.text
pour ajouter du texte à des coordonnées spécifiques sur la page. Nous ajoutons l'en-tête de la facture, y compris le titre, le numéro de la facture, la date, le nom et l'adresse du client.
Après l'en-tête, nous ajoutons la section "Items" en réglant la taille de la police et en ajoutant une ligne à l'aide de doc.line
pour séparer les items de l'en-tête. Ensuite, nous itérons sur chaque élément du tableau items
et calculons le prix total de chaque élément en multipliant la quantité par le prix. Nous mettons à jour la variable total
avec la somme de tous les totaux des articles.
Pour chaque article, nous utilisons doc.text
pour ajouter le nom de l'article, la quantité, le prix et le total de l'article au document PDF. Nous incrémentons la variable yOffset
pour passer à la ligne suivante pour chaque élément. Enfin, nous ajoutons une ligne pour séparer les éléments du total et utilisons doc.text
pour ajouter le montant total en bas à droite du document.
Une fois le contenu ajouté, nous utilisons doc.save("facture.pdf)
pour enregistrer le PDF généré en tant que "invoice.pdf" sur l'ordinateur de l'utilisateur. Enfin, nous réinitialisons l'état error
à false
pour effacer toutes les erreurs de validation précédentes.
L'instruction return
contient le code JSX qui gère le processus de rendu. Il comprend des champs de saisie pour le nom et l'adresse du client, un tableau pour saisir les détails des articles, des boutons pour ajouter des articles et générer la facture, ainsi qu'une barre d'erreur pour afficher les erreurs de validation.
Il utilise les composants de la bibliothèque Material-UI, tels que Button
, TextField
, Box
, Container
, Typography
, Table
, TableBody
, TableCell
, TableContainer
, TableHead
, TableRow
, Paper
, IconButton
, Snackbar
, et Alert
, pour créer des composants de base. Ces composants sont utilisés pour créer les champs du formulaire, les tableaux, les boutons et les notifications d'erreur.
return (
<Container maxWidth="md">
<Box sx={{ my: 4 }}>
<Typography variant="h3" component="h1" gutterBottom>
Create Invoice
</Typography>
{/* Customer Name and Address fields */}
<Grid container spacing={3}>
<Grid item xs={6}>
<TextField
label="Customer Name"
fullWidth
margin="normal"
value={customerName}
onChange={(e) => setCustomerName(e.target.value)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label="Customer Address"
fullWidth
margin="normal"
value={customerAddress}
onChange={(e) => setCustomerAddress(e.target.value)}
/>
</Grid>
</Grid>
{/* Items table */}
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="invoice table">
<TableHead>
<TableRow>
<StyledTableCell>Item Name</StyledTableCell>
<StyledTableCell align="left">Quantity</StyledTableCell>
<StyledTableCell align="left">Price</StyledTableCell>
<StyledTableCell align="left">Action</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((item, index) => (
<StyledTableRow key={index}>
<StyledTableCell component="th" scope="row">
<TextField
fullWidth
value={item.name}
onChange={(event) => handleItemChange(index, event)}
name="name"
/>
</StyledTableCell>
<StyledTableCell align="right">
<TextField
fullWidth
value={item.quantity}
onChange={(event) => handleItemChange(index, event)}
name="quantity"
/>
</StyledTableCell>
<StyledTableCell align="right">
<TextField
fullWidth
value={item.price}
onChange={(event) => handleItemChange(index, event)}
name="price"
/>
</StyledTableCell>
<StyledTableCell align="right">
<IconButton onClick={() => deleteItem(index)}>
<DeleteIcon />
</IconButton>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
{/* Buttons */}
<Box mt={2} display="flex" gap={2}>
<Button variant="contained" onClick={addItem}>
Add Item
</Button>
<Button variant="outlined" color="success" onClick={generateInvoice}>
Generate Invoice
</Button>
</Box>
</Box>
{/* Error Snackbar */}
<Snackbar
open={error}
autoHideDuration={6000}
onClose={() => setError(false)}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
>
<Alert onClose={() => setError(false)} severity="error">
Please fill in all required fields.
</Alert>
</Snackbar>
</Container>
);
Voici le code complet d'App.js que vous pouvez copier et coller dans votre projet :
import React, { useState } from "react";
import "./App.css";
import {
Button,
TextField,
Box,
Container,
Typography,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
IconButton,
Snackbar,
Alert,
} from "@mui/material";
import Grid from "@mui/material/Grid";
import DeleteIcon from "@mui/icons-material/Delete";
import jsPDF from "jspdf";
import { styled } from "@mui/material/styles";
import { tableCellClasses } from "@mui/material/TableCell";
const StyledTableCell = styled(TableCell)(({ theme }) => ({
[`&.${tableCellClasses.head}`]: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
[`&.${tableCellClasses.body}`]: {
fontSize: 14,
},
}));
const StyledTableRow = styled(TableRow)(({ theme }) => ({
"&:nth-of-type(odd)": {
backgroundColor: theme.palette.action.hover,
},
"&:last-child td, &:last-child th": {
border: 0,
},
}));
function App() {
// State variables
const [customerName, setCustomerName] = useState("");
const [customerAddress, setCustomerAddress] = useState("");
const [items, setItems] = useState([{ name: "", quantity: "", price: "" }]);
const [error, setError] = useState(false);
// Event handler for item changes
const handleItemChange = (index, event) => {
let newItems = [...items];
newItems [index][event.target.name] = event.target.value;
setItems(newItems);
};
// Add new item to the list
const addItem = () => {
setItems([...items, { name: "", quantity: "", price: "" }]);
};
// Delete an item from the list
const deleteItem = (index) => {
let newItems = [...items];
newItems.splice(index, 1);
setItems(newItems);
};
// Generate invoice
const generateInvoice = () => {
// Validate the input fields
if (
!customerName
!customerAddress
items.some((item) => !item.name
!item.quantity
!item.price)
) {
setError(true);
return;
}
// Create a new jsPDF instance
let doc = new jsPDF("p", "pt");
// Add invoice header
doc.setFontSize(24);
doc.text("Invoice", 40, 60);
doc.setFontSize(10);
doc.text("Invoice Number: 123456", 40, 90);
doc.text("Date: " + new Date().toDateString(), 40, 110);
doc.text(`Customer Name: ${customerName}`, 40, 130);
doc.text(`Customer Address: ${customerAddress}`, 40, 150);
// Add items section
doc.setFontSize(14);
doc.text("Items:", 40, 200);
doc.line(40, 210, 550, 210);
// Add item details
doc.setFontSize(12);
let yOffset = 240;
let total = 0;
items.forEach((item) => {
let itemTotal = item.quantity * item.price;
total += itemTotal;
doc.text(`Item: ${item.name}`, 40, yOffset);
doc.text(`Quantity: ${item.quantity}`, 200, yOffset);
doc.text(`Price: $${item.price}`, 300, yOffset);
doc.text(`Total: $${itemTotal}`, 400, yOffset);
yOffset += 20;
});
// Add total
doc.line(40, yOffset, 550, yOffset);
doc.setFontSize(14);
doc.text(`Total: $${total}`, 400, yOffset + 30);
// Save the generated PDF as "invoice.pdf"
doc.save("invoice.pdf");
// Reset error state
setError(false);
};
return (
<Container maxWidth="md">
<Box sx={{ my: 4 }}>
<Typography variant="h3" component="h1" gutterBottom>
Create Invoice
</Typography>
{/* Customer Name and Address fields */}
<Grid container spacing={3}>
<Grid item xs={6}>
<TextField
label="Customer Name"
fullWidth
margin="normal"
value={customerName}
onChange={(e) => setCustomerName(e.target.value)}
/>
</Grid>
<Grid item xs={6}>
<TextField
label="Customer Address"
fullWidth
margin="normal"
value={customerAddress}
onChange={(e) => setCustomerAddress(e.target.value)}
/>
</Grid>
</Grid>
{/* Items table */}
<TableContainer component={Paper}>
<Table sx={{ minWidth: 700 }} aria-label="invoice table">
<TableHead>
<TableRow>
<StyledTableCell>Item Name</StyledTableCell>
<StyledTableCell align="left">Quantity</StyledTableCell>
<StyledTableCell align="left">Price</StyledTableCell>
<StyledTableCell align="left">Action</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{items.map((item, index) => (
<StyledTableRow key={index}>
<StyledTableCell component="th" scope="row">
<TextField
fullWidth
value={item.name}
onChange={(event) => handleItemChange(index, event)}
name="name"
/>
</StyledTableCell>
<StyledTableCell align="right">
<TextField
fullWidth
value={item.quantity}
onChange={(event) => handleItemChange(index, event)}
name="quantity"
/>
</StyledTableCell>
<StyledTableCell align="right">
<TextField
fullWidth
value={item.price}
onChange={(event) => handleItemChange(index, event)}
name="price"
/>
</StyledTableCell>
<StyledTableCell align="right">
<IconButton onClick={() => deleteItem(index)}>
<DeleteIcon />
</IconButton>
</StyledTableCell>
</StyledTableRow>
))}
</TableBody>
</Table>
</TableContainer>
{/* Buttons */}
<Box mt={2} display="flex" gap={2}>
<Button variant="contained" onClick={addItem}>
Add Item
</Button>
<Button variant="outlined" color="success" onClick={generateInvoice}>
Generate Invoice
</Button>
</Box>
</Box>
{/* Error Snackbar */}
<Snackbar
open={error}
autoHideDuration={6000}
onClose={() => setError(false)}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
>
<Alert onClose={() => setError(false)} severity="error">
Please fill in all required fields.
</Alert>
</Snackbar>
</Container>
);
}
export default App;
Voici le code App.css
:
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;700&display=swap');
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: bold;
/* This is the weight for bold in Poppins */
color: #FF6347;
/* This is the color Tomato. Replace with your preferred color */
}
body {
font-family: 'Poppins', sans-serif;
background-color: #E9F8F4;
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
Pour tester la fonction de génération de PDF, exécutez la commande suivante dans le terminal :
npm start
Cela démarre le serveur de développement, et vous pouvez voir l'application dans votre navigateur à http://localhost:3000
.
Remplissez le nom du client, l'adresse et les détails de l'article dans les champs de saisie et cliquez sur le bouton "Générer la facture". Le fichier PDF sera téléchargé sur votre ordinateur et vous pourrez l'ouvrir pour voir la facture générée en pleine page.
Lorsque vous cliquez sur le bouton "Générer la facture", le fichier PDF est généré.
Si vous essayez de générer un PDF avec un champ vide, un message d'erreur s'affichera dans le coin supérieur droit.
IronPDF est une bibliothèque Node.js PDF complète qui excelle en termes de précision, de facilité d'utilisation et de rapidité. Il offre un large éventail de fonctionnalités pour générer, éditer et formater des PDF directement à partir de HTML, d'URL et d'images dans React. Grâce à la prise en charge de diverses plateformes, notamment Windows, macOS, Linux, Docker et des plateformes cloud comme Azure et AWS, IronPDF garantit une compatibilité multiplateforme. Son API conviviale permet aux développeurs d'intégrer rapidement la génération et la manipulation de PDF dans leurs projets Node.js.
Parmi les caractéristiques notables d'IronPDF Node.js, citons : un rendu parfait au pixel près, des options de formatage étendues et des capacités d'édition avancées telles que la fusion et la division de PDF, l'ajout d'annotations et la création de formulaires PDF.
Voici un exemple de génération d'un document PDF à partir de Fichier HTML, chaîne HTML, et URL:
import {PdfDocument} from "@ironsoftware/ironpdf";
(async () => {
const pdfFromUrl = await PdfDocument.fromUrl("https://getbootstrap.com/");
await pdfFromUrl.saveAs("website.pdf");
const pdfFromHtmlFile = await PdfDocument.fromHtml("design.html");
await pdfFromHtmlFile.saveAs("markup.pdf");
const pdfFromHtmlString = await PdfDocument.fromHtml("<p>Hello World</p>");
await pdfFromHtmlString.saveAs("markup_with_assets.pdf");
})();
Pour plus d'exemples de code sur les tâches liées au PDF, veuillez consulter le site suivant exemples de code page.
En conclusion, la création de PDF dans une application React ne doit pas être intimidante. Avec les bons outils et une bonne compréhension, vous pouvez générer sans effort de beaux documents PDF bien structurés. Nous avons exploré diverses bibliothèques telles que jsPDF, pdfmake, et React-PDF, chacune ayant ses propres forces et caractéristiques uniques.
Grâce au processus d'intégration simple d'IronPDF pour les cadres et les bibliothèques en JavaScript, d'excellents la documentationet un support technique réactif, les développeurs peuvent être opérationnels en un rien de temps, ce qui en fait un choix de premier ordre pour générer des PDF de qualité professionnelle dans les applications Node.js.
IronPDF offre un service de essai gratuit pour tester l'ensemble de ses fonctionnalités. Il est également disponible pour d'autres langues telles que C# .NET, Java et Python. Visitez le site IronPDF pour plus de détails.
9 produits de l'API .NET pour vos documents de bureau