IronRouter
человек и пароход
Что будет в докладе
server-client. что выбрать?
layouts. разметка одна, страниц много
helpes. какие же удобные штуки
subscriptions. Без никуда или "капитан реактивность"
plugins. просто, юзабельно, охрененно
hooks. уровень погружения - 2
route controllers. глубже некуда
Основы
meteor add iron:router
<template name="Post">
<h1>Post: {{title}}</h1>
</template>
Router.route('/post/:_id', function () {
this.render('Post');
});
.html
.js
Несколько уровней абстракции:
Route - класс обработки конкрентного пути
RouterController - название говорит само за себя
Router - одно месте, через которое все работает (в хорошем смысле)
server-client
Router.route('/post/:_id', function () {
var params = this.params; // { _id: "5" }
var id = params._id; // "5"
}, {where: 'client'}); //default
Router.route('/post/:_id', function () {
var params = this.params; // { _id: "5" }
var id = params._id; // "5"
}, {where: 'server'});
Реактивность!
Router.route('/post/:_id', {
name: 'post.show',
path: '/post/:_id',
controller: 'CustomController',
template: 'Post',
layoutTemplate: 'ApplicationLayout',
yieldRegions: {
'MyAside': {to: 'aside'},
'MyFooter': {to: 'footer'}
},
subscriptions: function() {
this.subscribe('items');
this.subscribe('item', this.params._id).wait();
},
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
},
data: function () {
return Posts.findOne({_id: this.params._id});
},
onRun: function () {},
onRerun: function () {},
onBeforeAction: function () {},
onAfterAction: function () {},
onStop: function () {},
action: function () {
this.render();
}
});
Router.route(
'/webhooks/stripe',
{ where: 'server' }
)
.get(function () {
// GET /webhooks/stripe
})
.post(function () {
// POST /webhooks/stripe
})
.put(function () {
// PUT /webhooks/stripe
})
layouts
<template name="ApplicationLayout">
<header>
<h1>{{title}}</h1>
</header>
<aside>
{{> yield "aside"}}
</aside>
<article>
{{> yield}}
</article>
<footer>
{{> yield "footer"}}
</footer>
</template>
<template name="PostFooter">
Some post specific footer content.
</template>
<template name="PostAside">
Some post specific aside content.
</template>
Router.route('/post/:_id', function () {
this.layout('ApplicationLayout');
});
Router.configure({
layoutTemplate: 'ApplicationLayout'
});
Router.route('/post/:_id', function () {
this.layout('ApplicationLayout');
this.render('Post');
this.render('PostAside', {to: 'aside'});
this.render('PostFooter', {to: 'footer'});
});
helpers
<template name="Post">
<p>
{{post_content}}
</p>
{{#contentFor "aside"}}
Some post specific aside content.
{{/contentFor}}
{{#contentFor "footer"}}
Some post specific footer content.
{{/contentFor}}
</template>
<template name="Post">
<p>
{{post_content}}
</p>
{{> contentFor region="aside" template="PostAside"}}
{{> contentFor region="footer" template="PostFooter"}}
</template>
<template name="pathForExample">
{{#with posts}}
<a href="{{pathFor route='post.show'}}">
{{postName}}
</a>
{{/with}}
</template>
<template name="linkToExample">
{{#linkTo
route="post.show"
data=getData
query="q=s"
hash="hashFrag"
class="my-cls"
}}
<span style="color: orange;">
Post Show
</span>
{{/linkTo}}
</template>
subscriptions
Router.route('/post/:_id', function () {
this.wait(Meteor.subscribe('item', this.params._id));
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
});
Router.route('/post/:_id', {
loadingTemplate: 'loading',
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
},
action: function () {
this.render('myTemplate');
}
});
Router.route('/post/:_id', {
subscriptions: function() {
return Meteor.subscribe('item', this.params._id);
},
action: function () {
if (this.ready()) {
this.render();
} else {
this.render('Loading');
}
}
});
Session.set/Session.get, ReactiveVar
plugins
Iron.Router.plugins.loading = function (router, options) {
// this loading plugin just creates an onBeforeAction hook
router.onBeforeAction('loading', options);
};
Router.plugin('dataNotFound', {
notFoundTemplate: 'NotFound',
except: ['server.route']
// or only: ['routeOne', 'routeTwo']
});
hooks
Router.onBeforeAction(function () {
if (!Meteor.userId()) {
this.render('Login');
} else {
this.next();
}
});
Router.onBeforeAction(myAdminHookFunction, {
only: ['admin']
});
-
onRun
-
onRerun
-
onBeforeAction
-
onAfterAction
-
onStop
route controllers
PostController = RouteController.extend();
Router.route('/post/:_id', {
name: 'post.show',
controller: 'PostController'
});
PostController = RouteController.extend({
layoutTemplate: 'PostLayout',
template: 'Post',
waitOn: function () { return Meteor.subscribe('post', this.params._id); },
data: function () { return Posts.findOne({_id: this.params._id}) },
action: function () {this.render();}
});
Iron.RouteController
- Наследование: Можно наследоваться от этого класса. И создавать правила обработки для "группы" маршрутов.
- Организация кода: Можно разделять логику маршрутизации в разных контроллерах и использовать несколько файлов и не хранить все в router.js
Итого
- IronRouter - не часть платформы Meteor,но де-факто стал его сердцем
- Расширяемый, имеет несколько уровней абстракции и возможность подключения плагинов
- Легок в освоении, простая документация
- Его можно заменить (таких не встречал)
Напутствие:
Попробуйте все возможности и выберите свою стратегию работы с роутером.
Не плодите лапшу!
Спасибо!
Iron Router
By lawrentiy
Iron Router
- 1,985