Обработка путей
m.route
и m.request
используют концепцию путей (path). Пути используются для генерации URL-адресов для навигации или получения данных.
Типы путей
Существует два основных типа путей: необработанные (raw paths) и параметризованные (parameterized paths).
- Необработанные пути - это строки, которые используются непосредственно в качестве URL-адресов. Никакие подстановки или разделения не производятся. Строка просто нормализуется, а все параметры добавляются в конец.
- Параметризованные пути позволяют вставлять значения в URL-адреса. По умолчанию значения экранируются для удобства и защиты от URL-инъекций.
Для m.request
это может быть практически любой URL-адрес, но для маршрутов это должны быть только абсолютные URL-пути без схемы или домена.
Параметры пути
Параметры пути достаточно просты. Они бывают двух видов:
:foo
- Вставляет значениеparams.foo
в URL-адрес, предварительно экранируя его.:foo...
- Вставляет необработанное значениеparams.foo
в URL-адрес, без экранирования.
Объект params
- это объект, передаваемый в m.route.set(path, params)
и m.request({url, params})
.
При определении маршрутов через m.route(root, defaultRoute, routes)
вы можете использовать эти параметры для извлечения значений из URL-адреса. Они работают аналогично генерации путей, но в обратном направлении.
// Редактирование одного элемента
m.route(document.body, '/edit/1', {
'/edit/:id': {
view: function () {
return [m(Menu), m('h1', 'Редактирование пользователя ' + m.route.param('id'))];
},
},
});
// Редактирование элемента, идентифицированного по пути
m.route(document.body, '/edit/pictures/image.jpg', {
'/edit/:file...': {
view: function () {
return [m(Menu), m('h1', 'Редактирование файла ' + m.route.param('file'))];
},
},
});
В первом примере, если вы перейдете к маршруту по умолчанию, m.route.param("id")
вернет "1"
, а m.route.param("file")
во втором примере вернет pictures/image.jpg
.
Параметры пути могут быть разделены символами /
, -
или .
. Это позволяет создавать динамические сегменты пути, которые более гибкие, чем просто имя пути. Например, вы можете сопоставить маршруты, такие как "/edit/:name.:ext"
для редактирования на основе расширения файла, или /:lang-:region/view
для локализованного маршрута.
Параметры пути ведут себя "жадно": для объявленного маршрута "/edit/:name.:ext"
, если вы перейдете к /edit/file.test.png
, извлеченные параметры будут {name: "file.test", ext: "png"}
, а не {name: "file", ext: "test.png"}
. Аналогично, для "/route/:path.../view/:child..."
, если вы перейдете к /route/foo/view/bar/view/baz
, извлеченные параметры будут {path: "foo/view/bar", child: "baz"}
.
Нормализация параметров
Параметры пути, подставленные в URL-адрес, исключаются из строки запроса для удобства и улучшения читаемости URL-адреса. Например, следующий код отправит серверный запрос GET /api/user/1/connections?sort=name-asc
, опуская дубликат id=1
в строке URL.
m.request({
url: 'https://example.com/api/user/:userID/connections',
params: {
userID: 1,
sort: 'name-asc',
},
});
Вы также можете указать параметры явно в строке запроса, как в этом примере, который эквивалентен приведенному выше:
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
},
});
И, конечно, вы можете смешивать и сочетать. Следующий код отправит запрос GET /api/user/1/connections?sort=name-asc&first=10
.
m.request({
url: 'https://example.com/api/user/:userID/connections?sort=name-asc',
params: {
userID: 1,
first: 10,
},
});
Это также относится к сопоставлению маршрутов: можно сопоставлять маршруты с явными параметрами в строке запроса. Для удобства, сопоставленный параметр сохраняется, и к нему можно получить доступ через параметры vnode или через m.route.param
. Обратите внимание, что, хотя это возможно, это обычно не рекомендуется, поскольку для страниц следует использовать пути. Это может быть полезно, если требуется отобразить немного отличающийся вид для определенного типа файла, но логически это все еще параметр запроса, а не отдельная страница.
// Примечание: это обычно *не* рекомендуется - для объявлений маршрутов следует использовать пути, а не строки запроса.
m.route(document.body, '/edit/1', {
'/edit?type=image': {
view: function () {
return [m(Menu), m('h1', 'Редактирование фотографии')];
},
},
'/edit': {
view: function () {
return [m(Menu), m('h1', 'Редактирование ' + m.route.param('type'))];
},
},
});
Параметры запроса обрабатываются неявно — вам не нужно объявлять их, чтобы их принять. Вы можете сопоставить на основе существующего значения, как в "/edit?type=image"
, но вам не нужно использовать "/edit?type=:type"
, чтобы принять значение. Фактически, Mithril.js будет интерпретировать это как попытку сопоставления со строкой m.route.param("type") === ":type"
, что, скорее всего, не является желаемым результатом. Короче говоря, используйте m.route.param("key")
или атрибуты компонента маршрута для чтения параметров запроса.
Нормализация пути
Обработанные пути всегда возвращаются без дублирующихся параметров и лишних слешей, и всегда начинаются со слеша. Эти незначительные различия часто создают проблемы, и это может усложнить маршрутизацию и обработку путей. Mithril.js внутренне нормализует пути для маршрутизации, но он не предоставляет текущий, нормализованный маршрут напрямую. (Вы можете вычислить его через m.parsePathname(m.route.get()).path
.)
При дедупликации параметров приоритет отдается параметрам в строке запроса, а также параметрам, расположенным в конце URL-адреса.
Экранирование пути
Некоторые символы необходимо экранировать, если вы хотите использовать их в исходном виде. Функция encodeURIComponent
кодирует эти символы (и не только), и она автоматически используется для кодирования параметров при их подстановке и добавлении в строку запроса. Вот символы, которые интерпретирует Mithril.js:
:
=%3A
/
=%2F
(требуется только в путях)%
=%25
?
=%3F
(требуется только в путях)#
=%23
Конечно, есть и другие символы, которые вы должны экранировать в соответствии со спецификацией URL, например, пробелы. Но, как уже отмечалось, encodeURIComponent
делает это за вас, и Mithril.js использует это неявно, когда вы подставляете параметры. Поэтому вам следует беспокоиться об экранировании только при явном указании параметров, как в примере m.request("https://example.com/api/user/User%20Name/:field", {params: {field: ...}})
.