Vue

Quick start

Warning

Supported Vue version: 3 or higher

Connecting via top-level-await

<!DOCTYPE html>
<html>
  <head>
    <!-- Replace YOUR_API_KEY with the real key -->
    <script src="https://api-maps.yandex.ru/v3/?apikey=YOUR_API_KEY&lang=en_US"></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/ymaps3';
  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.17",
    "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'
    }
  }
});

Set dependencies and run a local server:

npm install
npm run dev

Open the app

Specifics

  1. Specify the type="module" attribute in the "script" tag that loads the compiled project JS to enable ECMAScript Modules (ESM) and top-level-await support:

    <script type="module" src="index.ts"></script>
    
  2. In package.json, add a dev dependency on the @yandex/ymaps3-types package.

    We recommend installing the latest version:

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

  3. In tsconfig.json, set compilerOptions.typeRoots with a list of paths to type files. Add a path to the @yandex/ymaps3-types package there to make the ymaps3 namespace with types appear in the global scope.

    Note

    The ymaps3 namespace contains all the class types provided by the JS API, but they are not available in the runtime environment until ymaps3.ready is resolved.

  4. In tsconfig.json, set compilerOptions.paths, informing the TS compiler that the contents of the imported ymaps3 package should be searched for at the specified path. This enables you to import types in project files as if they were located not at @yandex/ymaps3-types, but in the ymaps3 package:

    import type {YMapLocationRequest} from 'ymaps3';
    

    All types must be imported from the root.

    The internal structure isn't guaranteed and can change over time.

  5. In tsconfig.json, for top-level-await to operate correctly, the compilerOptions.module parameter must be set to one of the following values: es2022, esnext, system, or preserve. The compilerOptions.target parameter must be set to es2017 or higher.

  6. In vite.config.ts, set resolve.alias to use the "complete" Vue build (vue/dist/vue.esm-bundler.js). This is necessary for ymaps3 of Vue components to work correctly.

  7. Each object in the JS API has a Vue analog. To use the Vue API version, connect the @yandex/ymaps3-vuefy module. In lib/ymaps3.ts, wait until the JS API and Vuefy module are fully loaded and then export the necessary map components so that they can be used in other parts of the project:

    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. The use of top-level-await in lib/ymaps3.ts guarantees that ymaps3.ready and ymaps3.import('@yandex/ymaps3-vuefy') are executed before the map components are imported, allowing any JS API objects to be used as Vue components synchronously:

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

Specifying input parameters for custom classes

Vue components require explicit declaration of input parameters so that Vue knows which of them should be considered additional attributes.

For basic objects from the ymaps3 namespace, input parameters are determined by default and no additional actions are required.

If you are a developer who creates custom classes (for example, as part of a separate package), you can determine which input parameters will be contained in the component. Determining props supports Vue format. Fro example, custom YMapSomeClass:

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

In addition to an array of strings, you can also use object syntax:

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

or with input parameter validation:

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

Specifying input parameters when using third-party packages

If developers of third-party packages have not determined input parameters for their classes, you can specify them yourself when calling vuefy by passing them as a second argument:

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 for the YMapSomeClass class
  }
);

The object syntax and validations shown above are supported in a similar way.

Custom implementations of ymaps3.YMapEntity objects for Vue

When the standard conversion is insufficient, use the ymaps3.overrideKeyVuefy key to specify your implementation for vuefy:

type YMapSomeClassProps = {
  id: string;
  counter?: number;
};
/* ymaps3.YMapEntity object */
export class YMapSomeClass extends ymaps3.YMapComplexEntity<YMapSomeClassProps> {
  static [ymaps3.overrideKeyVuefy] = YMapSomeClassVuefyOverride;
  //...
}

YMapSomeClassVuefyOverride is a method that must return a Vue component. It gets the base class, declared props, and an object with Vue and vuefy (if their methods are required) as parameters. The example below shows the creation of the YMapSomeClassV wrapper with additional logic around the component that was obtained using the base vuefy method:

export const YMapSomeClassVuefyOverride: CustomVuefyFn<YMapSomeClass> = (
  YMapSomeClassI, // base YMapSomeClass
  props, // declared input parameters
  {vuefy, Vue}
) => {
  // Standard vuefy method
  const YMapSomeClassVuefied = vuefy.entity(YMapSomeClassI, props);
  const YMapSomeClassV = Vue.defineComponent({
    props,
    name: 'YMapSomeClassV',
    components: {YMapSomeClassVuefied},
    setup() {
      // additional logic for custom implementation
    },
    template: `<YMapSomeClassVuefied v-bind="$props" ... />`
  });
  return YMapSomeClassV;
};

the resulting component can be used in the app:

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');