Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
> cd tempFolder && ijs template todoapp #logout x-pipe-signal='click: user.logout' > button > 'Sign out' '~[bind: date.getDate() ]'td > :datePicker {
р4 > 'test'
:dualbind value='date' getter='getDate' setter='setDate';
:customTag > button x-signal='click: clicked' > 'Click';
}
td > div > '~[bind:name]';td > $namerect dimension='0:0:100:100' color='red' {
line from='0:0' to='5:5' size=5;
}
~[name] и ~[bind: name]]), поэтому и синтаксиса специально для него нету. И из вашего примера, так будет через чур свободно, или?td > p > 'My name is $name'
// vs
td > p > 'My name is ~[name]'
Или есть у вас другие идеи?
= section :ImageObject extend :MediaObject # '= ' - объявление компонента
p ::name
image ::contentURL
body
p ?::author # '?' - узел будет создан только если свойство присутствует в источнике данных
data ?::datePublished
= section :ImageGallery extend :CollectionPage
header
hx ::name
p ?::description
image ?::image
body #
::primaryImageOfPage[ :ImageObject ] # свойство суб-компонент типа ImageObject
footer
::associatedMedia[ :ImageObject ] # превьюшки, суб-компоненты типа ImageObject
class ImageObject_controller extend MediaObject_controller {
constructor(el) {
super(el);
this.model = _.getModel(el); // _ - глобальная переменная фреймворка
this._el = _(el); // обёртка над Node элементом (в случае html backend)
}
openImage(imageObject = 0) {
if ( Number.isInteger( imageObject ) ) {
imageObject = this.model.associatedMedia[ imageObject ];
}
if ( !imageObject ) return;
this.model.primaryImageOfPage = imageObject; //тут вызывается setter у модели
}
events: {
"associatedMedia action": function(event) {
let {target, metaKey} = event; // деструкруризация let target = event.target, type = event.type
if ( !metaKey ) {
this.openImage(target);
}
else { // Нажали Ctrl + click - открыти картинку в новом окне
let model = _.getModel(el)
, url
;
if ( model && (url = model.url) ) {
_.globalRouter.openInNewWindow(url);
}
}
}
}
}
class ImageObject_model extend MediaObject_model {
constructor(dataView) {
super(dataView);
this.dataView = dataView;
}
get associatedMedia() {
return this.dataView.get("associatedMedia");
}
set associatedMedia(singleOrArray) {
if ( !_.validate("associatedMedia", singleOrArray, this.validation ) {
throw new ValidationError(_.validate.lastError);
}
if ( Array.isArray(singleOrArray) ) { // Если массив значению
return this.dataView.replace("associatedMedia", singleOrArray); // заменяем всю коллекцию
}
// Если один объект
return this.dataView.add("associatedMedia", singleOrArray); // то добавляем его вколлекцию
}
// ... остальные свойства
validation: { // Валидация
":scope": function() { // ":scope" ссылка на "всю" модель
// ...
// валидация всей модели
}
"associatedMedia": function(obj) {
return obj.contentURL && obj.name;
}
}
}
!!!
html
head
js 'script/something.js'
body.image-gallery :ImageGallery /images/get/92188?from=0&to=10 # /images/get/* ссылка на источник данных
# Устанавливаем css класс и текст по-умолчанию
.image-gallery__author ::author ? "Автор не указан"
h4 > 'Title'
:datePicker;
button > 'X'
p ::name — у вас также шаблон зависит от модели, а если имеется ввиду, что это данные из контроллера — тогда контроллер, это чистой воды Presenter — который в свою очередь получает данные из модели. (см. статью)"model.someAttr" лучше, чем model.get("someAttr");. Если вы получаете данные по ajax запросу, вам их не надо расширять до бэкбоновской модели — а напрямую передавать во View.div > '~[:get("username")]', что бы достать данные из модели — но биндинги на данный момент работать не будут таким образом. model.get('attrName') — это ужасный хак. Проперти должны оставаться ими, а не создаваться функции геттеры / сеттеры. Биндинг в маске это всего лишь плагин, который может привязаться к свойствам любой модели model.attrName. Но как уже сказал в статье, можно создать кастомный биндинг провайдер, который будет привязываться к этим функциям и слушать изменения. А такая запись div > '~[:get("username")]' — это не binding, а просто expression.происходит один раз на domReady— я же как раз и сравниваю этот «запуск» приложения — на сколько быстро angularjs сможет приложение зарендерить и создать биндинги — и не важно где происходит инициализация участка страницы — в domReady или после ответа сервера.
splice, чем 100 раз push — ну или просто сообщить маске, что нужно кешировать изменения — (lock model), а потом пакетом применить — (unlock model). В Backbone это именно модель— вы, думаю, понимаете, что любые данные — это модель. Эти данные / состояния можно обернуть или скрыть в классах / структурах. И эти «обертки» собственно и называются domain model. Маска может работать и с тем, и с другим.
input #device-type type=value > :dualbind value="age" {
:validate match="^[a-z]{2}-[\d]{4}$" message=" ... pattern: xx-1234"
}
input #device-type type=text {
:dualbind value="age" {
:validate match="^[a-z]{2}-[\d]{4}$" message=" ... pattern: xx-1234";
// ....
}
}
input #device-type type=text value="{{age}}"
{{age}}). Просто, понимаете, если будет много других параметров — changeEvent, signal listener, геттеры и сеттеры и прочее, то инлайн запись не подойдёт, через тэг тогда нужно будет.
MaskJS — HMV* фреймворк