Модуль basis.router позволяет отслеживать изменения location и задавать реакцию на эти изменения.
В настоящий момент модуль работает только со значением хеша адреса (location.hash). Поддержка History API планируется в будущих версиях.
Модуль отслеживает изменения location.hash, используя событие hashchanged, либо каждые 50ms, используя таймер, если событие не поддерживается браузером. При этом запоминается предущее известное значение для location.hash, и если между проверками произойдет несколько изменений, то "реакции" будут применены только к последнему значению. Если несколько изменений в итоге приводят к тому же значению, что было при предыдущей проверке, "реакций" применено не будет.
По умолчанию состояние location.hash не проверяется, и изменения не отслеживаются. Для того чтобы модуль начал отслеживать изменения, необходимо вызвать функцию basis.router.start(). Последующие вызовы этой функции не имеют эффекта, если изменения уже отслеживаются. Чтобы модуль прекратил отслеживать изменения, необходимо вызвать функцию basis.router.stop(). Когда изменения начинают отслеживаться, срабатывают уже добавленные "реакции", которые удовлетворяют текущему значению location.hash.
Реакция – это набор функций, которые задаются для определенного значения location.hash и выполняются при определенных условиях (событиях).
Чтобы добавить "реакцию" для некоторого значения location.hash, используется функция basis.router.add, а чтобы удалить – функция basis.router.remove. При этом функции basis.router.remove должны передаваться те же значения, что и для функции basis.router.add. Добавлять и удалять "реакции" можно в любой момент, независимо от того, отслеживаются ли изменения location.hash или нет. При этом если отслеживаются изменения и добавляемая "реакция" удовлетворяет условиям, то она тут же срабатывает.
Для функции basis.router.add (как и для basis.router.remove) задаются три параметра:
path – строка или регулярное выражение, описывающее значение location.hash;callbacks – набор функций, выполняемых при наступлении определенных событий;context – опциональный параметр, задающий контекст для функций (значение this).В качестве значения для path может быть задана строка или регулярное выражение.
Если задана строка, то она трансформируется в регулярное выражение по следующим правилам:
:\w+ (например, :foo) преобразуются в ([^/]+), что значит один и более символ, не являющийся слешем (/);*name (например, *rest) преобразуются в (.*?), то есть произвольное количество символов;(expr) → (?:expr)?);foo(/bar(/baz));| для описания альтернатив, например, foo(/bar|/baz);\) перед символом отменяет его специальное значение, при этом обратный слеш не попадает в результат; например, \:foo не будет преобразовано (будет /^:foo$/);\ нужно указывать пару, например, '\\:foo';^, а в конец $ – таким образом, регулярное значение применяется ко всему значению (ко всей строке).Преобразование подстрок вида
:foo,*barи(baz)аналогично поведениюBackbone.Router, но вBackboneне поддерживается вложенность скобок, вертикальная черта в скобках и экранирование символов.
Все значения в скобках в регулярном выражении становятся значениями параметров для match-функций "реакции". Другими словами, делается примерно следующее:
fn.apply(context, location.hash.match(/^foo\/(\d+)(\/bar|baz)$/).slice(1));
Рассмотрим несколько примеров. Допустим, для path задана строка 'books/:kind/page:page'. Такое значение сработает для #books/sci-fi/page5, а в match-функции будут переданы значения 'sci-fi' и '5'.
Путь 'foo/*rest' сработает для #foo/bar/baz, передав в функцию значение 'bar/baz'.
А путь 'docs/:section(/:subsection)' сработает для #docs/faq и для #docs/faq/installing, передав в функцию 'faq' в первом случае, а во втором – значения 'faq' и 'installing'.
Слеши в конце пути считаются частью пути, поэтому 'docs' и 'docs/' будут считаться разными путями. Чтобы указать реакцию для обоих случаев, необходимо использовать скобки, например 'docs(/)'.
В простых случаях описанных правил оказывается досточно. Но в сложных случаях или когда возможностей оказывается недостаточно, оказывается проще описать непосредственно регулярное выражение.
Для одного пути можно задавать произвольное количество "реакций". Например, разные модули могут добавлять свои реакции на один и тот же путь.
Для callbacks задается объект, где ключ – это название события, а значение – функция, которая должна быть выполнена при наступлении этого события. Доступны следующие события:
enter - значение location.hash начало удовлетворять path (похоже на mouseenter);match – срабатывает при каждом изменении location.hash, если значение удовлетворяет path;leave - значение location.hash перестало удовлетворять path (похоже на mouseleave).Все функции являются необязательными. match-функциям передаются параметры (подстроки из location.hash), если в path есть значения в скобках. Для enter- и leave-функций параметры не передаются.
При изменении location.hash проверяется, какие "реакции" удовлетворяют новому значению. После чего выполняются функции в следующем порядке:
leave-функции;enter-функции;location.hash, выполняются их match-функции.// location.hash = 'foo/123'
var router = basis.require('basis.router');
router.start();
router.add('foo/:id', {
enter: function(){ console.log('foo enter'); },
match: function(id){ console.log('foo match', id); },
leave: function(){ console.log('foo leave'); }
});
// > 'foo enter'
// > 'foo match' '123'
router.add('bar/:baz(/:etc(/))', {
enter: function(){ console.log('bar enter'); },
match: function(a, b){ console.log('bar match', a, b); },
leave: function(){ console.log('bar leave'); }
});
router.navigate('bar/456');
// > 'foo leave'
// > 'bar enter'
// > 'bar match' '456' undefined
router.navigate('bar/456/example');
// > 'bar match' '456' 'example'
router.navigate('bar/456/example/');
// > 'bar match' '456' 'example'
В качестве значения для callbacks может быть задана функция, а не объект, тогда считается, что задана match-функция.
var router = basis.require('basis.router');
router.add('foo', function(){
// ..
});
// эквивалентно
router.add('foo', {
match: function(){
// ..
}
});
Функция меняет текущее значение location.hash на переданное (value). При этом если передан параметр replace и его значение приводится к true, то предыдущее значение location.hash не сохраняется в истории (используется метод location.replace()).
Переданное значение никак не трансформируется и задается location.hash, как есть. При этом новое значение немедленно проверяется, и для него применяются "реакции".
var router = basis.require('basis.router');
router.navigate('foo');
console.log(location.hash);
// > '#foo'
router.navigate('bar');
console.log(location.hash);
// > '#bar'
history.back();
console.log(location.hash);
// > '#foo'
router.navigate('one'); // добавит #one в историю
router.navigate('two', true); // перезапишет #one на #two
console.log(location.hash);
// > '#two'
history.back();
console.log(location.hash);
// > '#foo'
Функция позволяет немедленно перепроверить значение location.hash, не дожидаясь события или срабатывания таймера.
Свойство debug с заданным значением true позволяет получать отладочную информацию об изменении location.hash и примененных реакциях.
// location.hash == '#foo'
var router = basis.require('basis.router');
router.debug = true;
router.start();
// > basis.router started
// > basis.router: hash changed to "foo"
// <no matches>
router.add('foo', function(){});
// > basis.router: add handler for route `asd3`
// Object {type: "match", path: "foo", cb: Object, route: Object, args: Array[0]}
До версии
1.4изменять значение флага необходимо иначе: либоbasis.router.debug = value, либоbasis.namespace('basis.router').debug = value.