Подключение API
Обычное подключение
<!DOCTYPE html>
<html>
<head>
<!-- Вместо YOUR_API_KEY подставить значение настоящего ключа -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU"></script>
<script src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
{
"devDependencies": {
"http-server": "14.1.1"
},
"scripts": {
"start": "npx http-server ."
}
}
Поставьте зависимости и запустите локальный сервер:
npm install
npm run start
Откройте приложение
Внимание
Работа API гарантируется в браузерах, чья аудитория больше 0.5% по данным Browserslist.
Особенности обычного подключения
- JS API распространяется исключительно по ссылке, которую нужно подключать в шапке документа.
- Компоненты API всегда загружаются асинхронно.
- Компоненты существуют только в глобальной области видимости в переменной
ymaps3
. - Компоненты доступны только после разрешения промиса
ymaps3.ready
.
Параметры загрузки API
apikey |
Обязательный параметр Ключ, полученный в Кабинете Разработчика. Примечание Ключ будет активирован в течение 15 минут после получения. JS API 3.0 работает только с ключами, у которых заполнено поле "Ограничение по HTTP Referer". Подробнее об ограничениях |
lang |
Обязательный параметр Локаль, задается в виде
|
Промис ready
Промис ymaps3.ready
гарантирует, что все компоненты основного модуля Javasript API
загружены, а DOM
построен.
Внимание
Обработчики событий типа document.ready
, window.onload
, jQuery.ready
не сигнализируют об окончании загрузки компонентов JS API.
Подключение через top-level-await (рекомендуется)
<!DOCTYPE html>
<html>
<head>
<!-- Вместо YOUR_API_KEY подставить значение настоящего ключа -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU"></script>
<script type="module" src="index.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import { YMap, YMapDefaultSchemeLayer } from './lib/ymaps.js'
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
await ymaps3.ready;
export const {YMap, YMapDefaultSchemeLayer} = ymaps3;
{
"devDependencies": {
"http-server": "14.1.1"
},
"scripts": {
"start": "npx http-server ."
}
}
Поставьте зависимости и запустите локальный сервер:
npm install
npm run start
Откройте приложение
Особенности
-
В теге script, который загружает скомпилированный проектный js, указываем атрибут
type="module"
, чтобы активировать поддержку ECMAScript Modules (ESM) и top-level-await:<script type="module" src="index.js"></script>
Поддержка ESM при использовании бандлеров
Если для сборки проекта используется бандлер, например Webpack, то в файл
package.json
необходимо добавить"type": "module"
-
В файле
lib/ymaps.js
дожидаемся полной загрузки JS API, после чего экспортируем необходимые компоненты карты для их использования в других частях проекта:await ymaps3.ready; export const {YMap, YMapDefaultSchemeLayer} = ymaps3;
-
Использование top-level-await в
lib/ymaps.js
гарантирует выполнениеymaps3.ready
до импорта компонентов карты, поэтому проектный код можно писать короче и опрятнее (больше не нужна асинхронная функция initMap):import { YMap, YMapDefaultSchemeLayer } from './lib/ymaps.js' const map = new YMap({...});
Подключение с Webpack
- Можно ли не подключать JS API в шапке
HTML
-документа? - Можно ли вызывать компоненты JS API не из глобальной переменной, а более привычно, словно они поставляются через
npm
-пакет? - Можно ли сделать так, чтобы не приходилось обрабатывать разрешение промиса
ymaps3.ready
?
С помощью Webpack
и его опции externals
это сделать можно. Есть три способа, каждый имеет как преимущества, так и ограничения.
Способ №1
<!DOCTYPE html>
<html>
<head>
<!-- Вместо YOUR_API_KEY подставить значение настоящего ключа -->
<script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU"></script>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externals: {
ymaps3: 'ymaps3'
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Поставьте зависимости, соберите проект и запустите локальный сервер:
npm install
npm run build
npm run start
Откройте приложение
Особенности
-
На
HTML
-странице всё ещё подключаем загрузчикJS API
:<head> <script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU"></script> </head>
Успешная загрузка скрипта гарантирует, что в глобальном доступе появляется переменная
ymaps3
. -
В
webpack.config.js
объявляем внешнюю переменнуюymaps3
:module.exports = { // ... externals: { ymaps3: 'ymaps3' } };
Благодаря этому в проектном коде появляется возможность импортировать
ymaps3
так, словно кодymaps3
поставляется не через глобальную переменную, а черезnpm
-пакет:import * as ymaps3 from 'ymaps3'; // ...
Способ №2
<!DOCTYPE html>
<html>
<head>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
async function initMap() {
await ymaps3.ready;
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
}
initMap();
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externalsType: 'script',
externals: {
// Вместо YOUR_API_KEY подставить значение настоящего ключа
ymaps3: ['https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU', 'ymaps3']
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Поставьте зависимости, соберите проект и запустите локальный сервер:
npm install
npm run build
npm run start
Откройте приложение
Особенности
Это видоизмененный первый способ:
-
Больше не нужно в шапке
HTML
-страницы подключать тег<script>
. Этим занимается самwebpack
. -
В
webpack.config.js
так же объявляется внешняя переменнаяymaps3
, но в ней указывается путь к загрузчику API:module.exports = { // ... externalsType: 'script', externals: { ymaps3: ['https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU', 'ymaps3'] } };
Ограничения способа №1 и №2
В обоих вышеописанных способах импортируется не готовое API, а легковесный загрузчик. Компоненты становятся полностью доступны только после разрешения промиса ymaps3.ready
. Это означает, что если ваш клиентский код разбит на свои модули, и JS API используется сразу в нескольких ваших модулях, следует в каждом вашем модуле дожидаться разрешения промиса ymaps3.ready
.
Например, вы хотите отобразить на странице сразу две карты, каждую в своем контейнере. Вам удобнее описывать эту функциональность не в одном большом модуле, а в двух разных, например с именами module-a.js
и module-b.js
. Тогда с использованием вышеописанных способов код ваших модулей будет выглядеть примерно так:
// Файл module-a.js
import * as ymaps3 from 'ymaps3';
async function initMap() {
// Дождитесь резолва`ymaps3.ready`
await ymaps3.ready;
const {YMap} = ymaps3;
// Карта инициализируется в первом контейнере
const map = new YMap({document.getElementById('first-map-container')});
}
initMap();
// Файл module-b.js
import * as ymaps3 from 'ymaps3';
async function initMap() {
// Дождитесь резолва`ymaps3.ready`
await ymaps3.ready;
const {YMap} = ymaps3;
// Карта инициализируется во втором контейнере
const map = new YMap({document.getElementById('second-map-container')});
}
initMap();
Приходится в каждом модуле дожидаться разрешения ymaps3.ready
. Это неудобно, хотелось бы писать код проще:
// Файл module-a.js
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({document.getElementById('first-map-container')});
// Файл module-b.js
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({document.getElementById('second-map-container')});
Чтобы этого достичь, воспользуйтесь третьим способом.
Способ №3
<!DOCTYPE html>
<html>
<head>
<script src="build/bundle.js"></script>
</head>
<body>
<div id="app" style="width: 600px; height: 400px"></div>
</body>
</html>
import * as ymaps3 from 'ymaps3';
const {YMap, YMapDefaultSchemeLayer} = ymaps3;
const map = new YMap(
document.getElementById('app'),
{
location: {
center: [37.588144, 55.733842],
zoom: 10
}
}
);
map.addChild(new YMapDefaultSchemeLayer());
const path = require('path');
module.exports = {
mode: 'development',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build'),
},
externalsType: 'script',
externals: {
// Вместо YOUR_API_KEY подставить значение настоящего ключа
ymaps3: [
`promise new Promise((resolve) => {
if (typeof ymaps3 !== 'undefined') {
return ymaps3.ready.then(() => resolve(ymaps3));
}
const script = document.createElement('script');
script.src = "https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=ru_RU";
script.onload = () => {
ymaps3.ready.then(() => resolve(ymaps3));
};
document.head.appendChild(script);
})`
]
},
devtool: 'cheap-source-map'
};
{
"devDependencies": {
"http-server": "14.1.1",
"webpack": "5.88.2",
"webpack-cli": "5.1.4"
},
"scripts": {
"build": "webpack",
"start": "npx http-server ."
}
}
Поставьте зависимости, соберите проект и запустите локальный сервер:
npm install
npm run build
npm run start
Откройте приложение
Особенности
Это почти тот же способ №2, только в webpack.config.js
при объявлении переменной ymaps3
несколько иначе указывается путь к загрузчику API и там же происходит разрешение промиса ymaps3.ready
.
При таком подключении в собранном проектном js-файле становятся доступны полностью загруженные модули JS API и гарантируется исполнение ymaps3.ready
, поэтому проектный код можно писать короче и опрятнее:
import * as ymaps3 from 'ymaps3';
const {YMap} = ymaps3;
const map = new YMap({...});
Внимание
При таком способе подключения проектный код не начнет выполняться до тех пор, пока компоненты JS API не будут полностью загружены.
Ограничение способа №3
Например, вы хотите показывать анимацию загрузки до момента, пока не загрузились компоненты карты. Подключили JS API способом №3 и написали для этого вот такой код. К сожалению, у вас не получится выполнить задачу:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ymaps3 from 'ymaps3';
// Выполнение этой строки начнется только после загрузки ymaps3 и резолва ymaps3.ready
const reactify = ymaps3.reactify.bindTo(React, ReactDOM);
const {YMap} = reactify.module(ymaps3);
function MapView() {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
setLoading(false);
}, []);
// Этот код бесполезен. Он, конечно, выполнится при монтировании компонента в DOM, но
// монтирование-то произойдет лишь после загрузки ymaps3 и резолва ymaps3.ready.
// Поэтому при монтировании пользователь на долю секунды увидит статус 'Loading...',
// а потом сразу же случится useEffect, который отменит показ анимации загрузки.
if (loading) {
return <div>Loading...</div>;
}
return <YMap />;
}
function App() {
return (
<MapView />
);
}
Главный недостаток webpack-подключения №3 состоит в том, что в проектных модулях не будет ничего выполняться до тех пока, пока компоненты JS API не загрузятся полностью.
Чтобы показать анимацию загрузки, от способа №3 придётся отказаться:
- Перейти на webpack-подключение №1 или №2.
- Внутри
React.useEffect
нужно дождатьсяymaps3.ready
и только после этого снять флажокloading
. - Код, использующий
reactify
-модуль, необходимо поместить внутрь компонентаMapView
так, чтобыJS
-интерпретатор смог "прочитать" эти строчки только после разрешенияymaps3.ready
:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ymaps3 from 'ymaps3';
function MapView() {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
ymaps3.ready.then(() => setLoading(false));
}, []);
if (loading) {
return <div>Loading...</div>;
}
const reactify = ymaps3.reactify.bindTo(React, ReactDOM);
const {YMap} = reactify.module(ymaps3);
return <YMap />;
}
function App() {
return (
<MapView />
);
}
Переключение языка
Помните, что при подключении API указывается язык. Если вы создаете интернациональные сайты, при любом способе подключения следите за его переключением.
Например, для подключения с Webpack третьим способом это можно сделать так:
module.exports = {
//...
externals: {
ymaps3: [
`promise new Promise((resolve) => {
...
const lang = ['ru', 'ru-Ru'].includes(navigator.language) ? 'ru-Ru' : 'en-US';
script.src = "https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=" + lang;
...
})`
]
}
};
Подключение пакетов и модулей
JS API предоставляет дополнительные пакеты и модули, полезные для решения специфических задач. Для их загрузки предусмотрен метод ymaps3.import
. Подробнее читайте в документации пакетов и модулей