6. Guards и переходы
ISusRouteGuard — защита навигации
csharp
public interface ISusRouteGuard
{
bool CanEnter(SusRoute from, SusRoute to);
bool CanLeave(SusRoute from, SusRoute to);
}Глобальный guard (все переходы)
csharp
router.BeforeEach((from, to) =>
{
if (to.Record?.Config?.Meta?.ContainsKey("requiresAuth") == true
&& to.Record.Config.Meta["requiresAuth"] is true
&& !AuthService.IsLoggedIn)
{
router.Push("/login");
return false;
}
return true;
});Guard на маршрут
csharp
public class AdminGuard : ISusRouteGuard
{
public bool CanEnter(SusRoute from, SusRoute to) => User.IsAdmin;
public bool CanLeave(SusRoute from, SusRoute to) => true;
}
router.Register("/admin", typeof(AdminScreen), new SusRouteConfig
{
Guard = new AdminGuard(),
Meta = new() { ["requiresAuth"] = true, ["role"] = "admin" }
});BeforeResolve — перед созданием экрана
csharp
router.BeforeResolve((from, to) =>
{
if (to.FullPath == "/battle/0") return false; // invalid id
return true;
});Асинхронные guard'ы (BeforeEachAsync / BeforeResolveAsync)
Для проверок, которым нужен await (запрос к серверу, загрузка данных), доступны асинхронные guard'ы:
csharp
router.BeforeEachAsync(async (from, to) =>
{
var ok = await AuthService.CheckSessionAsync();
return ok;
});
router.BeforeResolveAsync(async (from, to) =>
{
return await DataService.PreloadAsync(to.FullPath);
});Порядок при PushAsync / ReplaceAsync:
BeforeEachAsync(все, последовательно,await)BeforeResolveAsync(все, последовательно,await)- синхронный конвейер (
BeforeLeave→BeforeEach→CanEnter→BeforeResolve→ создание экрана)
⚠️ Ограничение: синхронная навигация (
Push/Replace/Back/Forward) не запускает асинхронные guard'ы — их нельзяawaitить синхронно. Если асинхронные guard'ы зарегистрированы, но вызван синхронныйPush, они пропускаются (Editor/Development-сборки логируют предупреждение[GuardAudit]). Для маршрутов с асинхронными проверками используйтеPushAsync/ReplaceAsync.
SusRouteTransition — анимации переходов
API
csharp
public class SusRouteTransition
{
public float Duration { get; }
public static SusRouteTransition None();
public static SusRouteTransition Fade(float duration = 0.2f);
public static SusRouteTransition SlideLeft(float duration = 0.3f);
public static SusRouteTransition SlideRight(float duration = 0.3f);
public void PlayIn(VisualElement target);
public void PlayOut(VisualElement target);
}Реализация (на коде)
Анимации используют schedule.Execute плюс манипуляции style.opacity / style.translate:
csharp
public static SusRouteTransition Fade(float d = 0.2f) => new(
playIn: el => { /* opacity 0 → 1 over d seconds */ },
playOut: el => { /* opacity 1 → 0 over d seconds */ },
duration: d
);
public static SusRouteTransition SlideLeft(float d = 0.3f) => new(
playIn: el => { /* translate X: 100px → 0 over d seconds */ },
playOut: el => { /* translate X: 0 → -100px over d seconds */ },
duration: d
);Использование
csharp
new SusRouteConfig { Transition = SusRouteTransition.Fade(0.2f) }
new SusRouteConfig { Transition = SusRouteTransition.SlideLeft(0.3f) }
new SusRouteConfig { Transition = SusRouteTransition.SlideRight(0.3f) }
new SusRouteConfig { Transition = SusRouteTransition.None() }Анимации проигрываются в SusRouteView.OnRouteChanged: PlayOut на старом экране, PlayIn на новом.