Conception de Windows 8
Blog Windows Store pour les développeurs
IEBlog Français
Blog Visual Studio
Blogs de l'équipe Windows
Blog Windows Live
Télécharger Windows 8 Release Preview
Centre de développement : applications de style Metro
Suivez-nous @windevs
Conférence BUILD de Windows //build/
Développement d’applications Metro
Si vous avez déjà développé des applications Windows Store en JavaScript, vous connaissez sans doute déjà la bibliothèque Windows pour JavaScript (WinJS). Cette bibliothèque met à votre disposition des styles CSS, ainsi que des contrôles et des utilitaires JavaScript qui vous permettent de créer rapidement des applications respectant les recommandations relatives à l'expérience utilisateur du Windows Store. WinJS propose notamment différentes fonctions que vous pouvez utiliser pour créer des contrôles personnalisés au sein de votre application.
Pour développer vos contrôles JavaScript, vous pouvez utiliser les modèles et les bibliothèques que vous souhaitez : les fonctions de bibliothèque fournies dans WinJS ne constituent qu'une des possibilités qui s'offrent à vous. En créant vos contrôles avec WinJS, vous profitez néanmoins d'un avantage important : vous créez des contrôles personnalisés qui fonctionneront en parfaite cohérence avec les autres contrôles de la bibliothèque. Les modèles de développement et d'utilisation des contrôles personnalisés sont identiques à ceux des autres contrôles de l'espace de noms WinJS.UI.
Dans ce billet, je vais vous expliquer comment créer vos propres contrôles prenant en charge des options configurables, des événements et des méthodes publiques. Certains d'entre vous souhaiteront peut-être savoir comment faire de même avec les contrôles XAML. Sachez que nous aborderons ce sujet dans un prochain billet !
Tout d'abord, rappelons comment insérer un contrôle WinJS dans une page. Deux possibilités s'offrent à vous : vous pouvez procéder à une insertion impérative (en utilisant exclusivement JavaScript, de façon non obtrusive) ou à une insertion déclarative (en insérant les contrôles dans votre page HTML via des attributs complémentaires appliqués aux éléments HTML). Avec la deuxième méthode, les outils fournissent une expérience utilisateur au moment de la conception, ce qui permet par exemple de faire glisser des contrôles à partir d'une boîte à outils. Pour en savoir plus, consultez l'article MSDN suivant : Démarrage rapide : ajout de contrôles et de styles WinJS.
Dans cet article, je vais vous expliquer comment générer un contrôle JavaScript exploitant le modèle de traitement déclaratif de WinJS. Pour insérer un contrôle dans votre page de façon déclarative, suivez la procédure ci-dessous :
<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>
Créons maintenant un contrôle très simple : le « Hello World » des contrôles ! Voici le code JavaScript utilisé pour définir le contrôle. Créez un fichier appelé hello-world-control.js dans votre projet, en utilisant le code suivant :
function HelloWorld(element) { if (element) { element.textContent = "Hello, World!"; }};WinJS.Utilities.markSupportedForProcessing(HelloWorld);
Ensuite, dans le corps de votre page, insérez le contrôle en utilisant le code suivant :
<div data-win-control="HelloWorld"></div>
Si vous exécutez votre application, vous pouvez constater que le contrôle a été chargé et qu'il affiche le texte « Hello, World! » dans le corps de votre page.
Le seul fragment de code propre à WinJS est l'appel de WinJS.Utilities.markSupportedForProcessing, qui décrit le code comme compatible avec un traitement déclaratif. Ceci vous permet d'indiquer à WinJS que vous autorisez ce code à injecter du contenu dans votre page. Pour en savoir plus à ce sujet, consultez la documentation MSDN consacrée à la fonction WinJS.Utilities.markSupportedForProcessing.
Je viens de vous montrer comment créer un contrôle déclaratif sans vraiment utiliser WinJS. Examinons maintenant le fragment de code suivant, qui n'utilise toujours pas WinJS pour la majeure partie de ses implémentations. Il s'agit là d'un contrôle plus complexe, possédant des événements, des options configurables et des méthodes publiques :
(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 || {});
De nombreux développeurs construisent les contrôles de cette manière (à l'aide de fonctions anonymes, de fonctions de constructeur, de propriétés et d'événements personnalisés). Si votre équipe de développement est à l'aise avec cette méthode, inutile de changer vos habitudes ! Cependant, pour certains développeurs, ce code peut s'avérer quelque peu déroutant. En effet, de nombreux développeurs Web ne maîtrisent pas les techniques utilisées. C'est là tout l'intérêt des bibliothèques : elles rendent l'écriture du code moins complexe et moins déroutante.
En plus d'améliorer la lecture du code, WinJS et les autres bibliothèques gèrent pour vous de nombreux éléments subtils dont vous n'avez plus à vous préoccuper (les prototypes, propriétés et événements personnalisés sont utilisés de façon efficace). Elles optimisent l'utilisation de la mémoire et vous évitent de tomber dans les pièges courants. WinJS n'est qu'un exemple : c'est vous qui choisissez ! Pour découvrir plus concrètement les avantages liés à l'utilisation d'une bibliothèque, une fois que vous aurez terminé la lecture de ce billet, je vous invite à réexaminer le code qui y figure et à comparer l'implémentation précédente avec le même contrôle implémenté à la fin de l'article à l'aide des utilitaires de WinJS.
Le code suivant offre un modèle recommandé pour la création d'un contrôle JavaScript avec 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 });})();
Dans votre, page, insérez le contrôle de façon déclarative :
<div data-win-control="Contoso.UI.HelloWorld"></div>
Certaines parties de ce code vous sembleront sans doute inconnues, en particulier si vous n'avez jamais utilisé WinJS. Examinons plus en détail le processus.
(function () {…})();
Pour rendre notre exemple un peu plus intéressant, ajoutons à notre contrôle la prise en charge d'options configurables. Dans ce cas, nous allons ajouter une option permettant à l'utilisateur de faire clignoter le contenu.
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 });
Cette fois-ci, lorsque vous insérez le contrôle dans votre page, vous pouvez configurer l'option de clignotement en utilisant l'attribut data-win-options :
Pour ajouter la prise en charge d'options, apportons les modifications suivantes au code :
Dans cet exemple, le gros du travail correspond à l'appel de la fonction WinJS.UI.setOptions(). Une fonction utilitaire, setOptions, passe en revue chacun des champs de l'objet options et attribue sa valeur à un champ du même nom sur l'objet cible, qui est le premier paramètre de setOptions.
Dans notre exemple, nous configurons l'objet options par le biais de l'argument data-win-options de notre contrôle win-control, afin de transmettre la valeur true pour le champ « blink ». L'appel de setOptions() dans notre fonction de constructeur détecte ensuite le champ « blink » et copie sa valeur dans un champ portant le même nom dans notre objet de contrôle. Nous avons défini une propriété blink qui fournit une fonction setter. Cette fonction est appelée par setOptions(), ce qui a pour effet de définir le membre _blink de notre contrôle.
Maintenant que nous avons implémenté notre option blink, ajoutons la prise en charge des événements, afin de pouvoir répondre chaque fois qu'un événement blink a lieu :
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);
Insérez le contrôle dans la page, comme nous l'avons déjà expliqué. Vous remarquerez que nous avons ajouté un identifiant à l'élément, pour pouvoir le retrouver facilement par la suite :
<div id="hello-world-with-events" data-win-control="Contoso.UI.HelloWorld" data-win-options="{blink: true}"></div>
Ces modifications effectuées, nous pouvons maintenant associer un détecteur d'événements afin d'écouter l'événement « blink » (remarque : dans cet exemple, l'alias $ correspond à document.getElementById) :
$("hello-world-with-events").addEventListener("blink", function (event) { console.log("blinked element this many times: " + event.count); });
Lorsque vous exécutez ce code, vous voyez un message s'afficher toutes les 500 millisecondes dans la fenêtre JS Console de Visual Studio.
Pour prendre en charge ce comportement, trois modifications ont été apportées au contrôle :
Signalons ici que les appels émis vers dispatchEvent() fonctionnent uniquement si vous avez défini this.element dans le constructeur de votre contrôle. Les éléments internes de l'événement mix-in ont besoin de cet élément pour accéder à l'élément dans le DOM. Ce cas fait partie des situations que j'ai déjà évoquées ci-dessus, dans lesquelles un membre élément est requis sur l'objet de contrôle. Ainsi, les événements peuvent être regroupés au sein d'éléments parents dans la page, dans un modèle d'événement DOM de niveau 3.
Pour terminer la modification de notre contrôle, ajoutons une fonction publique doBlink() qui peut être appelée à tout moment pour forcer le clignotement.
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);
Il s'agit là d'une simple convention : nous pouvons en effet remplacer le nom de notre fonction _doBlink par doBlink.
Pour appeler la fonction doBlink() via JavaScript, vous devez disposer d'une référence à l'objet de votre contrôle. Si vous créez votre contrôle de façon impérative, vous disposez peut-être déjà d'une référence. Si vous utilisez un traitement déclaratif, vous pouvez accéder à l'objet de contrôle en utilisant une propriété winControl sur l'élément HTML de votre contrôle. En reprenant par exemple le même code qu'auparavant, vous pouvez accéder à l'objet de contrôle à l'aide du code suivant :
$("hello-world-with-events").winControl.doBlink();
Nous venons de passer en revue les aspects les plus courants liés à l'implémentation d'un contrôle :
J'espère que ce didacticiel vous permettra de mieux comprendre comment créer un contrôle JavaScript personnalisé relativement simple. Pour toute question sur la gestion de vos propres contrôles personnalisés, consultez le Centre de développement Windows et posez votre question dans les forums. Si vous développez en XAML, sachez que nous publierons prochainement un billet expliquant les mêmes procédures pour le développement de contrôles XAML.
Jordan Matthiesen Chef de projet, Microsoft Visual Studio