Месяц назад Гордон Л. Хэмптон написал около двенадцати фреймворков JavaScript в пространстве MVC на стороне клиента . Его рейтинговые критерии отличались от моих. Что действительно выделяется, так это то, что мне нравится логика, не заставляющая шаблон HTML мигрировать в теги <script>. В зависимости от сложности приложения, мне нравится иметь возможность видеть приложение в браузере или DreamWeaver, когда среда не запущена . Это дает мне возможность оценить состав приложения. Это обращается к WYSIWYG склонности, которую я имею. Мне нравится, когда мои структуры пользовательского интерфейса создаются для удобства проектирования, если хотите.
У Адди Османи есть ряд реализаций приложения TODO на сайте github . Для композиционных целей это действительно определенное место в настоящее время. Используя их, я собираюсь изучить HTML и то, как приложение выглядит без JavaScript. Я проверил репозиторий Addy, затем рекурсивно удалил все файлы javascript перед загрузкой главной страницы каждого из них в браузер.
угловатый
В браузере:
В DreamWeaver:
Что мне нравится, так это то, что я вижу повторяющийся элемент в стиле шаблонов усов: {{todo.content}} . Что мне не нравится, так это то, что я не вижу сообщения «X item left (s) left», которые обновляются в реальном времени. Angular оставляет ваш шаблон HTML на месте — там, где он был бы, если бы с ним не было угловой логики. Вот список задач в коде (ng: repeat — это циклическая конструкция):
<div id="todos">
<ul id="todo-list">
<li class="todo" ng:class="'editing-' + todo.editing + ' done-' + todo.done" ng:repeat="todo in todos">
<div class="display">
<input class="check" type="checkbox" name="todo.done" / >
<div ng:click="editTodo(todo)" class="todo-content"> {{ todo.content }} </div>
<span class="todo-destroy" ng:click="removeTodo(todo)"></span>
</div>
<div class="edit">
<form ng:submit="finishEditing(todo)">
<input class="todo-input" my:focus="todo.editing" my:blur="finishEditing(todo)" name="todo.content" type="text">
</form>
</div>
</li>
</ul>
</div>
позвоночник
Отсутствует повторяющиеся ТОДО. Вместо этого на странице есть заполнитель <ul id = «todo-list»> </ ul> для Backbone, в который потом можно вставить дочерние элементы. Вот шаблон в каноническом Backbone (скрытый внутри тега <script>):
<!-- Templates --> <script type="text/template" id="item-template"> <div class="todo <%= done ? 'done' : '' %>"> <div class="display"> <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> /> <label class="todo-content"><%= content %></label> <span class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="<%= content %>" /> </div> </div> </script>
Там нет нг: повторить эквивалентный код в HTML , это сделано в JavaScript.
Нокаутировать
Я не уверен, что способ, которым приложение TODO было закодировано с помощью нокаута, является единственным способом, но строка, которая будет отображать отдельный элемент TODO из списка TODO, выглядит как <div class = «todo-content» data-bind = «text: content, event: {dblclick: edit}» style = «курсор: указатель;»> </ div>. Без прикрепленных фреймворков для этого DIV ничего не видно . Если я жестко закодирую TODO-CONTENT в этом DIV и перезагружаю, то это больше похоже на Angular:
Приятно видеть встроенный шаблонизатор, а не шаблон в теге <script>, таком как Angular:
<div id="todos"> <div data-bind="visible: todos().length"> <input id="check-all" class="check" type="checkbox" data-bind="checked: allCompleted" /> <label for="check-all">Mark all as complete</label> </div> <ul id="todo-list" data-bind="foreach: todos"> <li data-bind="css: { editing: editing }"> <div class="todo" data-bind="css: { done : done }"> <div class="display"> <input class="check" type="checkbox" data-bind="checked: done" /> <div class="todo-content" data-bind="text: content, event: { dblclick: edit }" style="cursor: pointer;"></div> <span class="todo-destroy" data-bind="click: $root.remove"></span> </div> <div class="edit"> <input class="todo-input" data-bind="value: content, valueUpdate: 'afterkeydown', enterKey: stopEditing, event: { blur: stopEditing }"/> </div> </div> </li> </ul> </div>
Knockback
Скриншот — как Backbone’s
Knockback — это очень прагматичное слияние лучших функций Backbone и Knockout. В отличие от многих сайтов, посвященных этим технологиям, сайт Knockback пытается мгновенно продать эту технологию разработчику. Как и Backbone, Knockback хранит шаблоны отдельно. Вот их список задач: <ul class = «список задач» data-bind = «template: {name: ‘item-template’, foreach: todo_list.todos}»> </ ul>. Вот шаблон для этого:
<script type="text/x-jquery-tmpl" id="item-template"> <li> <div class="todo" data-bind="css: {done: done, editing: edit_mode}"> <div class="display"> <input class="check" type="checkbox" data-bind="checked: done" /> <div class="todo-text" data-bind="text: text, dblclick: toggleEditMode"></div> <div class="todo-destroy" data-bind="click: destroyTodo"></div> </div> <div class="edit"> <input class="todo-input" type="text" data-bind="value: text, event: {keyup: onEnterEndEdit}" /> </div> </div> </li> </script>
Сломался
Скриншот — как Backbone’s
Логика шаблона находится в файлах JavaScript, которые мне действительно не нравятся:
todo.templates= { list: '<ul class="items">' + '{% for task in taskList %}' + genericTaskTemplate + '{% endfor %}' + '</ul>' ,view: genericTaskTemplate ,create: '' ,update: '<li class="item" data-app_label="{{ task.__class__._meta.appLabel }}" data-model="{{ task.__class__._meta.modelName }}" data-pk="{{ task.pk }}">'+ '<form action="#/task/update/{{ task.pk }}/">' + '<input type="text" name="title" value="{{ task.title }}" />' + '</form>' + '</li>' };
Сэмми
Скриншот — как Backbone’s
Логика шаблона находится в отдельном файле .template, который кажется ненужным, учитывая, что это просто расширенный формат HTML .
<h2 data-type="list" data-id="<%= list.id %>"></h2> <% $.each(todos, function(index, todo) { %> <li data-type="todo" data-id="<%= todo.id %>" class="<%= todo.done ? 'done' : '' %>"> <div class="todo"> <div class="display"> <input class="check" type="checkbox" <%= todo.done ? 'checked' : '' %>/> <span class="trashcan" data-type="todo" data-id="<%= todo.id %>"></span> <span contenteditable="true" data-type="todo" data-id="<%= todo.id %>" class="todo-item"><%= todo.name %></span> </div> </div> </li> <% }); %>
тлеющие угли
<script type="text/x-handlebars"> {{#view id="todos"}} {{#collection id="todo-list" contentBinding="Todos.todosController" tagName="ul" itemClassBinding="content.isDone"}} {{view Ember.Checkbox titleBinding="content.title" valueBinding="content.isDone"}} {{/collection}} {{/view}} </script>
Тебе уже следует знать, что мне действительно нравятся шаблоны Эмбер. С моей точки зрения, это последняя позиция!
ExtJs
Скриншот — как Backbone’s
Логика шаблона находится в файлах JavaScript. ExtJs не так уж и дополнен HTML — возможностями на стороне клиента MVC , как остальные. Это скорее отступление от HTML и реальность, построенная на его собственном DSL, который сам по себе может быть очень привлекательным. Я включил его только потому, что у Адди есть в его списке. В этом случае грамматика ExtJS показывает встроенный HTML в соответствующем списке раздела TODO:
Ext.define('Todo.view.TaskList' , { store: 'Tasks', loadMask: false, itemSelector: 'div.row', extend: 'Ext.view.View', alias : 'widget.taskList', tpl: Ext.create('Ext.XTemplate', '<tpl for=".">', '<div class="row">', '<input type="checkbox" {[values.checked ? "checked" : ""]} />', '<span class="{[values.checked ? "checked" : ""]}">{label}</span>', '</div>', '</tpl>', {compiled: true} ) });
Фидель
Скриншот — как Backbone’s
<script type="text/template" id="item-template"> <li class="todo {!= todo.done ? 'done' : '' !}" data-todoid="{!= todo.guid !}"> <div class="display"> <input class="check" type="checkbox" {!= todo.done ? 'checked="checked"' : '' !} /> <div class="todo-content">{!= todo.name !}</div> <span data-action="destroyTodo" class="todo-destroy"></span> </div> <div class="edit"> <input class="todo-input" type="text" value="" /> </div> </li> </script>
Как и в Backbone или в этом примере, в HTML отсутствует эквивалентный код ng: repeat . Вместо этого это делается в JavaScript.
JavaScriptMVC
Скриншот — как в Backbone’s. Вложение шаблона (внутри тегов <script>) выглядит мощно:
<script type='text/ejs' id='todosEJS'> <% for(var i =0; i < this.length ; i++){ %> <li <%= this[i]%>> <%= $.View('todoEJS',this[i] ) %> </li> <% } %> </script> <script type='text/ejs' id='todoEJS'> <input type='checkbox' name='complete' <%= this.complete ? "checked" : "" %>> <span class=''><%= (this.text || "empty todo ...")%></span> <span class='destroy'></span> </script>
JQuery с рулем
Скриншот — как в Backbone’s. Отдельный шаблон снова:
<script type="text/x-handlebars-template" id="todo-template"> {{#this}} <li {{#if done}}class="done"{{/if}} data-id="{{id}}"> <div class="view"> <input class="toggle" type="checkbox" {{#if done}}checked{{/if}}> <label>{{title}}</label> <a class="destroy"></a> </div> <input class="edit" type="text" value="{{title}}"> </li> {{/this}} </script>
корешок
Скриншот — как Backbone’s. Шаблон снова использует <script> снова, но встраивается в HTML, который его содержит. Циклы не входят в грамматику, поэтому они выполняются JavaScript при работе с шаблоном.
<div class="items"> <script type="text/html" id="task-template"> <div class="item {{if done}}done{{/if}}"> <div class="view" title="Double click to edit..."> <input type="checkbox" {{if done}}checked="checked"{{/if}}> <span>${name}</span> <a class="destroy"></a> </div> <form class="edit"> <input type="text" name="name" value="${name}"> </form> </div> </script> </div>
Библиотека YUI
Скриншот как Backbone’s. Как правило, шаблон находится в теге & lt; script> с зацикливанием в Javascript.
<script type="text/x-template" id="todo-item-template"> <div class="todo-view"> <input type="checkbox" class="todo-checkbox" {checked}> <span class="todo-content" tabindex="0">{text}</span> </div> <div class="todo-edit"> <input type="text" class="todo-input" value="{text}"> </div> <a href="#" class="todo-remove" title="Remove this task"> <span class="todo-remove-icon"></span> </a> </script>
Бэтмен
(добавлено 14 февраля)
TODO Бэтмена находится в его собственном Github Repo , а не в Addy (пока). Бэтмен использует CoffeeScript вместо JavaScript, что само по себе привлекательно. Вот скриншот:
Как и Knockout, связанное поле не отображается в режиме разработки. Точно так же отсутствует статистика количества предметов. Наконец, тег <a> для «delete» отсутствует a и поэтому не отображается как ссылка. Другие фреймворки использовали для этого причудливые изображения, так что, вероятно, то же самое и для них, но не видно в их демонстрациях. Я взломал эти вещи (жестко запрограммирован) и сделал еще один скриншот для вашего удовольствия:
Хорошая новость (для меня) заключается в том, что Бэтмен расширяет HTML, как Angular и Knockout.
Вывод.
Только Angular, Knockout и Batman позволяют мне видеть, что к чему в режиме дизайна, и видеть механизм зацикливания в расширенной грамматике HTML . Это противоположно одному из «хороших» критериев Гордона Л. Хэмптона.
Также интересно, что у одного из них есть покровительство Microsoft, а у другого — поддержка Google. Интересно, есть ли в будущем порт Dart «Dangular» от сотрудников Google ?
После мысли.
Реализация списка TODO в Angular могла бы быть еще лучше в режиме разработки, если бы он кодировал статистику следующим образом:
<div id="todo-stats"> <span class="todo-count" ng:show="hasTodos()"> {{statsCount()}} item{{statsPlural()}} left. </span> <span class="todo-clear" ng:show="hasFinishedTodos()"> <a ng:click="clearCompletedItems()"> Clear {{finishedTodos()}} completed item{{finsihedPlural()}} </a> </span> </div>
Вместо того, как сейчас:
<div id="todo-stats"> <span class="todo-count" ng:show="hasTodos()"> <ng:pluralize count="remainingTodos()" when="{'0' : 'No items left.', '1': '1 item left.', 'other' : '{} items left.' }"> </ng:pluralize> </span> <span class="todo-clear" ng:show="hasFinishedTodos()"> <a ng:click="clearCompletedItems()"> Clear <ng:pluralize count="finishedTodos()" when="{'1': '1 completed item', 'other' : '{} completed items' }"></ng:pluralize> </a> </span> </div>
We’d get a design mode view like so: