Bearbeitbare Bereiche in Word-Dokumenten mit JavaScript sperren

2026-09-30 09:24:33 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

The document after an editable range is set; the lightly shaded paragraph is the editable range

Stellen Sie sich eine Vertragsvorlage vor, die an Dutzende von Kunden versendet wird. Das Rechtsteam hat jede Klausel sorgfältig ausgearbeitet, und die einzigen Dinge, die jeder Empfänger anfassen sollte, sind der Unterschriftsblock, der Projektname und das Annahmedatum. Geben Sie ihnen eine vollständig bearbeitbare Word-Datei, und irgendjemand wird unweigerlich eine Vertragsstrafenklausel umformulieren oder einen Haftungsabschnitt löschen. Sperren Sie das gesamte Dokument, und niemand kann die Felder überhaupt ausfüllen. Was Sie wirklich brauchen, ist selektives Bearbeiten — eine Möglichkeit zu sagen: „Diese bestimmten Absätze sind freigegeben, alles andere ist eingefroren.“

Genau das ermöglichen Ihnen bearbeitbare Bereiche. Sie schützen das gesamte Dokument als schreibgeschützt und setzen dann ein Paar Berechtigungsmarkierungen um die Absätze, die Sie offen halten möchten. Jeder, der die Datei in Word öffnet, kann innerhalb des markierten Bereichs tippen, aber außerhalb davon kein einziges Zeichen ändern. Spire.Doc for JavaScript bringt diese Funktion über WebAssembly in den Browser, sodass Sie geschützte Dokumente aus einer React-App ohne Server-Roundtrip erzeugen können — Schriftarten und Eingabedateien werden über ein virtuelles In-Memory-Dateisystem (VFS) verwaltet.

Dieser Leitfaden behandelt beide Hälften des Workflows:

Wenn Sie Spire.Doc noch nicht in Ihr Projekt eingebunden haben, beginnen Sie mit Integrating Spire.Doc for JavaScript in a React Project. Die folgenden Snippets gehen davon aus, dass das WebAssembly-Modul geladen und bereit ist.


Einen bearbeitbaren Bereich festlegen

Der Prozess hat drei Phasen. Zuerst laden Sie die Schriftartdateien und das Ziel-Word-Dokument mit FetchFileToVFS in das virtuelle WASM-Dateisystem. Als Nächstes instanziieren Sie ein Document, laden die Datei, rufen Protect auf, um das gesamte Dokument als schreibgeschützt zu sperren, und erstellen dann ein Paar aus PermissionStart / PermissionEnd, das dieselbe id teilt — diese beiden Markierungen umschließen den Absatz, den Sie bearbeitbar lassen möchten. Abschließend speichern Sie die Datei, lesen sie aus dem VFS zurück, verpacken sie in einen Blob und lösen einen Download aus.

function App() {
  const SetEditableRange = async () => {
    const docModule = window.wasmModule?.spiredoc;
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Load the input document into VFS
    const inputFileName = "SetEditableRange.docx";
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}static/data/`);

    // Create a document object and load the document
    const doc = new docModule.Document();
    doc.LoadFromFile(inputFileName);

    // Protect the whole document: everything outside the editable range is read-only
    doc.Protect({ type: docModule.ProtectionType.AllowOnlyReading, password: "password" });

    // Create the permission markers: a start and an end with the same id form one editable range
    const start = new docModule.PermissionStart(doc, "testID");
    const end = new docModule.PermissionEnd(doc, "testID");

    // Insert the markers into the first paragraph: the start at the beginning, the end appended at the end
    doc.Sections.get_Item(0).Paragraphs.get_Item(0).ChildObjects.Insert(0, start);
    doc.Sections.get_Item(0).Paragraphs.get_Item(0).ChildObjects.Add(end);

    // Save the document
    const outputFileName = "Set Editable Range.docx";
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });
    doc.Dispose();

    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

 return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Set Editable Range in a Word Document</h1>
      <button onClick={SetEditableRange}>
        Generate
      </button>
    </div>
  );
}
export default App;

In der Beispieldatei tragen die Felder, die ein Prüfer ausfüllen darf, eine leichte Schattierung — das ist lediglich ein visueller Hinweis für den Leser und hat keinen Einfluss darauf, wie der bearbeitbare Bereich im Code definiert wird. Sobald die Markierungen platziert sind, behandelt Word den schattierten Absatz als bearbeitbar und jeden anderen Absatz als gesperrt.

The document after an editable range is set; the lightly shaded paragraph is the editable range


Einen bearbeitbaren Bereich entfernen

Das Entfernen des bearbeitbaren Bereichs ist eine einzige Durchquerung: Sie durchlaufen jeden Abschnitt und jeden Absatz, prüfen jedes Objekt in der ChildObjects-Sammlung des Absatzes und ziehen alles heraus, was ein PermissionStart oder PermissionEnd ist.

Eine Feinheit überrascht viele: ChildObjects.Remove verkleinert die Sammlung sofort, sodass jedes Element nach dem entfernten um einen Index nach vorne rutscht. Wenn Sie Ihren Schleifenzähler beim Löschen erhöhen, wird bei jeder Entfernung genau die nächste Markierung übersprungen — und je mehr Markierungen Sie haben, desto mehr Überbleibsel bleiben zurück.

function App() {
  const RemoveEditableRange = async () => {
    const docModule = window.wasmModule?.spiredoc;
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

      // Load the input document into VFS
      const inputFileName = "RemoveEditableRange.docx";
      await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}static/data/`);

      // Create a document object and load the document
      const doc = new docModule.Document();
      doc.LoadFromFile(inputFileName);

      // Iterate over every section and paragraph and delete the permission markers
      for (let i = 0; i < doc.Sections.Count; i++) {
        const section = doc.Sections.get_Item(i);
        for (let j = 0; j < section.Body.Paragraphs.Count; j++) {
          const paragraph = section.Body.Paragraphs.get_Item(j);

          // Remove on a match; the collection shrinks, so the index is not incremented
          for (let k = 0; k < paragraph.ChildObjects.Count;) {
            const obj = paragraph.ChildObjects.get_Item(k);
            if (obj instanceof docModule.PermissionStart || obj instanceof docModule.PermissionEnd) {
              paragraph.ChildObjects.Remove(obj);
            } else {
              k++;
            }
          }
        }
      }

      // Save the document
      const outputFileName = "Remove Editable Range.docx";
      doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });

    // Release resources
    doc.Dispose();

    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

 return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Remove Editable Ranges from a Word Document</h1>
      <button onClick={RemoveEditableRange}>
        Generate
      </button>
    </div>
  );
}
export default App;

Das Löschen der Markierungen verschiebt nur die Grenze dessen, was bearbeitbar ist — der Text selbst und die gesamte Formatierung bleiben unberührt.

The document after the editable range markers are removed; the content and formatting stay unchanged


Der vollständige Schutz-Lebenszyklus

In einem realen Genehmigungsworkflow tun Sie selten nur eine einzige Sache. Ein typischer Durchlauf sieht so aus:

  1. Schützen — Rufen Sie doc.Protect mit AllowOnlyReading (oder AllowOnlyFormFields) und einem Kennwort auf. Das gesamte Dokument ist nun gesperrt.
  2. Markieren — Umschließen Sie jeden für Prüfer bearbeitbaren Absatz mit einem Paar aus PermissionStart / PermissionEnd, das eine id teilt. Diese Bereiche werden zu den einzigen Stellen, an denen ein Prüfer tippen kann.
  3. Markierung entfernen — Wenn die Prüfungsrunde vorbei ist, durchlaufen Sie das Dokument und entfernen jede Berechtigungsmarkierung. Die Bereiche fügen sich wieder in den schreibgeschützten Hauptteil ein.
  4. Schutz aufheben — Rufen Sie doc.Unprotect("password") auf, um das Dokument vollständig freizugeben und es für die nächste Verarbeitungsphase wieder in einen vollständig bearbeitbaren Zustand zu versetzen.

Die entscheidende Erkenntnis ist, dass Schutz und bearbeitbare Bereiche zwei unabhängige Ebenen sind. Der Schutz entscheidet, ob das Dokument überhaupt gesperrt ist; das Markierungspaar entscheidet, welche kleinen Bereiche von dieser Sperre ausgenommen sind. Sie können Markierungen beliebig oft hinzufügen und entfernen, ohne den Schutzstatus zu berühren, und Sie können den Schutz ein- oder ausschalten, ohne die Markierungen zu stören — aber die Markierungen haben nur dann Wirkung, wenn der Schutz aktiv ist.


FAQ

Der bearbeitbare Bereich ist festgelegt, aber der Inhalt darin kann trotzdem nicht bearbeitet werden

Warum das passiert: Berechtigungsmarkierungen sind für sich genommen wirkungslos. Sie schaffen lediglich Ausnahmen von einer dokumentweiten Einschränkung. Wenn Protect also nie aufgerufen wurde, gibt es keine Einschränkung, von der ausgenommen werden könnte, und die Markierungen bewirken nichts. Eine zweite Voraussetzung ist, dass PermissionStart und PermissionEnd dieselbe id-Zeichenfolge tragen müssen — Word behandelt sie nur dann als Paar, wenn die ids übereinstimmen.

Lösung: Aktivieren Sie zuerst die Bearbeitungseinschränkung und erstellen Sie dann beide Markierungen mit einer identischen id:

// Enable protection first so that the markers mean something
document.Protect({ type: wasmModule.ProtectionType.AllowOnlyReading, password: "password" });

// The start and the end must use the same id
const start = new wasmModule.PermissionStart(document, "testID");
const end = new wasmModule.PermissionEnd(document, "testID");

Beim Entfernen bearbeitbarer Bereiche werden einige Markierungen übersehen

Warum das passiert: Jeder Aufruf von ChildObjects.Remove verkleinert die Sammlung um eins und verschiebt den Index jedes nachfolgenden Elements nach unten. Wenn der Schleifenzähler im selben Durchlauf wie eine Entfernung erhöht wird, wird das Element, das an die aktuelle Position gerutscht ist, nie geprüft — es wird übersprungen, und das Problem verstärkt sich mit jeder weiteren Markierung.

Lösung: Halten Sie den Index beim Entfernen entweder stabil (erhöhen Sie ihn nur, wenn keine Entfernung stattgefunden hat) oder sammeln Sie die Zielobjekte zuerst und löschen Sie sie in umgekehrter Reihenfolge:

for (let k = 0; k < paragraph.ChildObjects.Count;) {
  const obj = paragraph.ChildObjects.get_Item(k);
  if (obj instanceof wasmModule.PermissionStart || obj instanceof wasmModule.PermissionEnd) {
    paragraph.ChildObjects.Remove(obj);
    // Do not increment k here: check the new object at the current index
  } else {
    k++;
  }
}

Das Dokument ist nach dem Entfernen der Markierungen weiterhin schreibgeschützt

Warum das passiert: Die Markierungen definieren nur, welche Bereiche von der Sperre ausgenommen sind — sie sind nicht die Sperre selbst. Ihr Entfernen hebt lediglich die Ausnahmen auf; der zugrunde liegende Schutz, den Protect eingerichtet hat, ist weiterhin in Kraft, sodass das gesamte Dokument schreibgeschützt bleibt.

Lösung: Sobald die Markierungen entfernt sind und Sie die Einschränkung nicht mehr benötigen, rufen Sie Unprotect mit dem ursprünglichen Kennwort auf:

document.Unprotect("password");

Siehe auch