具有插槽内容的Vue组件转换为谷歌地图标记

时间:2017-12-12 19:06:39

标签: vue.js

我知道有一个google maps vue库,但我在代码库中工作,它已经创建了一些类似的组件。

特别是,我有一个组件在vue中包裹rich-marker,暴露了一个在地图上呈现为富标记的插槽。

为了完成这项工作,我需要向Google API提供div,并且我希望此div的内容能够反映slot的内容。使用渲染函数似乎部分工作如下(粗略地):

render(createElement){
   let content = createElement('div', this.$slots.default);
   this._marker = new RichMarker({
      content: content,
      map: this.map
   });
   return content;
}

但它有时会导致问题,因为Vue控制下的DOM节点正在树上移动(谷歌地图将它们放在任何需要的地方)。这由以下错误显示:

DOMException: Failed to execute 'insertBefore' on 'Node': 
The node before which the new node is to be inserted is not a child of this node.

为了避免这种情况,我可以考虑几个选项:

  1. 以某种方式将$slots.default VNode转换为实际的DOM节点,然后将其提供给Google(并使渲染函数返回虚拟空div)。
  2. 让Vue渲染其所需的位置,但使用css进行隐藏,然后将innerHTML复制到Google的新div
  3. 做一些包装破解,我移动一个内部元素,但留下最外面的元素,以便Vue不会混淆。
  4. 我无法找到任何可以让我选择的东西(1.)。有谁知道Vue中是否有未记录的部分可以让我这样做?

    我确实尝试了选项(2.),但update生命周期事件似乎没有做我需要的事情,因为当插槽内容发生变化时它没有触发。我也不确定在真正的DOM渲染后是否可以保证触发。

    我也尝试过选项(3.)但是与选项(2.)有类似的问题。实际上,我不确定选项(3.)是否真的有用,因为Vue需要改变与插槽相关的节点以及标记组件的节点。

    更新 我设法最终做出选项(3.)的工作。渲染函数现在看起来大致如下:

    render(createElement){
       this._otherEl = this._otherEl || document.createElement('div');
       let elInner = createElement('div', this.$slots.default);
       let el = createElement('div', {}, [elInner]);
       if(this.$el && this.$el.firstChild && this._otherEl.firstChild !== this.$el.firstChild){
         this._otherEl.firstChild && this._otherEl.removeChild(this._otherEl.firstChild);
         this._otherEl.appendChild(this.$el.firstChild);
       }
    
       this.marker = new RichMarker({
          content: this._otherEl,
          map: this.map
       });
       return el;
    }
    

    marker需要在组件的data中声明(由于某些原因我没有进一步调查)。

0 个答案:

没有答案