Initiation Ă  Vue.js

Que se passerait-il si Monsieur Angular avait rencontré en cachette Madame Polymer?

Le concept du templating avec du “two-way data binding” d’Angular est intĂ©ressant, celui des filters aussi, mais finalement, on voit apparaĂźtre ceci aussi dans Polymer: polymer-filters, mais comme une dĂ©pendance externe ou directement dans Polymer en ce qui concerne le data binding mais avec une logique de dĂ©veloppement par composants. Je ne vous parle pas non plus des nombreuses directives fournies par Angular.

Le modĂšle par composants me plaĂźt fortement, j’ai donc une tendance Ă  faire pas mal de directives personnalisĂ©es lorsque je fais du Angular pour essayer de reproduire ce type de modĂšle, mais cela devient vite lourd et complexe si je compare Ă  Polymer. Puis entre les contrĂŽleurs, les factories, les providers, les services, les directives, 
 il y a de quoi virer chĂšvre.

Et finalement, passĂ© le cĂŽtĂ© magique du framework, on s’aperçoit rapidement que si on ne le maĂźtrise pas de A Ă  Z (et “il y a du monde”) on peut rapidement faire des erreurs de conception ou gĂ©nĂ©rer des effets de bord sans s’en apercevoir.

D’un autre cĂŽtĂ©, avec Polymer, je suis obligĂ© de me trimbaler une tonne de composants, fichiers javascript et autres choses avant d’avoir une plateforme de dĂ©veloppement opĂ©rationnelle. Mais pour le futur, je miserais plus sur Polymer qu’Angular.

Parfois, je rĂȘve de quelque chose d’aussi magique mais de plus simple, que je puisse prendre en main facilement, faire cohabiter sans heurts avec d’autres frameworks (j’aime bien le cĂŽtĂ© “spartiate” de Backbone, qui malheureusement ne possĂšde pas le cĂŽtĂ© magique du “two-way data binding”).

Et finalement, c’est comme si Angular et Polymer lors d’une soirĂ©e arrosĂ©e avaient eu une relation illĂ©gitime qui aurait donnĂ© naissance Ă  Vue.js, un petit framework qui apporte du templating “à la Mustache” avec un systĂšme de “two-way data binding”, mais aussi un modĂšle par composants (non obligatoire).

Le plus simple c’est de montrer des exemples de code. Donc allons-y!

Les views Vue, ou les vues Vue?

Pour installer Vue.js, vous pouvez aller le chercher sur le site http://vuejs.org/guide/installation.html ou sinon un simple bower install vue fera l’affaire.

Puis préparez votre page

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>demo</title>
</head>
<body>

<script src="js/bower_components/vue/dist/vue.min.js"></script>

<script>
  //foo
</script>

</body>
</html>

Dans mon exemple, j’ai deux listes de super hĂ©ros (des arrays de super hĂ©ros) que je veux afficher dans ma page Web:

<body>

<script src="js/bower_components/vue/dist/vue.min.js"></script>

<script>
  var Model = function (fields) {
    this.fields = fields
  }

  var xMen = [
    new Model({name: "Wolverine"}),
    new Model({name: "Colossus"}),
    new Model({name: "Cyclops"})
  ];

  var avengers = [
    new Model({name: "Iron Man"}),
    new Model({name: "Captain America"}),
    new Model({name: "Thor"})
  ];
</script>

</body>

Je souhaite donc les afficher dans 2 listes différentes de type <ul><li></li></ul>. Avec Vue.js les template ressemblent à des templates Mustache:

<body>

  <ul id="xmen-list">
    <li v-repeat="characters">
        {{fields.name}}
    </li>
  </ul>

  <ul id="avengers-list">
    <li v-repeat="characters">
        {{fields.name}}
    </li>
  </ul>

<script src="js/bower_components/vue/dist/vue.min.js"></script>

<script>
  var Model = function (fields) {
    this.fields = fields
  }

  var xMen = [
    new Model({name: "Wolverine"}),
    new Model({name: "Colossus"}),
    new Model({name: "Cyclops"})
  ];

  var avengers = [
    new Model({name: "Iron Man"}),
    new Model({name: "Captain America"}),
    new Model({name: "Thor"})
  ];
</script>

</body>

Donc, jusque lĂ , rien de dĂ©paysant (notamment pour les habituĂ©s d’Angular). Maintenant je veux lier mes “collections” de super hĂ©ros Ă  mes templates. Pour cela j’ai besoin de d’instancier des objet Vue de cette maniĂšre:

new Vue({
  el: "# xmen-list",
  data: {
    characters: [new Model({name: "Wolverine"}), new Model({name: "Colossus"})] 
  }
}

C’est trĂšs simple, comme j’ai 2 templates <ul id="xmen-list"> et <ul id="avengers-list">, je vais juste me crĂ©er une fonction Ă  laquelle je passerais en paramĂštre le sĂ©lecteur de l’élĂ©ment du DOM auquel je veux me raccrocher (dans mon cas ce seront des id) et la collection Ă  afficher. Et donc mon code va ressembler Ă  ceci:

<body>

  <ul id="xmen-list">
    <li v-repeat="characters">
        {{fields.name}}
    </li>
  </ul>

  <ul id="avengers-list">
    <li v-repeat="characters">
        {{fields.name}}
    </li>
  </ul>

<script src="js/bower_components/vue/dist/vue.min.js"></script>

<script>
  var Model = function (fields) {
    this.fields = fields
  }

  var xMen = [
    new Model({name: "Wolverine"}),
    new Model({name: "Colossus"}),
    new Model({name: "Cyclops"})
  ];

  var avengers = [
    new Model({name: "Iron Man"}),
    new Model({name: "Captain America"}),
    new Model({name: "Thor"})
  ];

  var getListView = function(selector, collection) {
    return new Vue({
      el: selector,
      data: {
        characters: collection
      }
    })
  }

  getListView('# xmen-list', xMen);
  getListView('# avengers-list', avengers);

</script>

</body>

On essaye

Ouvrez votre page dans un navigateur:

Ça fonctionne simplement. Maintenant, dans la console de votre navigateur, saisissez ceci:

var thor = avengers.filter(function(character){return character.fields.name == "Thor"})[0]
thor.fields.name = "THOR"

On va donc chercher l’avenger Thor pour changer son nom:

De la mĂȘme maniĂšre vous pouvez ajouter une X-Woman Ă  l’autre collection:

xMen.push(new Model({name:"Tornado"}))

Donc finalement, nous sommes arrivĂ©s Ă  mettre ceci en Ɠuvre assez simplement. Sachez cependant que Vue.js utilise des fonctionnalitĂ©s spĂ©cifiques Ă  ECMAScript 5 (Object.defineProperty pour Ă©viter le dirty checking), donc (Ă  moins d’utiliser un Polyfill), cela ne fonctionnera que sur des navigateurs rĂ©cents.

Mais ce qui est intĂ©ressant, c’est que Vue.js propose aussi un systĂšme de composants (et bien d’autres choses).

Les composants avec Vue.js

Plutît que de mettre 2 templates dans ma page html, j’aimerais juste pouvoir faire quelque chose comme ceci:

<div id="root">

  <my-list collection="xMen"></my-list>
  
  <my-list collection="avengers"></my-list>

</div>

Remarque: j’ai insĂ©rĂ© mes composants Ă  l’intĂ©rieur d’un div, car les composants Vue.js doivent ĂȘtre “raccrochĂ©s” Ă  une vue Vue.js, donc j’instancierais une vue “reliĂ©e” Ă  root.

Pour faire un composant avec Vue.js c’est tout simple, par exemple je veux un composant <my-title></my-title>, je le dĂ©finie de cette maniĂšre:

Vue.component("my-title",{
  template: "<h1>{{title}}</h1>",
  ready : function() { 
    console.log("Ready!"); 
  },
  data : function () {
    return {
      title: "Hello World"
    }
  }
});

et ensuite je pourrais l’utiliser directement dans mon code html.

Donc pour mes super hĂ©ros, j’ai fait une nouvelle page qui ressemble Ă  ceci:

<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>demo</title>
</head>
<body>

<div id="root">

  <my-list collection="xMen"></my-list>

  <my-list collection="avengers"></my-list>

</div>

<script src="js/bower_components/vue/dist/vue.min.js"></script>

<script>

  var Model = function (fields) {
    this.fields = fields
  }

  var collections = {
    xMen : [
      new Model({name: "Wolverine"}),
      new Model({name: "Colossus"}),
      new Model({name: "Cyclops"})
    ],
    avengers : [
      new Model({name: "Iron Man"}),
      new Model({name: "Captain America"}),
      new Model({name: "Thor"})
    ]
  }

  Vue.component("my-list",{
    paramAttributes: ['collection'], // permet d'utiliser des attributs <my-list collection="xMen"></my-list>
    template: [
      '<ul>',
      '   <li v-repeat="characters">',
      '       {{fields.name}}',
      '   </li>',
      '</ul>'
    ].join(''),
    ready : function() {
      this.$data = {
        characters:collections[this.collection] // modifier la propriété $data
      }
    },
    data : function () { // initialiser les données (facultatif)
      return {
        characters:[]
      }
    }
  });

  var DivView = new Vue({el:"# root"});
  //il faut qu'une vue existe pour que les composants y soient raccrochés

Sauvegardez, ouvrez dans le navigateur:

Donc, mĂȘme principe que tout Ă  l’heure, mais avec une logique composants.

Ce nouveau framework me plaĂźt Ă©normĂ©ment, il ne me reste plus qu’à le tester de façon un peu plus “sĂ©vĂšre”, mais, comme ça Ă  premiĂšre vue, je le trouve trĂšs trĂšs prometteur.

blog comments powered by Disqus

Related posts