>웹 프론트엔드 >JS 튜토리얼 >backbone.js 간단한 시작하기 예제

backbone.js 간단한 시작하기 예제

小云云
小云云원래의
2018-01-15 10:28:532453검색

Backbone은 간단하고 유연하며 풍부한 JS 애플리케이션과 기업 웹 사이트 모두에서 사용할 수 있습니다. View 및 단방향 데이터 흐름에 대한 React의 디자인과 비교하여 Backbone은 MVC의 아이디어를 더 잘 구현할 수 있으므로 소개 예제를 작성합니다. 친구들이 참조할 수 있어야 합니다. 모든 사람에게 도움이 되기를 바랍니다.

2011년 처음 프론트엔드 MVC 프레임워크를 사용하기 시작했을 때 글을 썼습니다. 당시에는 Knockout과 Backbone을 모두 사용했지만 이후의 모든 프로젝트에서는 Backbone을 사용했는데, 주로 단순하고 유연하기 때문입니다. JS 애플리케이션이나 기업 웹사이트 모두 편리합니다. React의 View 설계와 단방향 데이터 흐름에 비해 Backbone은 MVC의 아이디어를 더 잘 구현할 수 있으므로 이에 대한 소개 예제를 다음과 같이 작성했습니다.

1 구조는 4개 섹션으로 나누어 Model을 소개합니다. /View/Collection. 데이터를 원격으로 수집하고 테이블에 표시한 후 수정하고 삭제합니다.
2. 코드는 각 섹션의 첫 번째 코드입니다. , 복사하여 붙여넣기하여 사용할 수 있습니다. 각 코드는 이전 코드 섹션에 작성되었으므로 각 코드 섹션의 새로운 내용은 20줄(중괄호 포함)을 초과하지 않습니다. 각 코드 줄에 대한 주석이 있지만 중요한 내용 뒤에 구체적인 지침이 작성됩니다.
4. 개발 환경은 Chrome이며, github의 API를 사용하므로 Chrome은 로컬 경로(파일 형식의 경로)에서도 데이터를 얻을 수 있습니다. /).

0. 소개

거의 모든 프레임워크는 두 가지 작업을 수행합니다. 하나는 올바른 위치에 코드를 작성하는 데 도움이 되고, 다른 하나는 지저분한 작업을 수행하는 데 도움이 됩니다. Backbone은 명확한 MVC 코드 구조를 구현하고 데이터 모델 및 뷰 매핑 문제를 해결합니다. JS 관련 프로젝트는 모두 사용할 수 있지만 JS를 사용하여 대량의 페이지 콘텐츠(주로 HTML)를 생성해야 하고 사용자가 페이지 요소와 상호 작용이 많은 시나리오에는 Backbone이 가장 적합합니다.

Backbone 객체에는 모델/컬렉션/뷰/라우터/히스토리의 5가지 중요한 기능이 있습니다. Router와 History는 웹 애플리케이션에 최적화되어 있으므로 pushState 관련 지식을 먼저 숙지하는 것이 좋습니다. 진입단계에서는 Model/Collection/View만 이해할 수 있습니다. Model을 핵심으로, Collection을 모델 모음으로, View를 프런트 엔드의 모델 변경 사항을 반영하는 것으로 생각하세요.

1. Model

Model은 모든 JS 애플리케이션의 핵심입니다. 실제로 View에는 내용이 많지 않으며 Model을 이해하는 것이 더 중요합니다. 다음 코드는 github API에서 요점 정보를 가져와서 페이지에 표시하는 것을 구현합니다.

<!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: 사용할 JS 라이브러리를 로드합니다. Ajax 요청 및 일부 View 함수에는 jQuery 지원이 필요합니다(또는 ajax/View 함수 다시 작성). Backbone의 코드는 Underscore를 기반으로 합니다(또는 Lo-Dash로 대체됨). bootstrap.css는 기본 스타일이 너무 못생겼기 때문에 로드됩니다...

LINE16~22: 모델을 생성하고 인스턴스화합니다. url은 데이터 소스(API 인터페이스)의 주소이고, 구문 분석은 반환된 데이터를 처리하는 데 사용됩니다. 실제로 반환되는 것은 배열입니다. 여기서는 첫 번째 개체를 가져옵니다.

LINE24~33: 바인드 변경 이벤트. 아직 View를 사용해본 적이 없어서 HTML을 직접 처리해야 합니다. 이 10줄의 코드는 주로 get(model.get)의 사용법이고, 다른 기능은 나중에 View를 사용하여 구현될 것입니다.

LINE34: 가져오기를 실행합니다. 리모컨에서 데이터를 가져오면 데이터를 가져온 후 변경 이벤트가 트리거됩니다. 동기화 방법을 재정의할 수 있습니다.

Chrome 콘솔을 열고 gist를 입력하면 모델에서 얻은 속성을 볼 수 있습니다.

모델은 데이터 및 데이터 관련 논리를 제공합니다. 위 그림의 속성 출력은 데이터입니다. 코드의 fetch/parse/get/set는 모두 데이터에 대해 작동합니다. 기타 기능에는 escape/unset/clear/destroy가 포함됩니다. 설정/저장 작업 중 데이터 확인에 사용되는 매우 일반적으로 사용되는 유효성 검사 기능도 있습니다. 확인에 실패하면 잘못된 이벤트가 발생합니다:

/* 替换之前代码的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();
이전 코드와 비교하여 4가지 변경 사항이 있습니다:

LINE7~9 : 기본값이 추가되었습니다. 속성에 웹 사이트가 없는 경우(웹 사이트 값이 비어 있지 않음) 웹 사이트 값은 dmyz로 설정됩니다.

LINE10~14: 유효성 검사 기능을 추가합니다. 웹사이트 값이 dmyz이면 잘못된 이벤트가 트리거됩니다.
LINE18~20: 잘못된 이벤트 바인딩, 경고에 의해 오류가 반환되었습니다.
LINE31: 가져오기가 없고 작업을 직접 저장합니다.

가져오기가 없기 때문에 페이지에 데이터가 표시되지 않습니다. 저장 작업이 실행되면 유효성 검사 함수가 호출됩니다. 확인에 실패하면 잘못된 이벤트가 트리거되고 오류 메시지가 표시됩니다. 동시에 저장 작업은 모델의 URL에 대한 PUT 요청도 시작합니다. github API는 PUT을 처리하지 않으므로 404 오류가 반환됩니다.

콘솔에 gist.set('description', 'demo')를 입력하면 그에 따라 페이지 요소도 변경되는 것을 확인할 수 있습니다. 이전 값을 복원하려면 gist.set('description', gist.previous('description')) 을 실행하십시오. 이것이 Model과 View 사이의 매핑입니다. 지금도 직접 구현하고 있으며 다음 섹션에서는 Backbone의 View를 사용하여 구현하겠습니다.

2. View

Backbone의 View를 사용하여 이전 코드의 LINE24~33 부분을 다시 작성합니다.

<!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中的集合详解_其它

위 내용은 backbone.js 간단한 시작하기 예제의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.