Skip to content

Latest commit

 

History

History
107 lines (79 loc) · 8.1 KB

File metadata and controls

107 lines (79 loc) · 8.1 KB

Философия работы noscript

В первую очередь, noscript - фреймворк для построение одностраничного положения с множеством виртуальных страниц. Другими словами, для легкого создания полноценного сайта, работающего исключительно в браузере. Исходя из этого, некоторые концепии отличаются от популярных mvc-фреймворков.

Рассмотрим на примере приложения todo, как работает noscript. Приложение имеет 3 страницы: дело (todo), список дел (todo-list), список списков дел (todo-lists).

Определяющими понятиями для страницы являются ее название и параметры (например, id списка дел или дела). Эти параметры можно составлять вручную или преобразовывать из адреса страницы.

Двухсторонним преобразователем адреса страницы в параметры является ns.router. Подробнее про него можно прочитать тут.

Теперь надо описать из каких видов будет состоять каждая страница. Для этого служит модуль ns.layout. Он сопоставляет название страницы (по сути, название layout) с деревом видов, которые должны быть на странице.

ns.layout('todo-lists', {
  'app': {
    'todo-lists': {}
  }
});

Таким образом мы описали, что на странице есть вид app, внутри которого есть todo-lists. К виду todo-lists привязан модель todo-lists.

Клеем между видами и layout является ns.Update. Это «обновлятор» страницы. Он умеет ходить по дереву видов, запрашивать им нужные модели и перерисовывать страницу.

Теперь опишем вторую страницу.

ns.layout('todo-list', {
  'app': {
    'todo-list': {}
  }
});

К виду todo-list привязана модель todo-list. У модели есть параметр lid (list id). Но данный пример будет работать неправильно при переключении список. Почему так происходит?

Во-первых, в отличии от многих фреймворков в noscript вид жестко привязывает себя к своему экземпляру модели при инициализации.

Как это происходит? У модели todo-list есть параметр lid. При создании экземпляра ей генерируется ключ, который однозначно идентифицирует экземпляр. noscript делает так, что не может быть двух экземпляров с одним ключом. Ключ выглядит следующим образом model=todo-list&list-id=1.

Параметры модели (если не указано другое) копируются в параметры вида. Вид тоже генерирует себе ключ view=todo-list&list-id=1. Таким образом, чтобы показать список дел с list-id=2 noscript должен создать другой вид с другим ключом.

Во-вторых, виды жестко привязывают список вложенных видов с ключами. В этом «виноваты» и сам вид и ns.Update. Когда ns.Update проходится по дереву, то всем видам передается layout и каждый вид создает себе своих детей. Это операция происходит единственный раз во время инициализации вида. Получается, что переключая параметры и, не меняя название страницы, ns.Update ничего не сделает, потому что каждый вид останется на месте и не изменится.

А почему бы не пересчитывать детей для каждого вида? Тогда бы все уже работало! Это хорошая идея и ее можно сделать, но у нее есть один большой недостаток. Допустим был один ребенок, а стало два. Вид не может понять куда надо вставить новые виды. А с учетом того, что вид имеет собственную разметку и детей он может располагать где угодно, проблема становится нерешаемой.

Это и есть одни из главных отличий noscript, ведь в большинстве других фреймворков вид всегда один и при изменении параметров у него заменятся модель, что приводит к перерисовке. А проблему излишних обновлений решают через data-binding или другие инструменты. В noscript же для переключения между двумя списками достаточно скрыть один вид и показать другой.

Но чтобы произошла эта магия, надо немного изменить layout.

ns.layout('todo-list', {
  'app': {
    'todo-list-box@': {
      'todo-list': {}
    }
  }
}); 

Как видно, мы добавили еще один вид todo-list-box@, но на самом деле видом он не является и декларировать его не надо. @ в конце названия означает, что здесь будет box. Box - это специальный модуль noscript, который может скрывать и показывать нужные виды внутри себя. По сути, это точка изменения страницы.

Как он работает? Допустим у нас есть страница с название todo-list и параметрами list-id=1. todo-list-box создат вид todo-list с ключом view=todo-list&list-id=1. При переходе на страницу с параметром list-id=1, box создаст вид с ключом view=todo-list&list-id=2. После этого он увидит, что у него уже есть видимый старый вид и скроет его. А вместо него покажет новый вид. У box может быть много внутренних видов и не обязательно, чтобы они все скрывались или показывались. Какие-то могут быть открыты постоянно и box будет сам следить за этим.

Теперь можно заметить, что переключение между списками дел работает, но переключится на список списков или дел нельзя. Чтобы это заработало нужно сам app тоже сделать box'ом. Получаются вот такие layout.

ns.layout('todo-lists', {
  'app@': {
    'todo-lists': {}
  }
});


ns.layout('todo-list', {
  'app@': {
    'todo-list': {}
  }
});


ns.layout('todo', {
  'app@': {
    'todo': {}
  }
});

Box app будет переключать нужные виды в зависимости от параметров и все будет работать правильно.