Maison  >  Article  >  interface Web  >  Exemple de démarrage simple Backbone.js

Exemple de démarrage simple Backbone.js

小云云
小云云original
2018-01-15 10:28:532342parcourir

Backbone est simple et flexible, et peut être utilisé à la fois dans des applications JS riches et dans des sites Web d'entreprise. Comparé à la conception de React pour View et le flux de données unidirectionnel, Backbone incarne mieux l'idée de MVC, je vais donc écrire un. exemple d'introduction, les amis dans le besoin peuvent s'y référer, j'espère que cela pourra aider tout le monde.

J'ai écrit un article lorsque j'ai commencé à utiliser le framework front-end MVC en 2011. Knockout et Backbone étaient tous deux utilisés à cette époque, mais tous les projets ultérieurs ont utilisé Backbone, principalement parce qu'il est simple et flexible, que ce soit c'est un JS riche. Il peut être utilisé à la fois pour les applications et les sites Web d'entreprise. Par rapport à la conception de React pour View et le flux de données unidirectionnel, Backbone peut mieux incarner l'idée de MVC, j'ai donc écrit un exemple d'introduction, comme suit :

1 La structure est divisée en 4. sections, introduisant Modèle/Vue/Collection, pour obtenir des données à distance, les afficher dans le tableau et les modifier et supprimer
2. Il s'appelle "Exemple", donc le code est principalement le premier code de chaque section ; le code complet, vous pouvez le copier et le coller. Chaque morceau de code est écrit sur la base du morceau de code précédent, donc le nouveau contenu de chaque morceau de code ne dépassera pas 20 lignes (y compris les accolades
3). il n'y a pas de commentaires pour chaque ligne de code, mais le contenu important est écrit après des instructions spécifiques ;
4. L'environnement de développement est Chrome et l'API de github est utilisée, afin que Chrome puisse obtenir des données même dans le chemin local (chemin sous forme de fichier://).

0. Introduction

Presque tous les frameworks font deux choses : l'une est de vous aider à écrire du code au bon endroit ; l'autre est de vous aider à faire du sale boulot. Backbone implémente une structure de code MVC claire et résout le problème du modèle de données et du mappage des vues. Bien que tous les projets liés à JS puissent être utilisés, Backbone est particulièrement adapté aux scénarios dans lesquels une grande quantité de contenu de page (principalement HTML) doit être générée à l'aide de JS et où les utilisateurs ont de nombreuses interactions avec les éléments de page.

L'objet Backbone a 5 fonctions importantes, Modèle/Collection/Vue/Routeur/Historique. Le routeur et l'historique sont optimisés pour les applications Web. Il est recommandé de se familiariser d'abord avec les connaissances liées à pushState. Au stade d’entrée, vous ne pouvez comprendre que Modèle/Collection/Vue. Considérez le modèle comme le noyau, la collection comme une collection de modèles et la vue comme le reflet des modifications du modèle sur le front-end.

1. Modèle

Le modèle est le cœur de toutes les applications JS. De nombreux didacticiels Backbone aiment commencer par View. En fait, View n'a pas beaucoup de contenu et la compréhension de View n'a que peu d'importance. . Comprendre le modèle est plus important. Le code suivant implémente l'obtention d'informations essentielles à partir de l'API github et leur affichage sur la page :

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script>

<link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">
</head>
<body>
 <table id="js-id-gists" class="table">
  <thead><th>description</th><th>URL</th><th>created_at</th></thead>
  <tbody></tbody>
 </table>
 <script type="text/javascript">
 var Gist = Backbone.Model.extend({
  url: 'https://api.github.com/gists/public',
  parse: function (response) {
   return (response[0]);
  }
 }),
  gist = new Gist();

 gist.on('change', function (model) {
  var tbody = document.getElementById('js-id-gists').children[1],
   tr = document.getElementById(model.get('id'));
  if (!tr) {
   tr = document.createElement('tr');
   tr.setAttribute('id', model.get('id'));
  }
  tr.innerHTML = '<td>' + model.get('description') + '</td><td>' + model.get('url') + '</td><td>' + model.get('created_at') + '</td>';
  tbody.appendChild(tr);
 });
 gist.fetch();
 </script>
</body>
</html>

LINE4~8 : Chargez la bibliothèque JS à utiliser. Les requêtes Ajax et certaines fonctions View nécessitent le support de jQuery (ou la réécriture des fonctions ajax/View) ; le code de Backbone est basé sur Underscore (ou remplacé par Lo-Dash. bootstrap.css est chargé simplement parce que le style par défaut est trop moche...

LINE16~22 : Créez un modèle et instanciez-le. url est l'adresse de la source de données (interface API) et l'analyse est utilisée pour traiter les données renvoyées. Ce qui est en réalité renvoyé est un tableau, nous prenons ici le premier objet.

LINE24~33 : Événement de changement de liaison. Je n'ai pas encore utilisé View, je dois donc gérer le HTML moi-même. Ces 10 lignes de code utilisent principalement get (model.get), et d'autres fonctions seront implémentées à l'aide de View ultérieurement.

LINE34 : Exécuter la récupération. Obtenez les données de la télécommande et l'événement de changement sera déclenché une fois les données obtenues. Vous pouvez remplacer la méthode de synchronisation

Ouvrez la console Chrome, entrez l'essentiel, vous pouvez voir les attributs obtenus par le modèle :

Le modèle fournit des données et des données- logique associée. Les attributs affichés dans l'image ci-dessus sont des données. Les attributs fetch/parse/get/set dans le code fonctionnent tous sur les données. D'autres incluent escape/unset/clear/destroy. Vous pouvez approximativement comprendre son objectif à partir du nom de la fonction. Il existe également une fonction de validation très couramment utilisée, qui est utilisée pour la vérification des données lors des opérations de définition/sauvegarde. Un échec de la vérification déclenchera l'événement invalide :

/* 替换之前代码的JS部分(LINE16~34) */
 var Gist = Backbone.Model.extend({
  url: 'https://api.github.com/gists/public',
  parse: function (response) {
   return (response[0]);
  },
  defaults: {
   website: 'dmyz'
  },
  validate: function (attrs) {
   if (attrs.website == 'dmyz') {
    return 'Website Error';
   }
  }
 }),
  gist = new Gist();

 gist.on('invalid', function (model, error) {
  alert(error);
 });
 gist.on('change', function (model) {
  var tbody = document.getElementById('js-id-gists').children[1],
   tr = document.getElementById(model.get('id'));
  if (!tr) {
   tr = document.createElement('tr');
   tr.setAttribute('id', model.get('id'));
  }
  tr.innerHTML = '<td>'+ model.get('description') +'</td><td>'+ model.get('url') +'</td><td>'+ model.get('created_at') +'</td>';
  tbody.appendChild(tr);
 });
 gist.save();
Par rapport au code précédent, il y a 4 changements. :

LINE7~9 : Ajout des valeurs par défaut. S'il n'y a pas de site Web dans l'attribut (notez que la valeur du site Web n'est pas vide), la valeur du site Web sera définie sur dmyz.

LINE10~14 : Ajouter une fonction de validation. Lorsque la valeur du site Web est dmyz, l'événement invalide est déclenché.
LINE18~20 : Lier un événement non valide, erreur renvoyée par l'alerte.
LINE31 : Pas de récupération, enregistrez l'opération directement.

Comme il n'y a pas de récupération, les données ne seront pas affichées sur la page. Lorsque l'opération de sauvegarde est exécutée, la fonction de validation sera appelée si la vérification échoue, l'événement invalide sera déclenché et une alerte provoquera une erreur. Dans le même temps, l'opération de sauvegarde lancera également une requête PUT vers l'URL du modèle. L'API github ne traite pas PUT, une erreur 404 sera donc renvoyée.

Entrez gist.set('description', 'demo') dans la console et vous pourrez voir que les éléments de la page changeront également en conséquence. Exécutez gist.set('description', gist.previous('description')) pour restaurer la valeur précédente. Il s'agit du mappage entre le modèle et la vue. Je l'implémente toujours moi-même maintenant. J'utiliserai Backbone's View pour l'implémenter dans la section suivante.

2. View

Utilisez Backbone’s View pour réécrire les parties LINE24~33 du code précédent :

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script>

<link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">
</head>
<body>
 <table id="js-id-gists" class="table">
  <thead><th>description</th><th>URL</th><th>created_at</th><th></th></thead>
  <tbody></tbody>
 </table>
 <script type="text/javascript">
 var Gist = Backbone.Model.extend({
  url: 'https://api.github.com/gists/public',
  parse: function (response) {
   return response[0];
  }
 }),
  gist = new Gist();

 var GistRow = Backbone.View.extend({
  el: 'tbody',
  MODEL: gist,
  events: {
   'click a': 'replaceURL'
  },
  replaceURL: function () {
   this.MODEL.set('url', 'http://dmyz.org');
  },
  initialize: function () {
   this.listenTo(this.MODEL, 'change', this.render);
  },
  render: function () {
   var model = this.MODEL,
    tr = document.createElement('tr');
   tr.innerHTML = '<td>' + model.get('description') + '</td><td>' + model.get('url') + '</td><td>' + model.get('created_at') + '</td><td><a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" >®</a></td>';
   this.el.innerHTML = tr.outerHTML;
   return this;
  }
 });
 var tr = new GistRow();
 gist.fetch();
 </script>
</body>
</html>

LINE25: 所有的View都是基于DOM的,指定el会选择页面的元素,指定tagName会创建相应的DOM,如果都没有指定会是一个空的p。
LINE27~32: 绑定click事件到a标签,replaceURL函数会修改(set)url属性的值。
LINE33~35: View的初始化函数(initialize),监听change事件,当Model数据更新时触发render函数。
LINE36~42: render函数。主要是LINE41~42这两行,把生成的HTML代码写到this.el,返回this。
LINE44: 实例化GistRow,初始化函数(initialize)会被执行。

点击行末的a标签,页面显示的这条记录的URL会被修改成http://dmyz.org。

这个View名为GistRow,选择的却是tbody标签,这显然是不合理的。接下来更改JS代码,显示API返回的30条数据:

/* 替换之前代码的JS部分(LINE16~45) */
 var Gist = Backbone.Model.extend(),
  Gists = Backbone.Model.extend({
   url: 'https://api.github.com/gists/public',
   parse: function (response) {
    return response;
   }
  }),
  gists = new Gists();

 var GistRow = Backbone.View.extend({
  tagName: 'tr',
  render: function (object) {
   var model = new Gist(object);
   this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td></td>'
   return this;
  }
 });

 var GistsView = Backbone.View.extend({
  el: 'tbody',
  model: gists,
  initialize: function () {
   this.listenTo(this.model, 'change', this.render);
  },
  render: function () {
   var html = '';
   _.forEach(this.model.attributes, function (object) {
    var tr = new GistRow();
    html += tr.render(object).el.outerHTML;
   });
   this.el.innerHTML = html;
   return this;
  }
 });
 var gistsView = new GistsView();
 gists.fetch();

LINE2~9: 创建了两个Model(Gist和Gists),parse现在返回完整Array而不只是第一条。
LINE11~18: 创建一个tr。render方法会传一个Object来实例化一个Gist的Model,再从这个Model里get需要的值。
LINE26~34: 遍历Model中的所有属性。现在使用的是Model而不是Collection,所以遍历出的是Object。forEach是Underscore的函数。

Backbone的View更多的是组织代码的作用,它实际干的活很少。View的model属性在本节第一段代码用的是大写,表明只是一个名字,并不是说给View传一个Model它会替你完成什么,控制逻辑还是要自己写。还有View中经常会用到的template函数,也是要自己定义的,具体结合哪种模板引擎来用就看自己的需求了。

这段代码中的Gists比较难操作其中的每一个值,它其实应该是Gist的集合,这就是Backbone的Collection做的事了。

3. Collection

Collection是Model的集合,在这个Collection中的Model如果触发了某个事件,可以在Collection中接收到并做处理。第2节的代码用Collection实现:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/javascript" src="http://backbonejs.org/backbone-min.js"></script>

<link href="http://cdn.bootcss.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="stylesheet">
</head>
<body>
 <table id="js-id-gists" class="table">
  <thead><th>description</th><th>URL</th><th>created_at</th><th></th></thead>
  <tbody></tbody>
 </table>
 <script type="text/javascript">
 var Gist = Backbone.Model.extend(),
  Gists = Backbone.Collection.extend({
   model: Gist,
   url: 'https://api.github.com/gists/public',
   parse: function (response) {
    return response;
   }
  }),
  gists = new Gists();

 var GistRow = Backbone.View.extend({
  tagName: 'tr',
  render: function (model) {
   this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td></td>'
   return this;
  }
 });

 var GistsView = Backbone.View.extend({
  el: 'tbody',
  collection: gists,
  initialize: function () {
   this.listenTo(this.collection, 'reset', this.render);
  },
  render: function () {
   var html = '';
   _.forEach(this.collection.models, function (model) {
    var tr = new GistRow();
    html += tr.render(model).el.outerHTML;
   });
   this.el.innerHTML = html;
   return this;
  }
 });
 var gistsView = new GistsView();
 gists.fetch({reset: true});
 </script>
</body>
</html>

LINE17~23: 基本跟第2节的第2段代码一样。把Model改成Collection,指定Collection的Model,这样Collectio获得返回值会自动封装成Model的Array。
LINE38: Collection和Model不同,获取到数据也不会触发事件,所以绑定一个reset事件,在之后的fetch操作中传递{reset: true}。
LINE42~45: 从Collection从遍历Model,传给GistRow这个View,生成HTML。

Collection是Backbone里功能最多的函数(虽然其中很多是Underscore的),而且只要理解了Model和View的关系,使用Collection不会有任何障碍。给Collection绑定各种事件来实现丰富的交互功能了,以下这段JS代码会加入删除/编辑的操作,可以在JSBIN上查看源代码和执行结果。只是增加了事件,没有什么新内容,所以就不做说明了,附上JSBIN的演示地址:http://jsbin.com/jevisopo/1

/* 替换之前代码的JS部分(LINE16~51) */
 var Gist = Backbone.Model.extend(),
  Gists = Backbone.Collection.extend({
   model: Gist,
   url: 'https://api.github.com/gists/public',
   parse: function (response) {
    return response;
   }
  }),
  gists = new Gists();

 var GistRow = Backbone.View.extend({
  tagName: 'tr',
  render: function (model) {
   this.el.id = model.cid;
   this.el.innerHTML = '<td>' + model.get('description') + '</td><td>'+ model.get('url') + '</td><td>' + model.get('created_at') + '</td><td><a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="js-remove">X</a> <a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="js-edit">E</a> </td>'
   return this;
  }
 });

 var GistsView = Backbone.View.extend({
  el: 'tbody',
  collection: gists,
  events: {
   'click a.js-remove': function (e) {
    var cid = e.currentTarget.parentElement.parentElement.id;
    gists.get(cid).destroy();
    gists.remove(cid);
   },
   'click a.js-edit': 'editRow',
   'blur td[contenteditable]': 'saveRow'
  },
  editRow: function (e) {
   var tr = e.currentTarget.parentElement.parentElement,
    i = 0;

   while (i < 3) {
    tr.children[i].setAttribute('contenteditable', true);
    i++;
   }
  },
  saveRow: function (e) {
   var tr = e.currentTarget.parentElement,
    model = gists.get(tr.id);

   model.set({
    'description' : tr.children[0].innerText,
    'url': tr.children[1].innerText,
    'created_at': tr.children[2].innerText
   });
   model.save();
  },
  initialize: function () {
   var self = this;
   _.forEach(['reset', 'remove', 'range'], function (e) {
    self.listenTo(self.collection, e, self.render);
   });
  },
  render: function () {
   var html = '';
   _.forEach(this.collection.models, function (model) {
    var tr = new GistRow();
    html += tr.render(model).el.outerHTML;
   });
   this.el.innerHTML = html;
   return this;
  }
 });
 var gistsView = new GistsView();
 gists.fetch({reset: true});

Afterword

虽然是入门范例,但因为篇幅有限,有些基本语言特征和Backbone的功能不可能面面俱到,如果还看不懂肯定是我漏掉了需要解释的点,请(在Google之后)评论或是邮件告知。

Backbone不是jQuery插件,引入以后整个DOM立即实现增删改查了,也做不到KnockoutJS/AnglarJS那样,在DOM上做数据绑定就自动完成逻辑。它是将一些前端工作处理得更好更规范,如果学习前端MVC的目的是想轻松完成工作,Backbone可能不是最佳选择。如果有一个项目,100多行HTML和1000多行JS,JS主要都在操作页面DOM(如果讨厌+号连接HTML还可以搭配React/JSX来写),那就可以考虑用Backbone来重写了,它比其他庞大的MVC框架要容易掌握得多,作为入门学习也是非常不错的。

相关推荐:

使用Backbone.js创建一个增删改查表的实例代码

javascript - 关于backbone.js里的model.set和model.get

Backbone.js中的集合详解_其它

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn