Upload
2-
View
1.017
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
ИЛЬЯ ТАРАТУХИН
KNOCKOUT.js НА ПРИМЕРЕ
2ГИС-ОНЛАЙН
ДОКЛАДЧИК
Разрабатывал АСУ ТП
для горно-шахтного
оборудования
Спикер CodeFest
2012
API справочника
>5 млн API карт
>8 млн Карты 2ГИС
>3 млн
С 2011 года работаю в 2ГИС
WWW.2GIS.RU
WWW.2GIS.RU
Пользователь
2ГИС Онлайн
API Справочника
АРХИТЕКТУРА WEB-APP
АРХИТЕКТУРА CLIENT-SIDE APP
Пользователь
2ГИС Онлайн
API
Транспорта
API
пробок
API <Место для
вашего сервиса>
API
Справочник
API
Карт +1
WWW.2GIS.RU
DOM НА КЛИЕНТЕ
WWW.2GIS.RU
DOM НА КЛИЕНТЕ
var newDiv = document.createElement('div');
newDiv.className = 'my-class';
newDiv.id = 'my-id';
newDiv.innerHTML = 'Привет, мир!';
$('#container').appendChild(newDiv);
Привет, мир!
WWW.2GIS.RU
WHERE IS
ШАБЛОНИЗАТОРЫ
jQueryTemplate
Mustache
Underscore.js
Шаблонизатор резига
Pure
WWW.2GIS.RU WWW.2GIS.RU
СОБЫТИЯ
.firmShort
.firmFull #firmList
WWW.2GIS.RU WWW.2GIS.RU
СОБЫТИЯ
$("#firmTemplate").tmpl(someData)
.appendTo("#firmList");
$('.firmShort').live({
click: function() {
showFirmCard(this);
}
});
$('.firmFull').live({
click: function() {
hideFirmCard(this);
}
});
WWW.2GIS.RU WWW.2GIS.RU
СОБЫТИЯ
WWW.2GIS.RU WWW.2GIS.RU
KNOCKOUT
WWW.2GIS.RU WWW.2GIS.RU
ПОЧЕМУ KNOCKOUT?
Активно развивается
WWW.2GIS.RU WWW.2GIS.RU
• Активно развивается
ПОЧЕМУ KNOCKOUT?
Удобное разделение
логики и шаблонов
WWW.2GIS.RU WWW.2GIS.RU
• Активно развивается
• Удобное разделение логики и шаблонов
ПОЧЕМУ KNOCKOUT?
Функционален, есть
декларативные биндинги
WWW.2GIS.RU WWW.2GIS.RU
• Активно развивается
• Удобное разделение логики и шаблонов
• Функционален, есть декларативные
биндинги
ПОЧЕМУ KNOCKOUT?
Низкий порог вхождения
WWW.2GIS.RU WWW.2GIS.RU
MVVM
View Model
ViewModel
UI Logic Business Logic
Application Logic
WWW.2GIS.RU WWW.2GIS.RU
KNOCKOUT
WWW.2GIS.RU WWW.2GIS.RU
<div class="dg-search-result-header">
<span data-bind="text:
what_text"></span>,
<span data-bind="text:
where_text"></span></div>
KNOCKOUT
WWW.2GIS.RU WWW.2GIS.RU
function vm() {
this.what_text = ko.observable('');
}
ko.applyBindings(new vm());
...
vm.what_text(response.what);
<span data-bind="text: what_text"></span>
KO.OBSERVABLE
WWW.2GIS.RU WWW.2GIS.RU
МАССИВЫ
WWW.2GIS.RU WWW.2GIS.RU
response.result = [
{
firmName = 'Завод №1',
...
},
{
firmName = 'Завод №2';
...
}]
МАССИВЫ
WWW.2GIS.RU WWW.2GIS.RU
function vm () {
this.firms = ko.observableArray([]);
}
...
vm.firms(response.result);
<div data-bind="foreach: firms">
<div data-bind="text: firmName"></div>
</div>
KO.OBSERVABLE_ARRAY
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
<div class="dg-search-result-header">
<span data-bind="text:
what_text"></span>,
<span data-bind="text:
where_text"></span></div>
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
- Текст и стиль блока
- Control flow
- Работа с формами
- Шаблонизация
- <место для ваших идей>
WWW.2GIS.RU WWW.2GIS.RU
.firmShort
.firmFull
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
#firmList
<div id="firmList"
data-bind="foreach: firms">
<div class="firmShort"
data-bind="visible: !isVisible"></div>
<div class="firmFull"
data-bind="visible: isVisible"></div>
</div>
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
data-bind="visible: isVisible,
click: toggleVisibility"
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
data-bind="visible: isVisible,
click: toggleVisibility"
toggleVisibility = function() {
this.isVisible(!this.isVisible());}
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
ko.bindingHandlers['visible'] = { 'update': function (element, valueAccessor) {
var value =
ko.utils.unwrapObservable(valueAccessor());
var isCurrentlyVisible = !(element.style.display
== "none");
if (value && !isCurrentlyVisible)
element.style.display = ""; else if ((!value) && isCurrentlyVisible)
element.style.display = "none"; }};
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
ko.bindingHandlers['animateVisible'] = { 'update': function (element, valueAccessor) {
var value =
ko.utils.unwrapObservable(valueAccessor());
var isCurrentlyVisible = !(element.style.display
== "none");
var slideSpeed = 200;
if (value && !isCurrentlyVisible)
$(element).slideDown(slideSpeed,
callback); else if ((!value) && isCurrentlyVisible)
$(element).slideUp(slideSpeed,
callback); }};
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
data-bind="animateVisible: isVisible,
click: toggleVisibility"
toggleVisibility = function() {
this.isVisible(!this.isVisible());}
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
<script type="text/my-tpl" id="firm-tpl">
//firm template code</script>
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
<script type="text/my-tpl" id="catalog-tpl">
//some template code
<div data-bind="template: {
name: 'firm-tpl',
foreach: firms
}"></div>
</script>
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
BINDING-CONTEXT
vm
vm.firms[n]
WWW.2GIS.RU WWW.2GIS.RU
ПЕЧАТЬ
WWW.2GIS.RU WWW.2GIS.RU
<script type="text/my-tpl" id="print-tpl">
//some template code
<div data-bind="template: {
name: 'firm-tpl',
foreach: firms,
templateOptions: {
isPrint: 1
}
}"></div>
</script>
ПЕЧАТЬ
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
<div class="phone-number"
data-bind="visible:
$context.isPrint)">
<!-- Some code-->
</div>
WWW.2GIS.RU WWW.2GIS.RU
BINDINGS
<div class="contacts"
data-bind="template: {
name: 'firm-tpl',
data: $data,
templateOptions: {
isPrint: $context.isPrint
}
}">
<!-- Some code-->
</div>
WWW.2GIS.RU WWW.2GIS.RU
$context
$data
templateOptions
BINDING CONTEXT
WWW.2GIS.RU WWW.2GIS.RU
BINDING CONTEXT
$context
$data
templateOptions
• $parent
• $parentContext
• $root
• $index
• $element
WWW.2GIS.RU WWW.2GIS.RU
function initBalloon (options) {
map.createBalloon({
point: options.point;
content: options.template
}); }
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
function initBalloon (options) {
map.createBalloon({
point: options.point;
content: options.template
});
var container = $('#balloonContent');
ko.applyBindingsToNode(container ,
vm);}
BINDINGS
WWW.2GIS.RU WWW.2GIS.RU
КОГДА МНОГО "ЕСЛИ"
WWW.2GIS.RU WWW.2GIS.RU
this.showPreloader = ko.computed(function(){
return this.firmsLoad() &&
this.geoLoad();});
<span id="preloader"
data-bind="visible: showPreloader">
</span>
КОГДА МНОГО "ЕСЛИ"
WWW.2GIS.RU WWW.2GIS.RU
Не наблюдайте один computed
внутри другого
KO.COMPUTED
WWW.2GIS.RU WWW.2GIS.RU
1. Не наблюдайте один computed внутри другого
KO.COMPUTED
Не меняйте observable внутри
computed
WWW.2GIS.RU WWW.2GIS.RU
1. Не наблюдайте один computed внутри другого
2. Не меняйте observable внутри computed
KO.COMPUTED
Используйте computed только там,
где это необходимо
WWW.2GIS.RU WWW.2GIS.RU
PLUGINS
WWW.2GIS.RU WWW.2GIS.RU
PLUGINS
knockout.address
WWW.2GIS.RU WWW.2GIS.RU
PLUGINS
knockout.address
window.location vm.myObservable
ko.linkObservableToUrl(vm.history, 'history');
WWW.2GIS.RU WWW.2GIS.RU
https://github.com/SteveSanderson/knockout/wiki/Plugins
PLUGINS
WWW.2GIS.RU WWW.2GIS.RU
БОЛЬШИЕ ПРОЕКТЫ
107 22 18
Observable
Computed Observable
Array
WWW.2GIS.RU WWW.2GIS.RU
Functions
БОЛЬШИЕ ПРОЕКТЫ
200+ 107 22 18
WWW.2GIS.RU WWW.2GIS.RU
БОЛЬШИЕ ПРОЕКТЫ
200+ 107
22
18
13
WWW.2GIS.RU WWW.2GIS.RU
Namespace.ViewModelModules.<ourModule> = {
_observables: {
<ourObservable>: <defaultData>,
<ourComputed>:
function(){/*computedCode*/}
},
<someProperty>: 100500,
_initModule: function(){/*initCode*/},
<function>: function(){/*fBody*/}}
БОЛЬШИЕ ПРОЕКТЫ
WWW.2GIS.RU WWW.2GIS.RU
Namespace.ViewModelModules.<ourModule> = {
_observables: {
<ourObservable>: <defaultData>,
<ourComputed>:
function(){/*computedCode*/}
},
<someProperty>: 100500,
_initModule: function(){/*initCode*/},
<function>: function(){/*fBody*/}}
WWW.2GIS.RU
БОЛЬШИЕ ПРОЕКТЫ
150
WWW.2GIS.RU WWW.2GIS.RU
IDE
data-bind="
//очень много
//кода
//который выглядит
//как одна сплошная строка
"
WWW.2GIS.RU WWW.2GIS.RU
IDE
WWW.2GIS.RU WWW.2GIS.RU
WWW.2GIS.RU
IDE
WWW.2GIS.RU WWW.2GIS.RU
АНАЛОГИ
- AngularJS
- Backbone.js
- Ember.js
- ExtJS
- CorMVC
- AsanaLuna
- ...
WWW.2GIS.RU WWW.2GIS.RU
ВОПРОСЫ?
WWW.2GIS.RU WWW.2GIS.RU