Dokumentation
PDFs erstellen
PDFs in Vue
PDFs in Nuxt
PDFs in React
PDFs in Angular
Daten und Assets
Reaktive Daten
Der ganze Sinn, in Vue zu schreiben: Ihre Daten steuern das Dokument. v-for, v-if, computed und Slots
funktionieren alle - der Renderer läuft durch denselben Baum, den Vue baut, also wird alles, was einen Baum
erzeugt, zu einem PDF.
<script setup lang="ts">
import { computed } from "vue";
import { Document, Page, Row, Text, Divider } from "@jasy/vue";
const props = defineProps<{ lines: { id: number; name: string; price: number }[] }>();
const total = computed(() => props.lines.reduce((sum, l) => sum + l.price, 0));
</script>
<template>
<Document :size="11">
<Page :size="'A4'" :margin="48" :gap="8">
<Row v-for="line in lines" :key="line.id" :justify="'between'">
<Text>{{ line.name }}</Text>
<Text>{{ line.price }} EUR</Text>
</Row>
<Divider />
<Row :justify="'between'">
<Text bold>Total</Text>
<Text bold>{{ total }} EUR</Text>
</Row>
</Page>
</Document>
</template>
Ein PDF wird einmal gerendert und nicht wie eine Seite am Leben gehalten: Laden Sie, was das Dokument
braucht, vor renderToPdf und übergeben Sie es als Props. Eine Änderung in onMounted (oder ein
asynchroner Fetch dort) kommt zu spät - das Dokument ist dann schon gelesen.
Eigene Fonts
Die Standard-PDF-Fonts (Helvetica, Times, Courier) brauchen nichts. Für einen eigenen registrieren Sie den
Font unter einem Namen an <Document :fonts> und verwenden diesen Namen dann als font. Im Browser holen
Sie zuerst die Bytes und übergeben sie:
<!-- Report.vue -->
<script setup lang="ts">
import { Document, Page, Text } from "@jasy/vue";
defineProps<{ font: Uint8Array }>();
</script>
<template>
<Document :fonts="{ Inter: font }" font="Inter">
<Page size="A4" :margin="48">
<Text :size="24" bold>Set in Inter</Text>
</Page>
</Document>
</template>
const font = new Uint8Array(await (await fetch("/fonts/Inter.woff2")).arrayBuffer());
const bytes = await renderToPdf(Report, { font });
Das Format spielt keine Rolle: .ttf, .woff und .woff2 sind hier dasselbe - jasy entpackt den
Wrapper selbst. Volles Unicode kommt mit, und der Font wird auf dem Weg ins PDF gesubsettet, die Datei bleibt
also klein. Für mehrere Schriftstärken registrieren Sie eine Datei pro Stil als
{ Inter: { normal, bold, italic } }.
Auf dem Server (definePdfHandler in Nuxt oder jeder Node-Prozess) funktioniert auch ein einfacher
Pfad - dort ist :fonts="{ Inter: '/path/to/Inter.woff2' }" schon alles. Im Browser gibt es kein
Dateisystem, auf das man zeigen könnte, also sind es Bytes.
Bilder
<Image :src> nimmt die Bild-Bytes als Uint8Array, eine URL oder - auf einem Server - einen Pfad. JPEG
und PNG funktionieren beide, und die Transparenz eines PNG bleibt erhalten: Es liegt über dem, was
dahinter ist, nicht in einem weißen Kasten. Bytes kommen genauso wie ein Font, als Prop:
<template>
<Image :src="logo" :width="120" :height="40" fit="contain" />
</template>
Eine URL wird geladen, während das Dokument vorbereitet wird, noch vor dem Layout, ihre Größe ist also bekannt, wenn die Seite angeordnet wird.
Render-Optionen
renderToPdf (und renderToPdfString) nehmen die Render-Optionen der Engine als drittes Argument:
const bytes = await renderToPdf(Invoice, props, {
onOverflow: "warn",
accessible: true,
encrypt: { userPassword: "secret" },
onDiagnostic: (d) => console.log(d.code, d.message),
});
onOverflow- was passiert, wenn ein einzelnes unteilbares Element höher als die Seite ist:"error"(Standard) wirft,"warn"platziert es abgeschnitten und protokolliert,"ignore"platziert es abgeschnitten.accessible- ein getaggtes PDF mit Structure Tree für Screenreader, siehe Barrierefreiheit.encrypt- Passwortschutz mit AES-256, siehe Verschlüsselung.onDiagnostic- alles, was die Engine über das Dokument zu sagen hat, ein Aufruf pro Befund, siehe Ausgabeoptionen.
Ein Descriptor für einen Server
toDocumentDescriptor(Component, props) hält vor dem PDF an und gibt den Descriptor der Engine zurück:
einen einfachen Baum { type, props, children }, den buildDocument zum Dokument macht. Um ihn als JSON
zu senden, kodieren Sie Font- und Bild-Bytes selbst - JSON kennt kein Uint8Array - und dekodieren sie auf
der anderen Seite. Funktionen überleben JSON gar nicht, ein Dokument mit <Canvas>, <Flow> oder
<PageBuilder> geht also über renderToPdf.