Heim >Web-Frontend >js-Tutorial >Schreiben Sie einen sehr einfachen JavaScript-Editor
Natürlich haben wir bereits einen tollen Web-Editor parat: Sie laden ihn einfach herunter und fügen ihn in die Seite ein. Ich bin es gewohnt, CodeMirror und ACE zu verwenden. Ich habe zum Beispiel ein Plugin für CodeMirror geschrieben, um PlantUML zu unterstützen. Allerdings gibt es bei diesen Editoren ein Problem: Sie sind schwer erweiterbar und schwer zu verstehen.
Wenn ich mir den Code für diese Produkte ansehe, gibt es einige, die ich nicht leicht verstehen kann, und andere, bei denen ich nicht sicher bin, ob ich darauf aufbauen kann.
Im Moment ist es meine Philosophie, einfache Werkzeuge zu bauen, die funktionieren, verständlich, kombinierbar und erweiterbar sind. Deshalb wollte ich einen anderen Ansatz ausprobieren und einen einfachen Web-Editor von Grund auf erstellen.
Befolgen Sie das Prinzip, Code zu verwenden, um alles zu erklären. Weitere Informationen finden Sie im GitHub-Repo: https://github.com/ftomassetti/simple-web-editor
Beginnen wir mit etwas HTML-Code:
<html> <head> <link rel="stylesheet" type="text/css" href="css/style.css" media="screen" /> <script src="js/jquery-3.1.1.min.js"></script> <script src="js/webeditor.js"></script> <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet"> </head> <body> <h1>My Simple Web Editor</h1> <p id="editor"> </p> <span class="blinking-cursor">|</span> <body> </html>
Was müssen wir zur Vorbereitung tun?
Natürlich zuerst Jquery
Einige CSS
Coole Schriftarten von Google
Eine JS-Datei (wededitor.js), die den gesamten Code enthält
A p (Editor) und einen Span für den Editor
Jetzt werden wir TypeScript verwenden, in der Hoffnung, dass es die Arbeit mit JavaScript weniger schmerzhaft macht. Auch weil ich es ausprobieren wollte. Für diejenigen, die TypeScript noch nie verwendet haben: Es handelt sich im Grunde genommen um eine Obermenge von JavaScript, die die optionale Angabe von Typen ermöglicht. Typen werden zur Fehlerprüfung verwendet und dann vergessen, weil wir letztendlich JavaScript generieren. Sie können JavaScript-Bibliotheken in TypeScript verwenden. Wenn Sie eine JavaScript-Bibliothek verwenden möchten, müssen Sie möglicherweise alle Typbeschreibungen in die Bibliothek importieren. Das haben wir in der ersten Codezeile importiert.
/// <reference path="defs/jquery.d.ts" /> class Editor { private caretIndex: number; private text: string; constructor() { this.caretIndex = 0; this.text = ""; } textBeforeCaret() { if (this.caretIndex == 0) { return ""; } else { return this.text.substring(0, this.caretIndex); } } textAfterCaret() { if (this.caretIndex == this.text.length) { return ""; } else { return this.text.substring(this.caretIndex ); } } generateHtml() { return this.textBeforeCaret() + "<span class='cursor-placeholder'>|</span>" + this.textAfterCaret(); } type(c:string) { this.text = this.textBeforeCaret() + c + this.textAfterCaret(); this.caretIndex = this.caretIndex + 1; } deleteChar() : boolean { if (this.textBeforeCaret().length > 0) { this.text = this.textBeforeCaret().substring(0, this.textBeforeCaret().length - 1) + this.textAfterCaret(); this.caretIndex--; return true; } else { return false; } } moveLeft() : boolean { if (this.caretIndex == 0) { return false; } else { this.caretIndex--; return true; } } moveRight() : boolean { if (this.caretIndex == this.text.length) { return false; } else { this.caretIndex++; return true; } } } var updateHtml = function() { $("#editor")[0].innerHTML = (window as any).editor.generateHtml(); var cursorPos = $(".cursor-placeholder").position(); var delta = $(".cursor-placeholder").height() / 4.0; $(".blinking-cursor").css({top: cursorPos.top, left: cursorPos.left - delta}); }; $( document ).ready(function() { (window as any).editor = new Editor(); updateHtml(); $(document).keypress(function(e){ var c = String.fromCharCode(e.which); (window as any).editor.type(c); updateHtml(); }); $(document).keydown(function(e){ if (e.which == 8 && (window as any).editor.deleteChar()) { updateHtml(); }; if (e.which == 37 && (window as any).editor.moveLeft()) { updateHtml(); }; if (e.which == 39 && (window as any).editor.moveRight()) { updateHtml(); }; }); });
Okay, schauen wir uns den Code an. Wir haben:
Editor-Klasse
Funktion updateHTML
$(document).ready( ...) Formatverkabelung (Verkabelung)
In der Editor-Klasse müssen wir hart arbeiten. Hier speichern wir zwei Dinge:
Der im Editor enthaltene Text
Die Position des Caretzeichens im Text
TextBeforeCaret und TextAfterCaret ermöglichen uns offensichtlich, das Caretzeichen vor oder nach dem gesamten Text zu erhalten.
Was macht also genericHTML? Es generiert HTML-Code zum Platzieren von Textabschnitten zur Angabe der Caret-Position: Dieses Element ist der Caret-Platzhalter. Warum platzieren wir nicht das Caretzeichen selbst? Da die Einfügemarke eine Größe hat, wird beim Verschieben der Einfügemarke innerhalb des Textes immer der gesamte Text verschoben. Stattdessen verschieben wir den Caret-Platzhalter mit einer Größe von Null und positionieren ihn dann mit dem Caret-Platzhalter über dem Caret-Platzhalter, jedoch an einem anderen Z-Index. Auf diese Weise können wir die Einfügemarke grundsätzlich an der gewünschten Stelle sehen, ohne den Text nach links oder rechts verschieben zu müssen, um Platz für die Einfügemarke zu schaffen.
Die übrigen Methoden erlauben:
Zeichen einfügen
Zeichen löschen
Bewegen Sie die Einfügemarke nach links
Bewegen Sie die Einfügemarke nach rechts
Die Funktion updateHTML implementiert die Caret Der Trick:
var updateHtml = function() { $("#editor")[0].innerHTML = (window as any).editor.generateHtml(); var cursorPos = $(".cursor-placeholder").position(); var delta = $(".cursor-placeholder").height() / 4.0; $(".blinking-cursor").css({top: cursorPos.top, left: cursorPos.left - delta}); };
Zuerst aktualisieren wir den Inhalt des Editors, dann finden wir die Position des Caret-Platzhalters, dann bewegen wir den blinkenden Cursor, der sich über dem Platzhalter (also dem Platzhalter) befindet. Wir werden den Platzhalter tatsächlich etwas nach links verschieben, weil es so besser aussieht.
Verkabelung besteht aus dem Anhängen von Ereignishandlern an:
Abrufen von