将HTML元素添加到Vue模板

时间:2020-09-04 11:40:12

标签: javascript vue.js chartist.js

我使用的图表组件(Chartist)在呈现SVG时需要HTML元素作为父元素。

图表可以使用的元素是在v-for循环期间生成的,这意味着在图表呈现时不会将它们添加到DOM。

代码看起来像这样(在Vue中):

<div v-for="chart in charts">
  <h1>{{chart.Title}}</h1>
  <div class="ct-chart" :id="'chart-' + chart.name"></div>
  {{generateChart('#chart-' + chart.name, chart.Data}}
  <div>
    <span v-for="l in legend" :class="chart.ClassName">{{l.DisplayName}}</span>
</div>

在组件中:

generateChart(chartName: string, data: IChartData) {
    /* More code here */

    //doesn't get added (can't find html node in dom)
    new Chartist.Line(chartName, data, options);

    // this worked
    //var element = document.createElement("DIV");
    //element.className = "ct-chart";
    //document.body.appendChild(element);
    //new Chartist.Line(element, data, options);

}

这会导致Chartist在querySelectorAll上失败。

另一方面,如果我使用document.createElement生成一个元素并将其附加到html主体,则生成效果很好。

摘要:

我想渲染一个图表,该图表需要一个DOM元素进行渲染。但是由于Vue会在其虚拟DOM中呈现所有内容,因此当Vue呈现视图(包括图表)时,没有可用的元素。

问题:

如何告诉vue添加预创建的HTML元素?还是在vue将所有内容都添加到真实DOM之前,我应该如何推迟宪章的产生?

解决方法:

我正在使用超时(setTimeout)来推迟图表渲染,以便Vue可以在调用图表渲染功能之前完成。

2 个答案:

答案 0 :(得分:2)

首先,不要在这样的模板中使用功能。模板被转换为渲染函数,并且每当发生更改时都会执行该函数-在这种情况下,这意味着您每次模板渲染时都会创建新的图表对象。这是您不想要的。

您想要的是首先呈现DOM节点(不包含任何图表),并在DOM准备就绪后使用mounted钩子初始化每个图表:

mounted: function () {
  this.$nextTick(function () {
    // Code that will run only after the
    // entire view has been rendered
  })
}

如果需要DOM元素引用,则可以使用refs

还要注意,大多数动态创建DOM元素的库(例如Chartist)几乎总是需要一些清理代码to avoid memory leaks

或者仅使用一些Vue包装器,例如vue-chartist

答案 1 :(得分:1)

据我了解的问题,您不想加载具有以下类别的div “。ct-chart” ,直到DOM完全加载。

您可以做的是在vue组件中添加 v-if ,当DOM完全加载后,您可以调用 generateChart()函数。

>
new Vue({
  el: '#app',
  data: {
   domloaded: false
  },
  created() {
     window.addEventListener('load', function () {
      domloaded = true;
   });
  }
}

然后,您可以添加一个v-if,或者使用生命周期挂钩,例如 mount() created()

<div v-for="chart in charts">
 <h1>{{chart.Title}}</h1>
 <div v-if="domloaded" class="ct-chart" :id="'chart-' + chart.name"></div>
  {{generateChart('#chart-' + chart.name, chart.Data)}}
 <div>
 <span v-for="l in legend" :class="chart.ClassName">{{l.DisplayName}}</span>
</div>