我使用的图表组件(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可以在调用图表渲染功能之前完成。
答案 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>