FeRoutingManager.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using Bridge.Html5;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace FrontendRouting
  5. {
  6. public static class FeRoutingManager
  7. {
  8. public static event EventHandler Navigated;
  9. private static readonly Dictionary<string, FeRoutingView> Routes = new Dictionary<string, FeRoutingView>();
  10. private static FeRoutingView _currentView;
  11. private static string _basePath;
  12. private static FeRoutingView _pageNoFoundView = new DefaultPageNoFoundView();
  13. private static Node _parentNode = Window.Document.Body;
  14. public static FeRoutingView PageNoFoundView
  15. {
  16. get => _pageNoFoundView;
  17. set => _pageNoFoundView = value ?? throw new ArgumentNullException(nameof(value));
  18. }
  19. public static Node ParentNode
  20. {
  21. get => _parentNode;
  22. set
  23. {
  24. _currentView?.Leave();
  25. _parentNode = value ?? throw new ArgumentNullException(nameof(value));
  26. _currentView?.Enter(_parentNode);
  27. }
  28. }
  29. public static void Register(string path, FeRoutingView view)
  30. {
  31. if (false == path.StartsWith("/")) throw new ArgumentException($"{nameof(path)} must starts with /", nameof(path));
  32. if (Routes.ContainsKey(path)) throw new ArgumentException($"Route path `{path}' already registed", nameof(path));
  33. Routes.Add(path, view);
  34. }
  35. public static void UnRegister(string path)
  36. {
  37. Routes.Remove(path);
  38. }
  39. public static void Run(string basePath = "/")
  40. {
  41. if (null != _basePath) throw new InvalidOperationException("Already running");
  42. if (false == basePath.StartsWith("/")) throw new ArgumentException($"{nameof(basePath)} must starts with /", nameof(basePath));
  43. _basePath = basePath;
  44. Go(null);
  45. Window.AddEventListener(EventType.PopState, Window_PopState);
  46. }
  47. private static void Window_PopState(Event arg)
  48. {
  49. if (Go(null)) return;
  50. arg.PreventDefault();
  51. Window.History.Go(1);
  52. }
  53. public static bool Go(string path, bool replace = false)
  54. {
  55. if (null != _currentView) return _currentView.BeforeLeave(() => GoInternal(path, replace));
  56. return GoInternal(path, replace);
  57. }
  58. private static bool GoInternal(string path, bool replace)
  59. {
  60. if (null != path)
  61. {
  62. if (replace) Window.History.ReplaceState(null, null, path);
  63. else Window.History.PushState(null, null, path);
  64. }
  65. var routeKey = Window.Location.PathName;
  66. if (routeKey.StartsWith(_basePath)) routeKey = routeKey.Substring(_basePath.Length - 1);
  67. var targetView = Routes.TryGetValue(routeKey, out var controller)
  68. ? controller
  69. : PageNoFoundView;
  70. if (targetView.BeforeEnter(_currentView))
  71. {
  72. _currentView?.Leave();
  73. _currentView = targetView;
  74. _currentView.Enter(_parentNode);
  75. OnNavigated();
  76. return true;
  77. }
  78. return false;
  79. }
  80. private static void OnNavigated()
  81. {
  82. Navigated?.Invoke(null, EventArgs.Empty);
  83. }
  84. }
  85. }