【问题标题】:Vue 3: Why vue yandex maps package doesn't work in vue 3 with defineCustomElement feature?Vue 3:为什么 vue yandex 地图包在具有 defineCustomElement 功能的 vue 3 中不起作用?
【发布时间】:2021-12-22 03:26:05
【问题描述】:

我在 vue 3 中有 2 个带有 vue yandex maps 的项目:

第一个项目

Demo vue yandex 映射的第一个项目。在这个项目包中这样注册:

代码 main.js 其中注册了来自js 文件的vue-yandex-maps 组件

const { createApp } = require('vue');
import App from './App.vue';
import ymapPlugin from 'vue-yandex-maps/dist/vue-yandex-maps.esm.js';

const app = createApp(App);

app.config.isCustomElement = (tag) => tag.startsWith('y'); // <= This is doesn't work
app.use(ymapPlugin);
app.mount('#app');

代码 MapComponent.vue使用vue-yandex-maps包的地方:

<template>
  <yandex-map :coords="coords">
    <ymap-marker
      marker-id="123"
      :coords="coords"
      :marker-events="['click']"
    ></ymap-marker>
  </yandex-map>
</template>

<script>
export default {
  name: 'MapComponent',
  setup() {
    return {
      coords: [54, 39],
    };
  },
};
</script>

代码 App.vue使用组件MapComponent

<template>
  <div id="app">
    <MapComponent />
  </div>
</template>

<script>
import MapComponent from './components/MapComponent.vue';

export default {
  name: 'App',
  components: {
    MapComponent,
  },
};
</script>

第二个项目

Demo 第二个项目使用了来自 vue 版本 3.2 的新功能 defineCustomElement 并在使用包 vue-yandex-maps 时收到错误消息:

未捕获的类型错误:无法读取 null 的属性(读取 'offsetWidth')

代码 main.jsjs 文件中注册vue-yandex-maps 组件:

import { defineCustomElement } from './defineCustomElementWithStyles'
import App from './App.ce.vue'
import store from './store'
import router from './router'
import ymapPlugin from 'vue-yandex-maps/dist/vue-yandex-maps.esm.js'

customElements.define(
  'app-root',
  defineCustomElement(App, {
    plugins: [store, router, ymapPlugin],
  })
)

代码 defineCustomElementWithStyles.js:

import { defineCustomElement as VueDefineCustomElement, h, createApp, getCurrentInstance } from 'vue'

const getNearestElementParent = (el) => {
  while (el?.nodeType !== 1 /* ELEMENT */) {
    el = el.parentElement
  }
  return el
}

export const defineCustomElement = (component, { plugins = [] }) =>
  VueDefineCustomElement({
    props: component.props,
    setup(props) {
      const app = createApp()

      // install plugins
      plugins.forEach(app.use)

      app.mixin({
        mounted() {
          const insertStyles = (styles) => {
            if (styles?.length) {
              this.__style = document.createElement('style')
              this.__style.innerText = styles.join().replace(/\n/g, '')
              getNearestElementParent(this.$el).prepend(this.__style)
            }
          }

          // load own styles
          insertStyles(this.$?.type.styles)

          // load styles of child components
          if (this.$options.components) {
            for (const comp of Object.values(this.$options.components)) {
              insertStyles(comp.styles)
            }
          }
        },
        unmounted() {
          this.__style?.remove()
        },
      })

      const inst = getCurrentInstance()
      Object.assign(inst.appContext, app._context)
      Object.assign(inst.provides, app._context.provides)
      console.log({ props })
      return () => h(component, props)
    },
  })

代码 Home.ce.vue 使用组件MapComponent

<script>
export default {
  name: 'Home',
}
</script>

<script setup>
import HelloWorld from '@/components/HelloWorld.ce.vue'
import MapComponent from '@/components/MapComponent.ce.vue'
</script>

<template>
  <h2>Home</h2>
  <HelloWorld msg="hello world" />
  <MapComponent />
</template>

代码 MapComponent.ce.vue 使用的包vue-yandex-maps:

<template>
  <yandex-map :coords="coords">
    <ymap-marker marker-id="123" :coords="coords" :marker-events="['click']"></ymap-marker>
  </yandex-map>
</template>

<script>
export default {
  name: 'MapComponent',
  setup() {
    return {
      coords: [54, 39],
    }
  },
}
</script>

<style>
.ymap-container {
  height: 600px;
}
</style>

问题

我在second project 中有错误,我使用vue-yandex-mapsdefineCustomElement

【问题讨论】:

  • 可能是因为 Web 组件使用影子 DOM,而您不能将它们用于设计为与全局 DOM 一起使用的组件。您可以确定第三方小部件的包装器是。

标签: javascript vue.js vuejs3 yandex-maps


【解决方案1】:

vue-yandex-maps renders a map containerrandomly generated IDpassed to the ymaps.Map constructor,稍后使用它来查询 document 的元素。不幸的是,地图容器呈现在 app-root 自定义元素的 Shadow DOM 中,而 document 查询隐藏了该元素。 document.querySelector() 因此返回nullymaps.Map 代码尝试通过null 引用获取容器的大小,从而导致您观察到的错误。

您必须自己修补vue-yandex-maps,或提交GitHub issue 以请求功能更改,您可以在其中传入地图容器元素(来自自定义元素的Shadow DOM)而不是ID。它看起来像ymaps.Map already accepts either an element or a string ID,因此无需进行其他更改。

【讨论】:

    猜你喜欢
    • 2019-03-18
    • 2022-12-08
    • 2022-01-16
    • 2022-11-11
    • 2021-08-20
    • 2023-03-06
    • 2019-03-25
    • 2021-06-24
    • 1970-01-01
    相关资源
    最近更新 更多