Tutorial: ns.layout

ns.layout

Раскладка страницы (ns.Layout)

Раскладка служит для декларативного описания структуры видов на странице. При определении раскладки указывается её id и декларация.

    ns.layout.define('main', {
        app: {
            view1: true,
            view2: {
                view21: true
            }
        }
    });

В примере создаётся раскладка страницы, состоящей из четырёх видов. Корневой вид app содержит в себе view1 и view2, а view2 содержит в себе view21.

Каждый узел декларации соответствует виду. Ключ указывает на класс вида, в значении содержится декларация вложенных видов.

Способы описания структуры видов

    ns.layout.define('main', {
        app: {

            // Для описания вида без вложенностей значение устанавливается в true
            view1: true,

            // Для описания одного вложенного вида в значении указывается его класс
            view2: 'view21',

            // Для описания статической структуры видов используется объект
            view3: {
                view31: true,
                view32: 'view321'
            },
            // Для описания динамической структуры видов узел объяляется боксом,
            // а вложенность задаётся функцией.
            // В params приходят параметры страницы.
            // Функция может вернуть любой из выше перечисленных форматов декларации
            // видов, или falsy, чтобы отменить добавление вида в страницу.
            view4@: function(params) {
                if (params.value1) {
                    return null;
                }
                if (params.value2) {
                    return 'view41';
                }
                if (params.value3) {
                    return {
                        'view42': {
                            'view421': true;
                        }
                    };
                }
            }
        }
    });

Кроме описания структуры видов раскладка так же позволяет декларировать специальные атрибуты видов.

Бокс

Бокс - это специальный вид-контейнер. Он не имеет собственного html-содержимого и представлен в DOM только одним узлом, содержащим непосредственно в себе все вложенности. Бокс позволяет решать следующие задачи.

Кеширование экземпляров вида

    ns.layout.define('main', {
        app: {
            box@: 'view1'
        }
    });

В примере box будет содержать один вложенный вид view1. Если view1 зависит от параметров, то при изменении параметров предыдущие html-узлы будут скрываться, но оставаться в DOM-дереве, а новые - добавляться в box и показываться. При возврате к одному из предыдущих наборов параметров будет показан ранее сгенерированный соответствующий ему html-узел.

Создание динамической раскладки

    ns.layout.define('main', {
        app: {
            view1: true,
            view2@: function(params) {
                if (params.value1) {
                    return null;
                }
                if (params.value2) {
                    return 'view41';
                }
                if (params.value3) {
                    return {
                        'view42': 'view421',
                        'view43': 'view431'
                    };
                }
            }
        }
    });

В примере вид в зависимости от параметров может отсутствовать, содержать единственный вид view41, или содержать view42 и view43, содержащие в свою очередь соответственно view421 и view431. Для создания такой структуры view2 обязательно должен быть боксом. Обычный view, содержащий вложенные виды, при их исчезновении после обновления может работать некорректно.

Асинхронные виды

Асинхронный вид позволяет на время загрузки его моделей рисовать его в виде заглушки. Updater запросит модели асинхронных видов отдельными запросами и отрисует страницу до получения этих данных. Загрузив модели, Updater сделает повторный проход только по асинхронным видам и обновит их.

    ns.layout.define('main', {
        app: {
            viewLight: true,
            viewHard&: true
        }
    });
    ns.View.define('viewLight', {
        models: ['modelLight']
    })
    ns.View.define('viewHard', {
        models: ['modelHard']
    })
    match .view[id="viewLight"] ns-view {
        // основное html-содержимое вида viewLight
    }


    match .view[id="viewHard"] ns-view-async {
        // html-содержимое заглушки для вида viewHard
    }
    match .view[id="viewHard"] ns-view {
        // основное html-содержимое вида viewHard
    }

Предположим, что modelLight запросить легко, а запрос modelHard требует заметного времени. При обновлении Updater запросит модели отдельно: сначала modelLight, а затем modelHard. Получив данные для modelLight, Updater отрисует страницу. Вид viewHard при этом отрисуется в виде заглушки (с использованием шаблона ns-view-async). После получения данных для modelHard Updater сделает ещё один такт обновления и вместо заглушки отрисует основное содержимое viewHard.

Наследование

Один layout может наследовать от другого. Наследование реализуется следующим образом

// объявляет общий layout для всех страниц
ns.layout.define('common', {
    'app': {
        // каждая страница в проекте состоит из шапки, левой колонки и правой колонки
        'header-box@': {},
        'left-box@': {},
        'right-box@': {},
    }
});

// страница 1
// обратите внимание, что header-box@ не доопределяелся и берется как есть из common
ns.layout.define('posts', {
    // чтобы заново не описывать структуру, путь до видов указывается через пробел
    'app left-box@': {
        'navigation': {}
    },
    'app right-box@': {
        'posts': {}
    }
// последним параметром для ns.layout.define указывает, что layout наследуется от common
}, 'common');

// страница 2
ns.layout.define('profile', {
    'app header-box@': {
        'user-header': {}
    },
    'app left-box@': {
        'navigation': {}
    },
    'app right-box@': {
        'profile': {}
    }
}, 'common');
comments powered by Disqus