DUMP-2013 Frontend - Knockoutjs на примере 2ГИС-Онлайн - Таратухин...
-
Upload
it-people -
Category
Technology
-
view
1.176 -
download
1
Transcript of DUMP-2013 Frontend - Knockoutjs на примере 2ГИС-Онлайн - Таратухин...
С 2011 года работаю в 2ГИС:
- API Справочника > 5млн- API Карт > 8млн- Карты 2ГИС > 3млн
Пользователь
2ГИС Онлайн
API Справочника
АРХИТЕКТУРА WEB-APP
WWW.2GIS.RU
АРХИТЕКТУРА 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.RUWWW.2GIS.RU
СОБЫТИЯ
.firmShort
.firmFull#firmList
WWW.2GIS.RUWWW.2GIS.RU
СОБЫТИЯ
$("#firmTemplate").tmpl(someData).appendTo("#firmList");
$('.firmShort').live({ click: function() { showFirmCard(this); } });
$('.firmFull').live({ click: function() { hideFirmCard(this); } });WWW.2GIS.RUWWW.2GIS.RU
СОБЫТИЯ
ПОЧЕМУ KNOCKOUT?
Активно развивается
WWW.2GIS.RUWWW.2GIS.RU
● Активно развивается
ПОЧЕМУ KNOCKOUT?
Удобное разделение логики и шаблонов
WWW.2GIS.RUWWW.2GIS.RU
● Активно развивается● Удобное разделение логики и шаблонов
ПОЧЕМУ KNOCKOUT?
Функционален, есть декларативные биндинги
WWW.2GIS.RUWWW.2GIS.RU
● Активно развивается● Удобное разделение логики и шаблонов● Функционален, есть декларативные
биндинги
ПОЧЕМУ KNOCKOUT?
Низкий порог вхождения
WWW.2GIS.RUWWW.2GIS.RU
MVVM
View Model
ViewModel
UI Logic Business Logic
Application Logic
WWW.2GIS.RUWWW.2GIS.RU
KNOCKOUT
WWW.2GIS.RUWWW.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.RUWWW.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.RUWWW.2GIS.RU
МАССИВЫ
WWW.2GIS.RUWWW.2GIS.RU
response.result = [ { firmName = 'Театр №1', ... }, { firmName = 'Театр №2'; ... }]
МАССИВЫ
WWW.2GIS.RUWWW.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.RUWWW.2GIS.RU
BINDINGS
<div class="dg-search-result-header"> <span data-bind="text: what_text"></span>, <span data-bind="text: where_text"></span></div>
BINDINGS
WWW.2GIS.RUWWW.2GIS.RU
BINDINGS
— Текст и стиль блока
— Control flow
— Работа с формами
— Шаблонизация
— <место для ваших идей>
WWW.2GIS.RUWWW.2GIS.RU
.firmShort
.firmFull#firmList
WWW.2GIS.RUWWW.2GIS.RU
BINDINGS
<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.RUWWW.2GIS.RU
data-bind="visible: isVisible,click: toggleVisibility"
BINDINGS
WWW.2GIS.RUWWW.2GIS.RU
data-bind="visible: isVisible,click: toggleVisibility"
toggleVisibility = function() { this.isVisible(!this.isVisible());}
BINDINGS
WWW.2GIS.RUWWW.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.RUWWW.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.RUWWW.2GIS.RU
data-bind="animateVisible: isVisible,click: toggleVisibility"
toggleVisibility = function() { this.isVisible(!this.isVisible());}
BINDINGS
WWW.2GIS.RUWWW.2GIS.RU
<script type="text/my-tpl" id="firm-tpl"> //firm template code</script>
BINDINGS
WWW.2GIS.RUWWW.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.RUWWW.2GIS.RU
BINDINGS
BINDING-CONTEXT
vm
vm.firms[n]
WWW.2GIS.RUWWW.2GIS.RU
ПЕЧАТЬ
WWW.2GIS.RUWWW.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.RUWWW.2GIS.RU
BINDINGS
<div class="phone-number" data-bind="visible: $context.isPrint)"> <!-- Some code--></div>
WWW.2GIS.RUWWW.2GIS.RU
BINDINGS
<div class="contacts" data-bind="template: { name: 'firm-tpl', data: $data, templateOptions: { isPrint: $context.isPrint } }"> <!-- Some code--></div>
WWW.2GIS.RUWWW.2GIS.RU
$context
$data
templateOptions
BINDING CONTEXT
WWW.2GIS.RUWWW.2GIS.RU
BINDING CONTEXT
● $parent● $parentContext● $root● $index● $element
WWW.2GIS.RUWWW.2GIS.RU
$context
$data
templateOptions
function initBalloon (options) { map.createBalloon({ point: options.point; content: options.template }); }
BINDINGS
WWW.2GIS.RUWWW.2GIS.RU
function initBalloon (options) { map.createBalloon({ point: options.point; content: options.template });
var container = $('#balloonContent'); ko.applyBindingsToNode(container , vm);}
BINDINGS
WWW.2GIS.RUWWW.2GIS.RU
КОГДА МНОГО "ЕСЛИ"
WWW.2GIS.RUWWW.2GIS.RU
this.showPreloader = ko.computed(function(){ return this.firmsLoad() && this.geoLoad();});
<span id="preloader" data-bind="visible: showPreloader"></span>
КОГДА МНОГО "ЕСЛИ"
WWW.2GIS.RUWWW.2GIS.RU
Не наблюдайте один computed внутри другого
KO.COMPUTED
WWW.2GIS.RUWWW.2GIS.RU
WWW.2GIS.RU
1. Не наблюдайте один computed внутри другого
KO.COMPUTED
Не меняйте observable внутри computed
WWW.2GIS.RUWWW.2GIS.RUWWW.2GIS.RU
1. Не наблюдайте один computed внутри другого2. Не меняйте observable внутри computed
KO.COMPUTED
Используйте computed только там, где это необходимо
WWW.2GIS.RUWWW.2GIS.RU
PLUGINS
PLUGINS
knockout.address
WWW.2GIS.RUWWW.2GIS.RU
PLUGINS
window.location vm.myObservable
ko.linkObservableToUrl(vm.history, 'history');
WWW.2GIS.RUWWW.2GIS.RU
knockout.address
PLUGINS
WWW.2GIS.RUWWW.2GIS.RU
$('#firmFull').dataBind({ animateVisible: isVisible, click: toggleVisibility});
https://gist.github.com/joelnet/1006808
PLUGINS
WWW.2GIS.RUWWW.2GIS.RU
Unobtrusive Knockout support library for jQuery
Joel Thoms
https://github.com/SteveSanderson/knockout/wiki/Plugins
PLUGINS
WWW.2GIS.RUWWW.2GIS.RU
БОЛЬШИЕ ПРОЕКТЫ
107 22 18
Observable Computed ObservableArray
WWW.2GIS.RUWWW.2GIS.RU
Functions
БОЛЬШИЕ ПРОЕКТЫ
200+ 107 22 18
WWW.2GIS.RUWWW.2GIS.RU
БОЛЬШИЕ ПРОЕКТЫ
18
WWW.2GIS.RUWWW.2GIS.RU
107200+13 22
Namespace.ViewModelModules.<ourModule> = { _observables: { <ourObservable>: <defaultData>, <ourComputed>: function(){/*computedCode*/} }, <someProperty>: 100500, _initModule: function(){/*initCode*/}, <function>: function(){/*fBody*/}}
БОЛЬШИЕ ПРОЕКТЫ
WWW.2GIS.RUWWW.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.RUWWW.2GIS.RU
https://github.com/2gis/dgKoModulizer
dgKoModulizer
WWW.2GIS.RUWWW.2GIS.RU
IDE
data-bind=" //очень много //кода //который выглядит //как одна сплошная строка"
WWW.2GIS.RUWWW.2GIS.RU
IDE
WWW.2GIS.RUWWW.2GIS.RU
IDE
WWW.2GIS.RUWWW.2GIS.RU
ПРОИЗВОДИТЕЛЬНОСТЬ
WWW.2GIS.RUWWW.2GIS.RU
DOM.Build()
АНАЛОГИ
— AngularJS— Backbone.js— Ember.js— ExtJS�— CorMVC— AsanaLuna— ...
WWW.2GIS.RUWWW.2GIS.RU
Илья Таратухин@darklifa