13. Роутинг и навигация

Роутинг (Routing) и навигация — ключевые механизмы построения современных SAPUI5/Fiori приложений, позволяющие управлять переходами между экранами, состояниями и параметрами URL.

Основные понятия

  • Роутер (Router) — компонент, отвечающий за сопоставление URL и отображаемых представлений (View).
  • Route — правило, описывающее, какой View показывать при определённом URL.
  • Target — конкретный View или фрагмент, который будет отображён.
  • Pattern — шаблон URL, по которому определяется, какой маршрут активировать.

Зачем нужен роутинг?

  • Позволяет создавать SPA (Single Page Application) с "чистыми" URL.
  • Обеспечивает возможность закладок и прямых ссылок на определённые экраны.
  • Упрощает управление историей переходов (Back/Forward).
  • Позволяет передавать параметры между экранами.

Конфигурация роутинга (Freestyle)

Роутинг обычно настраивается в файле manifest.json:

"routing": {
  "config": {
    "routerClass": "sap.m.routing.Router",
    "viewType": "XML",
    "viewPath": "my.app.view",
    "controlId": "app",
    "controlAggregation": "pages",
    "bypassed": {
      "target": "notFound"
    },
    "async": true
  },
  "routes": [
    {
      "pattern": "",
      "name": "home",
      "target": "home"
    },
    {
      "pattern": "detail/{id}",
      "name": "detail",
      "target": "detail"
    }
  ],
  "targets": {
    "home": {
      "viewName": "Home",
      "viewLevel": 1
    },
    "detail": {
      "viewName": "Detail",
      "viewLevel": 2
    },
    "notFound": {
      "viewName": "NotFound"
    }
  }
}

Навигация между экранами (Freestyle)

Для перехода между экранами используется роутер:

this.getOwnerComponent().getRouter().navTo("detail", {
  id: 42
});
  • "detail" — имя маршрута.
  • { id: 42 } — параметры, которые попадут в URL и будут доступны в целевом контроллере.

Обработка параметров маршрута

В контроллере целевого View:

onInit: function() {
  this.getOwnerComponent().getRouter()
    .getRoute("detail")
    .attachPatternMatched(this._onObjectMatched, this);
},

_onObjectMatched: function(oEvent) {
  var sId = oEvent.getParameter("arguments").id;
  // Используйте sId для загрузки данных
}

Навигация назад

Для возврата на предыдущий экран:

onNavBack: function() {
  var oHistory = sap.ui.core.routing.History.getInstance();
  var sPreviousHash = oHistory.getPreviousHash();

  if (sPreviousHash !== undefined) {
    window.history.go(-1);
  } else {
    this.getOwnerComponent().getRouter().navTo("home", {}, true);
  }
}

Ленивая загрузка (Lazy Loading)

Для оптимизации производительности рекомендуется использовать асинхронную загрузку View ("async": true в конфиге роутинга).


Примеры роутинга и навигации в Fiori Elements

В Fiori Elements роутинг и навигация реализованы на уровне фреймворка и тесно связаны с OData и аннотациями. Обычно URL содержит binding context, отражающий ключевые поля сущности.

Пример URL для Object Page:

/webapp/index.html#/SalesOrderSet('500000001')

Пример конфигурации в manifest.json (Fiori Elements):

"routing": {
  "routes": [
    {
      "pattern": ":?query:",
      "name": "list",
      "target": "list"
    },
    {
      "pattern": "SalesOrderSet({key})",
      "name": "object",
      "target": "object"
    }
  ],
  "targets": {
    "list": {
      "type": "Component",
      "id": "list",
      "name": "sap.suite.ui.generic.template.ListReport"
    },
    "object": {
      "type": "Component",
      "id": "object",
      "name": "sap.suite.ui.generic.template.ObjectPage"
    }
  }
}

Навигация из ListReport в ObjectPage происходит автоматически при выборе строки, и URL содержит ключевые поля выбранной сущности.

Пример кастомной навигации в контроллере Extension:

onNavigateToObjectPage: function(oEvent) {
  var oContext = oEvent.getSource().getBindingContext();
  var sPath = oContext.getPath(); // например, "/SalesOrderSet('500000001')"
  this.getOwnerComponent().getRouter().navTo("object", {
    key: encodeURIComponent(sPath.match(/\('(.+)'\)/)[1])
  });
}

Best Practice: Использование binding context из OData в роутинге и в Freestyle-приложениях

Хорошей практикой является использование binding context из OData в качестве аргументов роутинга. Это позволяет:

  • Делать URL максимально прозрачными и отражающими бизнес-сущности (например, ключи объектов).
  • Обеспечивать прямую связь между отображаемыми данными и URL.
  • Упрощать закладки и обмен ссылками между пользователями.

Реализация:

  1. При навигации передавайте ключевые поля (или binding path) в параметры маршрута.
  2. При открытии страницы делайте bind страницы к этому контексту:
// Навигация
this.getOwnerComponent().getRouter().navTo("object", {
  key: oContext.getProperty("ID")
});

// В onInit целевого контроллера
onInit: function() {
  this.getOwnerComponent().getRouter()
    .getRoute("object")
    .attachPatternMatched(this._onObjectMatched, this);
},

_onObjectMatched: function(oEvent) {
  var sKey = oEvent.getParameter("arguments").key;
  var sPath = "/EntitySet('" + sKey + "')";
  this.getView().bindElement({
    path: sPath
  });
}

Преимущества:

  • В строке браузера отображаются те же ключи, что и в интерфейсе.
  • Легко реализовать deep linking и восстановление состояния.
  • Повышается прозрачность и предсказуемость навигации.

Советы и лучшие практики

  • Используйте осмысленные имена маршрутов и шаблоны URL.
  • Не перегружайте один View множеством маршрутов — лучше разбивать на отдельные экраны.
  • Для вложенной навигации (например, в Master-Detail) используйте viewLevel для анимаций и правильной истории переходов.
  • Обрабатывайте несуществующие маршруты через bypassed и отдельный NotFound View.
  • Для сложных сценариев используйте события роутера (attachRouteMatched, attachBypassed и др.).
  • В Fiori Elements используйте стандартные шаблоны и аннотации для навигации между сущностями.

Полезные ссылки