将 HTML 元素添加到 vue 模板
Adding HTML element to a vue template
我正在使用一个图表组件 (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 可以在我调用图表渲染函数之前完成。
据我了解您不想加载具有 class 的 div 的问题
".ct-chart" 直到 DOM 完全加载。
你可以做的是添加一个 v-if 到你的 vue 组件,当 DOM 完全加载时你可以调用你的 generateChart()函数。
new Vue({
el: '#app',
data: {
domloaded: false
},
created() {
window.addEventListener('load', function () {
domloaded = true;
});
}
}
然后您可以像这样添加 v-if 或者使用生命周期挂钩,例如 mounted() 或 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>
首先,不要在这样的模板中使用函数。模板被转换为渲染函数,每当发生变化时都会执行该函数 - 在这种情况下,这意味着您将在每次渲染模板时创建新的图表对象....这是您不想要的。
你想要的是先渲染 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
我正在使用一个图表组件 (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 可以在我调用图表渲染函数之前完成。
据我了解您不想加载具有 class 的 div 的问题 ".ct-chart" 直到 DOM 完全加载。
你可以做的是添加一个 v-if 到你的 vue 组件,当 DOM 完全加载时你可以调用你的 generateChart()函数。
new Vue({
el: '#app',
data: {
domloaded: false
},
created() {
window.addEventListener('load', function () {
domloaded = true;
});
}
}
然后您可以像这样添加 v-if 或者使用生命周期挂钩,例如 mounted() 或 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>
首先,不要在这样的模板中使用函数。模板被转换为渲染函数,每当发生变化时都会执行该函数 - 在这种情况下,这意味着您将在每次渲染模板时创建新的图表对象....这是您不想要的。
你想要的是先渲染 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