Интеграция с Vue

Быстрый старт

Важно

Поддерживаемая версия Vue: не ниже 3

Подключение через 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.ts"></script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
import {createApp} from 'vue';
import App from './App.vue';

createApp(App).mount('#app');
<script lang="ts" setup>
  import {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapMarker} from './lib/ymaps';
  import type {YMapLocationRequest} from 'ymaps3';

  const LOCATION: YMapLocationRequest = {
    center: [37.588144, 55.733842],
    zoom: 9
  };
</script>

<template>
  <div style="width: 600px; height: 400px">
    <YMap :location="LOCATION">
      <YMapDefaultSchemeLayer />
      <YMapDefaultFeaturesLayer />

      <YMapMarker :coordinates="[37.588144, 55.733842]" :draggable="true">
        <section>
          <h1>You can drag this header</h1>
        </section>
      </YMapMarker>
    </YMap>
  </div>
</template>
import * as Vue from 'vue';

const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);

export const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
export const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer, YMapMarker} = vuefy.module(ymaps3);
{
  "compilerOptions": {
    "target": "es2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "typeRoots": ["./node_modules/@types", "./node_modules/@yandex/ymaps3-types"],
    "paths": {
      "ymaps3": ["./node_modules/@yandex/ymaps3-types"]
    }
  }
}
{
  "type": "module",
  "scripts": {
    "dev": "vite"
  },
  "devDependencies": {
    "@yandex/ymaps3-types": "^0.0.27",
    "vue": "^3.4.21",
    "@vitejs/plugin-vue": "^5.0.4",
    "typescript": "^4.9.5",
    "vite": "^5.2.8"
  }
}
import {defineConfig} from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      vue: 'vue/dist/vue.esm-bundler.js'
    }
  }
});

Поставьте зависимости и запустите локальный сервер:

npm install
npm run dev

Откройте приложение

Особенности

  1. В теге script, который загружает скомпилированный проектный js, указываем атрибут type="module", чтобы активировать поддержку ECMAScript Modules (ESM) и top-level-await:

    <script type="module" src="index.ts"></script>
    
  2. В package.json добавляем dev-зависимость от пакета @yandex/ymaps3-types.

    Рекомендуется устанавливать последнюю версию:

    npm i --save-dev @yandex/ymaps3-types@latest

  3. В tsconfig.json задаём compilerOptions.typeRoots со списком путей к файлам типов. Добавляем туда путь к пакету @yandex/ymaps3-types, благодаря чему в глобальной области видимости появляется пространство имен ymaps3 с типами.

    Примечание

    Пространство имен ymaps3 содержит все типы классов, которые предоставляет JS API, но до резолва ymaps3.ready в среде выполнения они недоступны.

  4. В tsconfig.json задаём compilerOptions.paths, в которой сообщаем ts-компилятору о том, что при импорте пакета ymaps3 его контент следует искать по указанному пути. Благодаря этому в проектных файлах можно импортировать типы словно они лежат не в @yandex/ymaps3-types, а в пакете ymaps3:

    import type {YMapLocationRequest} from 'ymaps3';
    

    Все типы должны быть импортированы из корня.

    Внутренняя структура не гарантирована и может меняться со временем.

  5. В tsconfig.json, для корректной работы top-level-await, параметр compilerOptions.module должен быть установлен в одно из следующих значений: es2022, esnext, system или preserve. Также параметр compilerOptions.target должен быть es2017 или выше.

  6. В vite.config.ts задаём resolve.alias, чтобы использовать "полную" сборку Vue (vue/dist/vue.esm-bundler.js). Это необходимо для корректной работы ymaps3 Vue компонентов.

  7. Для каждого объекта в JS API существует аналог Vue. Чтобы использовать версию API Vue, подключите модуль @yandex/ymaps3-vuefy. В файле lib/ymaps.ts дожидаемся полной загрузки JS API и vuefy модуля, после чего экспортируем необходимые компоненты карты для их использования в других частях проекта:

    import * as Vue from 'vue';
    
    const [ymaps3Vue] = await Promise.all([ymaps3.import('@yandex/ymaps3-vuefy'), ymaps3.ready]);
    
    export const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
    export const {YMap, YMapDefaultSchemeLayer, YMapDefaultFeaturesLayer} = vuefy.module(ymaps3);
    
  8. Использование top-level-await в lib/ymaps.ts гарантирует выполнение ymaps3.ready и ymaps3.import('@yandex/ymaps3-vuefy') до импорта компонентов карты, что позволяет синхронно использовать любые объекты JS API в качестве компонентов Vue:

    <YMap :location="LOCATION">
      <YMapDefaultSchemeLayer />
      <YMapDefaultFeaturesLayer />
      ...
    </YMap>
    

Указание входных параметров для собственных классов

Компоненты Vue требуют явного объявления входных параметров, чтобы Vue знал, какие из них следует рассматривать как дополнительные атрибуты.

Для базовых объектов из пространства имен ymaps3 входные параметры определены по умолчанию, и никаких дополнительных действий выполнять не требуется.

Если вы разработчик, который создает свои собственные классы (например, в рамках отдельного пакета), то вы можете определить, какие входные параметры будут находиться в компоненте. Определение props поддерживает формат Vue. Например, пользовательский класс YMapSomeClass:

type YMapSomeClassProps = {
  id: string;
  counter?: number;
};
export class YMapSomeClass extends ymaps3.YMapComplexEntity<YMapSomeClassProps> {
  static [ymaps3Vue.vuefy.optionsKey] = {props: ['id', 'counter']};
  //...
}

Помимо массива строк, мы также можем использовать объектный синтаксис:

export class YMapSomeClass extends ymaps3.YMapComplexEntity<YMapSomeClassProps> {
  static [ymaps3Vue.vuefy.optionsKey] = {
    props: {
      id: String,
      counter: Number
    }
  };
  //...
}

или с валидацией входных параметров:

export class YMapSomeClass extends ymaps3.YMapComplexEntity<YMapSomeClassProps> {
  static [ymaps3Vue.vuefy.optionsKey] = {
    props: {
      id: {type: String, required: true},
      counter: {type: Number, required: false}
    }
  };
  //...
}

Указание входных параметров при использовании сторонних пакетов

Если разработчики сторонних пакетов не определили входные параметры для своих классов, то вы можете указать их самостоятельно при вызове vuefy, передав их в качестве второго аргумента:

const ymaps3Vue = await ymaps3.import('@yandex/ymaps3-vuefy');
const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
const {YMapSomeClass as YMapSomeClassV} = vuefy.module(
  {YMapSomeClass},
  {
    YMapSomeClass: ['id', 'counter'] // props для класса YMapSomeClass
  }
);

Аналогичным образом поддерживается синтаксис объекта и валидации, показанные выше.

Пользовательские реализации объектов ymaps3.YMapEntity для Vue

Когда стандартная конвертация недостаточна, используйте overrideKey ключ чтобы указать свою реализацию для vuefy:

type YMapSomeClassProps = {
  id: string;
  counter?: number;
};
/* объект ymaps3.YMapEntity */
export class YMapSomeClass extends ymaps3.YMapComplexEntity<YMapSomeClassProps> {
  static [ymaps3Vue.vuefy.overrideKey] = YMapSomeClassVuefyOverride;
  //...
}

YMapSomeClassVuefyOverride это метод, который должен вернуть компонент Vue. В качестве параметров он получает базовый класс, объявленные пропсы и объект с Vue и vuefy если потребуются их методы. В примере ниже создается обертка YMapSomeClassV с дополнительной логикой вокруг компонента, полученным базовым методом vuefy:

export const YMapSomeClassVuefyOverride: CustomVuefyFn<YMapSomeClass> = (
  YMapSomeClassI, // базовый YMapSomeClass
  props, // объявленные входные параметры
  {vuefy, Vue}
) => {
  // Стандартный vuefy метод
  const YMapSomeClassVuefied = vuefy.entity(YMapSomeClassI, props);
  const YMapSomeClassV = Vue.defineComponent({
    props,
    name: 'YMapSomeClassV',
    components: {YMapSomeClassVuefied},
    setup() {
      // дополнительная логика пользовательской реализации
    },
    template: `<YMapSomeClassVuefied v-bind="$props" ... />`
  });
  return YMapSomeClassV;
};

полученный компонент можно использовать в приложении:

const ymaps3Vue = await ymaps3.import('@yandex/ymaps3-vuefy');
const vuefy = ymaps3Vue.vuefy.bindTo(Vue);
const YMapSomeClassV = vuefy.entity(YMapSomeClass);
const app = createApp({
  components: {YMapSomeClassV},
  template: `<YMapSomeClassV id="some_id" />`
});
app.mount('#app');
Предыдущая
Следующая