Jak konwertować elementy HTML i fragmenty stron do formatu PDF w języku C
IronPDF nie udostępnia wbudowanej metody SelectElement ani SelectCss do kierowania działań na konkretne elementy HTML. ChromePdfRenderer renderuje kompletne dokumenty HTML — całą stronę, cały adres URL, cały ciąg HTML. Aby utworzyć plik PDF z określonej sekcji strony, izolujemy docelowy element przed renderowaniem, stosując jedną z czterech metod: manipulację DOM za pomocą JavaScript, wstrzykiwanie CSS, ekstrakcję fragmentów HTML po stronie serwera lub renderowanie adresów URL z wykorzystaniem JS.
Każde podejście odpowiada innym ograniczeniom. Izolacja DOM w JavaScript działa podczas renderowania adresów URL lub całych stron, gdzie musimy usunąć wszystko oprócz elementu docelowego. Wstrzykiwanie CSS ukrywa niepożądaną treść bez zmiany struktury DOM. Pobieranie danych po stronie serwera zapewnia najczystszy wynik, gdy mamy dostęp do surowego kodu HTML. Renderowanie adresów URL z wykorzystaniem JS obsługuje interaktywne pulpity nawigacyjne oraz strony zewnętrzne, w przypadku których źródłowy kod HTML nie jest dostępny.
Rozpocznij bezpłatny 30-dniowy okres próbny, aby przetestować wszystkie cztery podejścia.
Szybki start: Wyodrębnij określony element HTML jako plik PDF
Wybierz dowolny element za pomocą selektora CSS, korzystając z izolacji DOM w JavaScript i WaitFor, a następnie renderuj tylko ten fragment do pliku PDF.
-
Install IronPDF with NuGet Package Manager
PM > Install-Package IronPdf -
Skopiuj i uruchom ten fragment kodu.
using IronPdf; var renderer = new ChromePdfRenderer(); renderer.RenderingOptions.EnableJavaScript = true; renderer.RenderingOptions.JavaScript = @" var target = document.querySelector('#invoice-summary'); document.body.innerHTML = target.outerHTML; "; renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000); var pdf = renderer.RenderHtmlAsPdf(fullPageHtml); pdf.SaveAs("invoice-summary.pdf"); -
Wdrożenie do testowania w środowisku produkcyjnym
Rozpocznij używanie IronPDF w swoim projekcie już dziś z darmową wersją próbną
Minimalny przebieg pracy (3 kroki)
- Zainstaluj
IronPdfza pomocą NuGet:Install-Package IronPdf - Skonfiguruj
ChromePdfRenderOptions.JavaScript, aby wyodrębnić element docelowy, orazWaitFor, aby upewnić się, że istnieje - Wywołaj
RenderHtmlAsPdf()lubRenderUrlAsPdf()— plik PDF zawiera wyłącznie wyodrębnioną treść
Jak wyodrębnić elementy za pomocą manipulacji DOM w JavaScript?
Właściwość ChromePdfRenderOptions.JavaScript akceptuje ciąg znaków JavaScript, który jest wykonywany po załadowaniu kodu HTML, ale przed wyrenderowaniem pliku PDF. Zastępując document.body.innerHTML przez outerHTML elementu docelowego, usuwamy wszystko inne z renderowanej strony. Jest to najbardziej uniwersalne podejście — działa zarówno z RenderHtmlAsPdf(), jak i RenderUrlAsPdf().
Metoda WaitFor.HtmlQuerySelector() zapewnia, że element docelowy istnieje w DOM przed uruchomieniem kodu JavaScript. Ma to kluczowe znaczenie w przypadku stron z treścią asynchroniczną — komponentów React, szablonów Angular lub danych opartych na API, które wyświetlają się po początkowym załadowaniu strony.
using IronPdf;
string fullPageHtml = @"
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
";
// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
using IronPdf;
string fullPageHtml = @"
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Replace the body with only the target element
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
";
// Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000);
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-summary-only.pdf");
Imports IronPdf
Dim fullPageHtml As String = "
<html>
<body>
<header><h1>Acme Corp Invoice</h1></header>
<nav>Navigation links...</nav>
<div id='invoice-summary'>
<h2>Invoice #12345</h2>
<table>
<tr><td>Widget A</td><td>$49.99</td></tr>
<tr><td>Widget B</td><td>$29.99</td></tr>
<tr><td><strong>Total</strong></td><td><strong>$79.98</strong></td></tr>
</table>
</div>
<footer>Footer content...</footer>
</body>
</html>"
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
' Replace the body with only the target element
renderer.RenderingOptions.JavaScript = "
var el = document.querySelector('#invoice-summary');
if (el) {
document.body.innerHTML = el.outerHTML;
}
"
' Wait for the target element to exist before JS executes
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("#invoice-summary", 10000)
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-summary-only.pdf")
Kod JavaScript zastępuje całą treść elementem #invoice-summary div's outerHTML. Powstały plik PDF zawiera wyłącznie tabelę z fakturą — bez nagłówka, nawigacji ani stopki. Metoda WaitFor.HtmlElementById() stanowi prostszą alternatywę w przypadku kierowania reklam na podstawie identyfikatora:
// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
// Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000);
' Alternative: wait by ID directly
renderer.RenderingOptions.WaitFor.HtmlElementById("invoice-summary", 10000)
W przypadku złożonych selektorów (nazwy klas, atrybuty danych, elementy zagnieżdżone) HtmlQuerySelector() akceptuje każdy prawidłowy ciąg selektora CSS, który akceptowałby document.querySelector(). Dodatkowe metody pomocnicze WaitFor obejmują HtmlElementByClassName(), HtmlElementByName() oraz HtmlElementByTagName() — każda z nich wewnętrznie deleguje do HtmlQuerySelector(), ale zapewnia jaśniejszy przekaz w kodzie.
Gdy element docelowy zależy od stylów odziedziczonych po kontenerach nadrzędnych, zamiana outerHTML może spowodować utratę reguł CSS opartych na selektorach przodków (np. .dashboard .widget table { ... }. Aby je zachować, skopiuj odpowiednie tagi <style> i <link> z <head> do izolacji JS:
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
";
renderer.RenderingOptions.JavaScript = @"
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
";
renderer.RenderingOptions.JavaScript = "
var el = document.querySelector('#invoice-summary');
if (el) {
var head = document.head.innerHTML;
document.body.innerHTML = el.outerHTML;
document.head.innerHTML = head;
}
"
Zachowuje to oryginalną treść <head> (arkusze stylów, czcionki, metatagi), zastępując jedynie treść. Poradnik "JavaScript to PDF" oraz poradnik "WaitFor" obejmują dodatkowe opcje konfiguracyjne, w tym NetworkIdle0() dla stron z wieloma asynchronicznymi źródłami danych.
Jak wyodrębnić elementy za pomocą wstrzykiwania CSS?
Właściwość ChromePdfRenderOptions.CustomCssUrl akceptuje ścieżkę do pliku lub adres URL arkusza stylów, który IronPDF stosuje przed renderowaniem. Zamiast manipulować DOM, ukrywamy wszystko oprócz elementu docelowego za pomocą CSS display: none. Pozwala to zachować oryginalną strukturę DOM i całkowicie uniknąć wykonywania kodu JavaScript.
using IronPdf;
// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
using IronPdf;
// Create a CSS file that hides everything except #invoice-summary
string cssContent = @"
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
";
File.WriteAllText("isolate-element.css", cssContent);
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css";
PdfDocument pdf = renderer.RenderHtmlAsPdf(fullPageHtml);
pdf.SaveAs("invoice-css-isolated.pdf");
Imports IronPdf
Imports System.IO
' Create a CSS file that hides everything except #invoice-summary
Dim cssContent As String = "
body > *:not(#invoice-summary) {
display: none !important;
}
#invoice-summary {
display: block !important;
margin: 0;
padding: 20px;
}
"
File.WriteAllText("isolate-element.css", cssContent)
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CustomCssUrl = "isolate-element.css"
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fullPageHtml)
pdf.SaveAs("invoice-css-isolated.pdf")
Uwaga: Właściwość CustomCssUrl działa tylko z RenderHtmlAsPdf() podczas renderowania z ciągów HTML. W przypadku renderowania adresów URL należy zamiast tego osadzić wstrzyknięcie CSS we właściwości JavaScript:
renderer.RenderingOptions.JavaScript = @"
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = @"
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
";
renderer.RenderingOptions.JavaScript = "
var style = document.createElement('style');
style.textContent = 'body > *:not(#invoice-summary) { display: none !important; }';
document.head.appendChild(style);
"
Gdy mamy kontrolę nad źródłowym kodem HTML, reguły @media print oferują najlżejszą alternatywę — bez zewnętrznych zależności, bez wstrzykiwania w czasie wykonywania:
@media print {
header, nav, footer, .sidebar { display: none !important; }
#invoice-summary { width: 100%; margin: 0; }
}
Ustaw CssMediaType na PdfCssMediaType.Print w rendererze, aby aktywować te reguły:
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
Jest to idealne rozwiązanie w przypadku drukowania sekcji formularzy, gdzie aplikacja już definiuje reguły @media print, lub w przypadku podejścia 3, gdy kod HTML formularza jest generowany po stronie serwera.
Podejście CSS ma jedno istotne ograniczenie: ukryte elementy nadal zajmują miejsce w przepływie dokumentu, jeśli display: none zostanie użyte na niewłaściwym poziomie specyficzności. Zawsze używaj !important, aby zastąpić style frameworków (Bootstrap, Tailwind), które mogą ponownie wyświetlać elementy w określonych punktach przełamania. W przypadku głęboko zagnieżdżonych elementów docelowych bardziej precyzyjny selektor pozwala uniknąć ukrycia elementów pobocznych:
body > *:not(#target),
body > *:not(#target) ~ * {
display: none !important;
}
Jak wyodrębnić fragmenty HTML po stronie serwera?
Gdy mamy dostęp do surowego kodu HTML — odczytując go z pliku, bazy danych, systemu CMS lub odpowiedzi HTTP — najczystszym podejściem jest wyodrębnienie docelowego elementu po stronie serwera za pomocą parsera HTML, a następnie przekazanie fragmentu do RenderHtmlAsPdf(). Bez JavaScriptu, bez wstrzykiwania CSS, bez manipulacji DOM w czasie wykonywania.
AngleSharp jest standardowym parserem HTML dla platformy .NET Standard przeznaczonym do tego wzorca:
using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;
string fullPageHtml = @"
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>";
// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");
if (targetElement is null)
{
Console.WriteLine("Target element not found.");
return;
}
// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
using IronPdf;
using AngleSharp;
using AngleSharp.Html.Parser;
string fullPageHtml = @"
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>";
// Parse and extract the target element
var parser = new HtmlParser();
var document = parser.ParseDocument(fullPageHtml);
var targetElement = document.QuerySelector("#revenue-widget");
if (targetElement is null)
{
Console.WriteLine("Target element not found.");
return;
}
// Wrap the fragment in a minimal HTML document to preserve styles
string fragmentHtml = $@"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget.pdf");
Imports IronPdf
Imports AngleSharp
Imports AngleSharp.Html.Parser
Dim fullPageHtml As String = "
<html>
<head>
<style>
table { border-collapse: collapse; width: 100%; }
td, th { border: 1px solid #ddd; padding: 8px; text-align: left; }
</style>
</head>
<body>
<header><h1>Dashboard</h1></header>
<div id='revenue-widget'>
<h3>Q4 Revenue</h3>
<table>
<tr><th>Month</th><th>Revenue</th></tr>
<tr><td>October</td><td>$1.2M</td></tr>
<tr><td>November</td><td>$1.5M</td></tr>
<tr><td>December</td><td>$1.8M</td></tr>
</table>
</div>
<div id='other-content'>Other widgets...</div>
</body>
</html>"
' Parse and extract the target element
Dim parser As New HtmlParser()
Dim document = parser.ParseDocument(fullPageHtml)
Dim targetElement = document.QuerySelector("#revenue-widget")
If targetElement Is Nothing Then
Console.WriteLine("Target element not found.")
Return
End If
' Wrap the fragment in a minimal HTML document to preserve styles
Dim fragmentHtml As String = $"
<html>
<head>
<style>
table {{ border-collapse: collapse; width: 100%; }}
td, th {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
</style>
</head>
<body>
{targetElement.OuterHtml}
</body>
</html>"
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget.pdf")
Kluczowym szczegółem jest umieszczenie wyodrębnionego fragmentu w kompletnym dokumencie HTML z odpowiednimi tagami <style> lub <link>. Bez tej nakładki style wbudowane renderują się poprawnie, ale zewnętrzne arkusze stylów i odziedziczone reguły CSS są tracone. W przypadku renderowania podglądu szablonu wiadomości e-mail — gdzie kod HTML szablonu jest już zapisany jako ciąg znaków — ten wzorzec ekstrakcji zapewnia wyniki idealne pod względem pikseli, ponieważ kontrolujemy każdy aspekt renderowanej treści.
Ten sam schemat działa z HtmlAgilityPack jako alternatywnym parserem:
using HtmlAgilityPack;
using IronPdf;
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);
var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
Console.WriteLine("Target element not found.");
return;
}
string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
using HtmlAgilityPack;
using IronPdf;
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(fullPageHtml);
var targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']");
if (targetNode is null)
{
Console.WriteLine("Target element not found.");
return;
}
string fragmentHtml = $"<html><body>{targetNode.OuterHtml}</body></html>";
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml);
pdf.SaveAs("revenue-widget-hap.pdf");
Imports HtmlAgilityPack
Imports IronPdf
Dim htmlDoc As New HtmlDocument()
htmlDoc.LoadHtml(fullPageHtml)
Dim targetNode = htmlDoc.DocumentNode.SelectSingleNode("//*[@id='revenue-widget']")
If targetNode Is Nothing Then
Console.WriteLine("Target element not found.")
Return
End If
Dim fragmentHtml As String = $"<html><body>{targetNode.OuterHtml}</body></html>"
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml)
pdf.SaveAs("revenue-widget-hap.pdf")
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
PdfDocument pdf = renderer.RenderHtmlAsPdf(fragmentHtml, @"C:\templates\assets\");
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(fragmentHtml, "C:\templates\assets\")
Wybór między AngleSharp a HtmlAgilityPack jest w dużej mierze kwestią preferencji. AngleSharp wykorzystuje selektory CSS (QuerySelector), co jest zgodne z modelami mentalnymi programistów frontendowych. HtmlAgilityPack wykorzystuje XPath (SelectSingleNode), który jest bardziej znany w kodach .NET opartych na XML.
Dla renderowania podglądu szablonu email — generowanie podglądu PDF szablonu email HTML przed wysłaniem — jest to czysta sytuacja via Podejście 3. Szablon HTML jest zapisanym ciągiem znaków, zasoby zewnętrzne (obrazy, czcionki) są hostowane pod znanymi adresami URL, a parametr RenderHtmlAsPdf(string Html, string BaseUrlOrPath) w RenderHtmlAsPdf() rozstrzyga wszystkie ścieżki względne.
Gdy kod HTML zawiera <div id="app"></div>, który aplikacja React lub Vue wypełnia w czasie wykonywania, wyodrębniony fragment będzie pusty. W takich przypadkach należy zastosować podejście 1 lub 4.
Jak kierować reklamy na elementy podczas renderowania aktywnych adresów URL?
W przypadku aktywnych adresów URL, do których nie mamy dostępu do źródłowego kodu HTML — panele kontrolne stron trzecich, raporty zewnętrzne, aplikacje hostowane — łączymy RenderUrlAsPdf() z właściwością JavaScript oraz WaitFor, aby wyodrębnić konkretną sekcję po załadowaniu strony.
Oto scenariusz eksportu widżetu pulpitu nawigacyjnego: narzędzie BI wyświetla wykresy i tabele na stronie internetowej, a my musimy wyeksportować pojedynczy widżet jako plik PDF w celu dystrybucji wśród interesariuszy.
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);
// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
var widget = document.querySelector('[data-widget=""revenue-chart""]');
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
";
PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.EnableJavaScript = true;
// Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000);
// Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = @"
var widget = document.querySelector('[data-widget=""revenue-chart""]');
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
";
PdfDocument pdf = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report");
pdf.SaveAs("revenue-chart-export.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.EnableJavaScript = True
' Wait for the dashboard widget to render (async content)
renderer.RenderingOptions.WaitFor.HtmlQuerySelector("[data-widget='revenue-chart']", 15000)
' Isolate the widget after it renders
renderer.RenderingOptions.JavaScript = "
var widget = document.querySelector('[data-widget=""revenue-chart""]);
if (widget) {
// Preserve computed styles by cloning into a clean body
document.body.innerHTML = '';
document.body.appendChild(widget);
}
"
Dim pdf As PdfDocument = renderer.RenderUrlAsPdf("https://dashboard.example.com/q4-report")
pdf.SaveAs("revenue-chart-export.pdf")
Wywołanie WaitFor.HtmlQuerySelector() gwarantuje, że widget istnieje w DOM przed wykonaniem kodu JavaScript. Limit czasu wynoszący 15 sekund uwzględnia wolniejsze wywołania API, które wypełniają dane na pulpicie nawigacyjnym. Następnie JavaScript redukuje stronę do samego widgetu.
W przypadku stron o złożonych zależnościach CSS podejście appendChild (przenoszenie węzła zamiast kopiowania jego outerHTML) pozwala zachować więcej obliczonych stylów, ponieważ element zachowuje swoją pozycję w CSSOM. Podejście polegające na zastąpieniu innerHTML z podejścia 1 jest prostsze, ale może spowodować utratę stylów zależnych od selektorów nadrzędnych.
Jeśli strona docelowa wymaga uwierzytelnienia, skonfiguruj pliki cookie w rendererze przed wywołaniem RenderUrlAsPdf():
renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
{ "session_id", "abc123" },
{ "auth_token", "bearer-xyz" }
};
renderer.RenderingOptions.CustomCookies = new Dictionary<string, string>
{
{ "session_id", "abc123" },
{ "auth_token", "bearer-xyz" }
};
Imports System.Collections.Generic
renderer.RenderingOptions.CustomCookies = New Dictionary(Of String, String) From {
{"session_id", "abc123"},
{"auth_token", "bearer-xyz"}
}
Klasa WaitFor oferuje dodatkowe strategie oczekiwania wykraczające poza HtmlQuerySelector(). NetworkIdle0() czeka, aż wszystkie żądania sieciowe zostaną zakończone bez żadnych nierozwiązanych połączeń — przydatne w przypadku pulpitów nawigacyjnych, które ładują dane z wielu punktów końcowych API. NetworkIdle2() toleruje maksymalnie dwa aktywne połączenia, co pozwala obsługiwać strony z trwałymi połączeniami WebSocket lub długim odpytywaniem. JavaScript() czeka, aż strona wywoła window.ironpdf.notifyRender() — jest to najdokładniejsza opcja, gdy kontrolujemy stronę docelową i możemy wyraźnie zasygnalizować gotowość do renderowania po załadowaniu wszystkich danych i zakończeniu animacji.
W przypadku powtarzających się eksportów z pulpitu nawigacyjnego (np. generowanie plików PDF co noc w celu rozesłania ich pocztą elektroniczną do interesariuszy) należy umieścić renderowanie w pętli ponownych prób, która przechwytuje wyjątki związane z przekroczeniem limitu czasu. Jeśli WaitFor przekroczy swój maxWaitTime, IronPDF przystępuje do renderowania dostępnej treści — która może być niekompletna. Zwiększenie limitu czasu lub przejście na NetworkIdle0() zazwyczaj rozwiązuje sporadyczne awarie w wolniejszych sieciach.
Porównanie wszystkich czterech podejść
| Podejście | Najlepsze dla | Wymagany kod źródłowy HTML | Zależność JS | Złożoność |
|---|---|---|---|---|
| Izolacja DOM w JavaScript | Powszechne wyodrębnianie elementów z dowolnego źródła | Nie | Tak | Medium |
| Wstrzykiwanie CSS | Ukrywanie sekcji bez zmian w DOM; @media print układy |
Częściowe (CustomCssUrl wymaga RenderHtmlAsPdf) |
Nie (chyba że wstawianie odbywa się za pomocą JS dla adresów URL) | Low |
| Wyodrębnianie fragmentów po stronie serwera | Treści CMS, zapisane szablony, podglądy wiadomości e-mail | Tak | Nie | Niski–Średni |
| Renderowanie adresów URL z wykorzystaniem JS Targeting | Aktywne pulpity nawigacyjne, strony zewnętrzne, widżety SPA | Nie | Tak | Średni–wysoki |
Wybór właściwego podejścia
Decyzja zależy od dwóch czynników: czy mamy dostęp do surowego kodu HTML oraz czy renderowanie treści docelowej wymaga użycia JavaScript.
Invoice Wyodrębnianie pozycji jest najczęstszym przypadkiem użycia. Gdy kod HTML faktury jest generowany po stronie serwera (widoki Razor, szablony Handlebars, zapisane ciągi HTML), podejście 3 (pobieranie po stronie serwera) zapewnia najczystszy wynik bez obciążenia środowiska uruchomieniowego. Wyodrębnij tabelę #line-items, umieść ją w stylizowanej powłoce HTML i wyrenderuj.
Dashboard Eksport widżetu wymaga wykonania kodu JavaScript, ponieważ zawartość widżetu jest wypełniana przez wywołania API po początkowym załadowaniu strony. Podejście 1 (izolacja JS DOM) radzi sobie z tym, gdy pulpit nawigacyjny działa lokalnie lub za uwierzytelnieniem. Podejście 4 (renderowanie adresów URL z wykorzystaniem JS) jest konieczne, gdy pulpit nawigacyjny jest aplikacją hostowaną przez stronę trzecią, w przypadku której dysponujemy jedynie adresem URL.
Drukowanie sekcji Form — wyodrębnianie określonej sekcji wieloetapowego formularza do przeglądu przez użytkownika lub archiwizacji zgodności — w naturalny sposób odpowiada podejściu 2 (wstrzykiwanie CSS), gdy aplikacja zdefiniowała już reguły @media print, lub podejściu 3, gdy kod HTML formularza jest składany po stronie serwera.
Renderowanie podglądu szablonu Email — generowanie podglądu PDF szablonu wiadomości e-mail w formacie HTML przed wysłaniem — jest scenariuszem typowym dla podejścia 3. Szablon HTML jest zapisanym ciągiem znaków, zasoby zewnętrzne (obrazy, czcionki) są hostowane pod znanymi adresami URL, a parametr BaseUrlOrPath w RenderHtmlAsPdf() rozstrzyga wszystkie ścieżki względne.
W przypadku aplikacji, które muszą obsługiwać wiele scenariuszy, należy zamknąć logikę renderowania w interfejsie usługi, który akceptuje parametr strategii:
public enum ElementExtractionStrategy
{
JavaScriptIsolation,
CssInjection,
ServerSideExtraction,
UrlWithJsTargeting
}
public enum ElementExtractionStrategy
{
JavaScriptIsolation,
CssInjection,
ServerSideExtraction,
UrlWithJsTargeting
}
Public Enum ElementExtractionStrategy
JavaScriptIsolation
CssInjection
ServerSideExtraction
UrlWithJsTargeting
End Enum
Dzięki temu kod wywołujący może wybrać odpowiednie podejście w oparciu o typ danych wejściowych bez konieczności powielania konfiguracji renderera.
Kolejne kroki
Izolacja elementów HTML w IronPDF jest kwestią dotyczącą renderowania, a nie wbudowaną funkcją API. Powyższe cztery podejścia obejmują pełne spektrum — od ekstrakcji szablonów po stronie serwera (zero JS, najczystszy wynik) po kierowanie na aktywne adresy URL (pełne wykonanie JS, obsługa aplikacji SPA i treści asynchronicznych). Tabela porównawcza stanowi skrócone źródło informacji, a scenariusze z życia wzięte odnoszą typowe wymagania biznesowe do odpowiedniej strategii.
Kilka dodatkowych uwag dotyczących wdrożeń produkcyjnych:
Wydajność: Pobieranie po stronie serwera (podejście 3) jest najszybsze, ponieważ całkowicie pomija wykonanie kodu JavaScript. Podejścia oparte na JavaScript (1 i 4) powodują obciążenie proporcjonalne do złożoności strony i limitu czasu WaitFor. W przypadku przetwarzania wsadowego (np. generowania 500 plików PDF z fakturami) najlepszą przepustowość zapewnia ekstrakcja po stronie serwera z wykorzystaniem Parallel.ForEach i wielu instancji ChromePdfRenderer.
Debugowanie: Jeśli plik PDF jest pusty lub brakuje w nim treści, włącz EnableJavaScript = true i zwiększ limit czasu WaitFor. Jeśli element docelowy zależy od danych asynchronicznych, WaitFor.NetworkIdle0() jest bardziej niezawodny niż stały RenderDelay. Przewodnik po opcjach renderowania obejmuje konfiguracje szerokości okna wyświetlania i dopasowania do papieru, które mają wpływ na układ.
Łączenie podejść: Nic nie stoi na przeszkodzie, aby łączyć strategie. Możemy użyć ekstrakcji po stronie serwera, aby zbudować złożony dokument HTML z wielu fragmentów (nagłówek z jednego źródła, tabela danych z innego, wykres SVG z trzeciego), a następnie wyrenderować złożony dokument jako pojedynczy plik PDF. Metoda RenderHtmlAsPdf(string Html, string BaseUrlOrPath) rozpoznaje względne ścieżki zasobów na podstawie adresu URL bazowego, co ułatwia tworzenie dokumentów z różnorodnych źródeł.
Zapoznaj się z poradnikiem JavaScript to PDF, aby poznać zaawansowane wzorce wykonywania JS, dokumentacją WaitFor zawierającą wszystkie dostępne strategie oczekiwania, przewodnikiem po opcjach renderowania obejmującym pełną powierzchnię ChromePdfRenderOptions oraz przykładem niestandardowego kodu JavaScript zawierającym gotowe do użycia fragmenty kodu.
Zobacz opcje licencji, zaczynając od $999. Dokumentacja API ChromePdfRenderOptions i WaitFor opisuje wszystkie właściwości i metody.
Często Zadawane Pytania
Jakie są główne metody konwersji elementów HTML do formatu PDF w języku C#?
Główne podejścia obejmują izolację JS, ukrywanie CSS, ekstrakcję po stronie serwera oraz kierowanie na aktywne adresy URL, a wszystkie one mogą być wdrożone przy użyciu IronPDF.
Jak działa izolacja JS w kontekście konwersji HTML do PDF?
Izolacja JS polega na uruchomieniu kodu JavaScript w celu dynamicznej manipulacji dokumentem HTML przed konwersją do formatu PDF. Można to osiągnąć za pomocą IronPDF, aby zapewnić renderowanie tylko określonych elementów.
Czym jest ukrywanie CSS i jak wykorzystuje się je podczas konwersji plików PDF?
Ukrywanie za pomocą CSS polega na użyciu stylów CSS do ukrycia elementów, które nie powinny pojawiać się w pliku PDF. IronPDF obsługuje tę funkcję, umożliwiając programistom określenie arkuszy stylów lub reguł stylów podczas procesu konwersji.
Czy IronPDF może wyodrębniać określone elementy HTML po stronie serwera w celu generowania plików PDF?
Tak, IronPDF może wyodrębniać określone elementy HTML po stronie serwera, co pozwala na precyzyjną kontrolę nad tym, które części strony internetowej są konwertowane do formatu PDF.
Jaka jest zaleta kierowania na aktywne adresy URL podczas konwersji HTML do PDF?
Funkcja Live URL targeting pozwala IronPDF konwertować elementy z aktywnego adresu URL strony internetowej bezpośrednio do formatu PDF, zapewniając przechwycenie najbardziej aktualnej treści bez konieczności korzystania z lokalnych plików HTML.
Czy za pomocą IronPDF można przekonwertować tylko część strony internetowej do formatu PDF?
Tak, IronPDF oferuje funkcję konwersji określonych sekcji lub elementów strony internetowej do formatu PDF, co ułatwia skupienie się na istotnych treściach.
W jaki sposób IronPDF radzi sobie z treścią dynamiczną podczas konwersji HTML do PDF?
IronPDF może renderować treści dynamiczne poprzez wykonywanie kodu JavaScript podczas konwersji, zapewniając, że elementy oparte na skryptach po stronie klienta są dokładnie odwzorowane w pliku PDF.

