Die Entwicklung von Windows 8
Windows Store-Blog für Entwickler
IEBlog – Deutsch
Visual Studio-Blog
Windows-Teamblogs
Blog „Inside Windows Live“
Windows 8 Release Preview herunterladen
Dev Center – Apps im Metro-Stil
Folgen Sie uns @windevs
//build/-Konferenz
Foren zu Windows-Apps im Metro-Stil
Wenn Sie Windows Store-Apps mit JavaScript entwickelt haben, kennen Sie höchstwahrscheinlich die Windows-Bibliothek für JavaScript (WinJS). Diese Bibliothek enthält eine Reihe von CSS-Formatvorlagen, JavaScript-Steuerelementen und Dienstprogrammen, mit denen Sie unkompliziert Apps entwickeln können, die den UX-Richtlinien für den Windows Store entsprechen. Zu den von WinJS bereitgestellten Dienstprogrammen gehört ein Satz von Funktionen, die Sie zur Entwicklung von benutzerdefinierten Steuerelementen in Ihrer App verwenden können.
Sie können beliebige Muster oder Bibliotheken verwenden, um JavaScript-Steuerelemente zu schreiben, die Bibliotheksfunktionen in WinJS sind hierfür nur eine Möglichkeit von vielen. Der Hauptvorteil bei der Verwendung von WinJS zum Erstellen von Steuerelementen ist, dass Sie eigene Steuerelemente entwickeln können, die zuverlässig mit den anderen in der Bibliothek enthaltenen Steuerelementen zusammenarbeiten. Die Muster für die Entwicklung und Anwendung Ihres Steuerelements stimmen mit denen aller Steuerelemente im WinJS.UI-Namespace überein.
In diesem Beitrag zeige ich Ihnen, wie Sie mit Unterstützung konfigurierbarer Optionen, Ereignisse und öffentlicher Methoden eigene Steuerelemente erstellen können. Wenn Sie sich speziell für die Entwicklung von XAML-Steuerelementen interessieren, hierzu wird in Kürze ein eigener Beitrag folgen.
Zunächst möchte ich noch einmal das Einfügen eines WinJS-Steuerelements in eine Seite beschreiben. Dafür gibt es zwei verschiedene Methoden: imperativ (indem ausschließlich und auf unauffällige Weise JavaScript verwendet wird) oder deklarativ (indem das Steuerelement mithilfe der zusätzlichen Attribute von HTML-Elementen in die HTML-Seite eingefügt wird). Die letztere Methode ermöglicht das Erstellen von Tools, die Entwurfszeitoptionen wie das Ziehen von Steuerelementen aus einer Werkzeugleiste bereitstellen können. Weitere Informationen finden Sie unter Schnellstart: Hinzufügen von WinJS-Steuerelementen und -Stilen.
In diesem Artikel wird das Erstellen eines JavaScript-Steuerelements beschrieben, das das deklarative Verarbeitungsmodell in WinJS nutzen kann. Führen Sie zum deklarativen Einfügen eines Steuerelements in Ihre Seite die folgenden Schritte aus:
<script src="//Microsoft.WinJS.1.0/js/base.js"></script><script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<script src="js/hello-world-control.js"></script>
<div data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"></div>
Wir werden nun ein sehr einfaches Steuerelement erstellen: das „Hello World“-Steuerelement. Dies ist der JavaScript-Code für das Steuerelement. Erstellen Sie in Ihrem Projekt eine neue Datei mit dem Namen „hello-world-control.js“ und dem folgenden Code:
function HelloWorld(element) { if (element) { element.textContent = "Hello, World!"; }};WinJS.Utilities.markSupportedForProcessing(HelloWorld);
Fügen Sie das Steuerelement anschließend in den Text der Seite ein und verwenden Sie dabei das folgende Markup:
<div data-win-control="HelloWorld"></div>
Wenn Sie die App ausführen, sehen Sie, dass das Steuerelement geladen wurde und den Text „Hello, World!“ im Textkörper Ihrer Seite anzeigt.
Der einzige WinJS-spezifische Bestandteil dieses Codes ist der Aufruf an WinJS.Utilities.markSupportedForProcessing, der den Code als kompatibel für die Verwendung mit deklarativen Verfahren kennzeichnet. Auf diese Weise teilen Sie WinJS mit, dass dieser Code vertrauenswürdig ist, um Inhalte in Ihre Seite zu injizieren. Weitere Informationen dazu finden Sie in der MSDN-Dokumentation für die Funktion WinJS.Utilities.markSupportedForProcessing.
Gerade habe ich beschrieben, wie Sie ein deklaratives Steuerelement erstellen können, ohne WinJS wirklich zu verwenden. Sehen Sie sich nun den folgenden Codeabschnitt an, in dem für den Großteil der Implementierung WinJS ebenfalls nicht verwendet wird. Dies ist ein komplexeres Steuerelement mit Ereignissen, konfigurierbaren Optionen und öffentlichen Methoden:
(function (Contoso) { Contoso.UI = Contoso.UI || {}; Contoso.UI.HelloWorld = function (element, options) { this.element = element; this.element.winControl = this; this.blink = (options && options.blink) ? true : false; this._onblink = null; this._blinking = 0; element.textContent = "Hello, World!"; }; var proto = Contoso.UI.HelloWorld.prototype; proto.doBlink = function () { var customEvent = document.createEvent("Event"); customEvent.initEvent("blink", false, false); if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this.element.dispatchEvent(customEvent); }; proto.addEventListener = function (type, listener, useCapture) { this.element.addEventListener(type, listener, useCapture); }; proto.removeEventListener = function (type, listener, useCapture) { this.element.removeEventListener(type, listener, useCapture); }; Object.defineProperties(proto, { blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this.doBlink.bind(this), 500); } }, enumerable: true, configurable: true }, onblink: { get: function () { return this._onblink; }, set: function (eventHandler) { if (this._onblink) { this.removeEventListener("blink", this._onblink); this._onblink = null; } this._onblink = eventHandler; this.addEventListener("blink", this._onblink); } } }); WinJS.Utilities.markSupportedForProcessing(Contoso.UI.HelloWorld);})(window.Contoso = window.Contoso || {});
Viele Entwickler erstellen Steuerelemente auf diese Art, also unter Verwendung von anonymen Funktionen, Konstruktorfunktionen, Eigenschaften und benutzerdefinierten Ereignissen. Wenn Sie und Ihr Team damit zufrieden sind, machen Sie es ruhig so! Für viele Entwickler könnte dieser Code jedoch etwas verwirrend sein. Vielen Webentwicklern sind die verwendeten Techniken nicht vertraut. In diesem Fall sind Bibliotheken sehr hilfreich, da sie das Schreiben des Codes vereinfachen können.
WinJS und andere Bibliotheken verbessern nicht nur die Lesbarkeit, sie lösen außerdem viele kleinere Probleme, über die Sie dann gar nicht mehr nachdenken müssen, wie z. B. die effiziente Verwendung von Prototypen, Eigenschaften und benutzerdefinierten Ereignissen. Sie optimieren die Speichernutzung und helfen Ihnen, häufige Fehler zu vermeiden. WinJS ist nur ein Beispiel, Sie können sich natürlich auch für andere Bibliotheken entscheiden. Als konkretes Beispiel dafür, wie hilfreich eine Bibliothek sein kann, sehen Sie sich nach dem Lesen dieses Artikels den Code in diesem Abschnitt noch einmal an, und vergleichen Sie ihn mit der Implementierung des gleichen Steuerelements am Ende des Artikels, die WinJS-Dienstprogramme verwendet.
Dies ist ein minimales, bewährtes Muster zum Erstellen eines JavaScript-Steuerelements mithilfe von WinJS.
(function () { "use strict"; var controlClass = WinJS.Class.define( function Control_ctor(element) { this.element = element || document.createElement("div"); this.element.winControl = this; this.element.textContent = "Hello, World!" }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass });})();
Fügen Sie das Steuerelement in der Seite deklarativ ein:
<div data-win-control="Contoso.UI.HelloWorld"></div>
Einiges davon kann neu für Sie sein, besonders, wenn Sie bisher noch keine Erfahrung mit WinJS haben, daher zeige ich Ihnen Schritt für Schritt, was genau passiert.
(function () {…})();
Um unser Beispiel etwas interessanter zu machen, fügen wir dem Steuerelement Unterstützung für konfigurierbare Optionen hinzu. In diesem Fall fügen wir eine Option hinzu, mit der der Benutzer den Inhalt blinken lassen kann.
var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this._doBlink.bind(this), 500); } } }, _doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass });
Konfigurieren Sie beim Einfügen des Steuerelements in die Seite die Blinkoption diesmal mithilfe des data-win-options-Attributs:
Wir haben folgende Änderungen am Code vorgenommen, um Unterstützung für Optionen hinzuzufügen:
Der entscheidende Teil ist in diesem Beispiel der Aufruf von WinJS.UI.setOptions(). SetOptions, eine Hilfsprogrammfunktion, zirkuliert durch jedes Feld im Optionsobjekt und weist ihren Wert einem gleichnamigen Feld im Zielobjekt zu, das dem ersten Parameter von setOptions entspricht.
In unserem Beispiel konfigurieren wir das options-Objekt mithilfe des data-win-options-Arguments und übergeben den Wert „true“ für das Feld „blink“. Der Aufruf von setOptions() in der Konstruktorfunktion erkennt dann das Feld namens „blink“ und kopiert seinen Wert in ein gleichnamiges Feld im Objekt des Steuerelements. Wir haben eine Eigenschaft namens „blink“ definiert, die eine setter-Funktion bereitstellt. Unsere setter-Funktion wird durch setOptions() aufgerufen und legt das _blink-Member des Steuerelements fest.
Nachdem wir nun die ungemein nützliche Blinkoption implementiert haben, werden wir eine Ereignisunterstützung hinzufügen, damit wir immer dann reagieren können, wenn ein Blinken auftritt:
var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, _blinkCount: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this._doBlink.bind(this), 500); } } }, _doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this._blinkCount++; this.dispatchEvent("blink", { count: this._blinkCount }); }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass }); // Set up event handlers for the control WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.Utilities.createEventProperties("blink"), WinJS.UI.DOMEventMixin);
Fügen Sie das Steuerelement wie zuvor in die Seite ein. Beachten Sie, dass wir dem Element eine Identität hinzugefügt haben, damit wir es später abrufen können:
<div id="hello-world-with-events" data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"></div>
Nachdem wir diese Änderungen durchgeführt haben, können wir nun einen Ereignislistener anhängen, der auf „Blink“-Ereignisse lauscht. (Hinweis: Ich habe in diesem Beispiel document.getElementById das Alias $ gegeben):
$("hello-world-with-events").addEventListener("blink", function (event) { console.log("blinked element this many times: " + event.count); });
Wenn Sie diesen Code ausführen, sehen Sie eine Benachrichtigung, die alle 500 Millisekunden an das JS Console-Fenster in Visual Studio ausgegeben wird.
Um dieses Verhalten zu unterstützen, wurden 3 Änderungen am Steuerelement vorgenommen:
Ich weise an dieser Stelle darauf hin, dass Aufrufe von dispatchEvent() nur dann funktionieren, wenn Sie im Konstruktor Ihres Steuerelements this.element eingestellt haben. Die internen Komponenten des eingemischten Ereignisses machen es erforderlich, dass es auf das Element im DOM zugreift. Hier handelt es sich um einen der vorher erwähnten Fälle, in denen im Objekt des Steuerelements ein Elementmitglied erforderlich ist. Dies gestattet es Ereignissen, in einem DOM Level 3 event Muster zu übergeordneten Elementen aufzusteigen.
Als letzte Änderung an unserem Steuerelement fügen wir eine öffentliche doBlink()-Funktion hinzu, die jederzeit aufgerufen werden kann, um ein Blinken zu erzwingen.
var controlClass = WinJS.Class.define( function Control_ctor(element, options) { this.element = element || document.createElement("div"); this.element.winControl = this; // Set option defaults this._blink = false; // Set user-defined options WinJS.UI.setOptions(this, options); element.textContent = "Hello, World!" }, { _blinking: 0, _blinkCount: 0, blink: { get: function () { return this._blink; }, set: function (value) { if (this._blinking) { clearInterval(this._blinking); this._blinking = 0; } this._blink = value; if (this._blink) { this._blinking = setInterval(this.doBlink.bind(this), 500); } } }, doBlink: function () { if (this.element.style.display === "none") { this.element.style.display = "block"; } else { this.element.style.display = "none"; } this._blinkCount++; this.dispatchEvent("blink", { count: this._blinkCount }); }, }); WinJS.Namespace.define("Contoso.UI", { HelloWorld: controlClass }); // Set up event handlers for the control WinJS.Class.mix(Contoso.UI.HelloWorld, WinJS.Utilities.createEventProperties("blink"), WinJS.UI.DOMEventMixin);
Hier handelt es sich nur um eine Konventionsänderung: Wir können den Namen der „_doBlink“-Funktion in „doBlink“ ändern.
Sie benötigen für Ihr Steuerelement einen Verweis zum Objekt, um die doBlink()-Funktion über JavaScript aufzurufen. Wenn Sie das Steuerelement imperativ erzeugt haben, verfügen Sie möglicherweise bereits über einen Verweis. Wenn Sie deklarative Verfahren anwenden, können Sie mithilfe einer winControl-Eigenschaft des HTML-Elements Ihres Steuerelements auf das Objekt des Steuerelements zugreifen. Beispielsweise können Sie, mit dem gleichen Markup wie oben, folgendermaßen auf das Objekt des Steuerelements zugreifen:
$("hello-world-with-events").winControl.doBlink();
Wir haben nun die wichtigsten Aspekte beim Implementieren eines Steuerelements kennengelernt:
Ich hoffe, dass diese Anleitung zum Erstellen eines einfachen JavaScript-basierten benutzerdefinierten Steuerelements hilfreich war! Sollten bei der Arbeit an Ihren Steuerelementen weitere Fragen auftreten, besuchen Sie das Windows-Entwicklungscenter und stellen Sie sie in den Foren. Speziell für XAML-Entwickler erscheint in Kürze ein Beitrag, der das gleiche Verfahren für die Entwicklung von XAML-Steuerelementen erläutert.
Jordan Matthiesen Programmmanager, Microsoft Visual Studio