[尝试遍历Vue组件数组并访问每个组件的DOM元素。这似乎是一个非常基本的需求,但是我进行了很多搜索,尽管在同一总体领域中有很多问题,但我还没有为此提出解决方案。
上下文:我的应用将访问DOM元素以根据应用逻辑对文本进行样式设置。对于这篇文章,我创建了一个精简的,最小的应用程序来重现我的问题,因此它不做任何样式,而只是显示元素的innerText。
JSFiddle或在下面查看相同的代码。您将看到此代码仅在$ mount事件处理程序内成功成功地短暂访问了组件的$el
。之后,它是不确定的。我可以在事件处理程序中保存一个引用,但是认为这是必要的……我似乎疯了……我想念什么?
HTML
<div id="app"
oncontextmenu="return false"
v-on:mouseup="showchars()"
>
<h2>The components a, b and c will be here once mounted. Note in the initial dialogs that their $el is accessible when their mount event handler calls showchars. Then click this div to call showchars again, and note that $el is no longer defined.</h2>
<charcomponent
v-for = "c in charcomponents"
v-bind:char="c.char"
></charcomponent>
</div>
JS
let CharComponent = {
props: ['char'],
mounted: function() {
this.showinfo("it's like this on mount");
},
methods: {
showinfo: function(cmt) {
try {
alert(cmt + ': char=' + this.char +', el=' + this.$el + ', and...');
alert('...el.innerText=' + this.$el.innerText);
}
catch(error) {
alert(error);
}
}
},
template: '<p>{{ char }}</p>'
}
var vm = new Vue({
el: "#app",
components: {
charcomponent: CharComponent
},
data: {
charcomponents: []
},
methods: {
showchars() {
for (var c of this.charcomponents) {
c.showinfo("it's different later");
}
}
}
})
var ccharcomp = Vue.extend(CharComponent);
for (var ch of ['a','b','c']) {
var ocharcomp = new ccharcomp({
propsData: {
char: ch
}
});
vm.charcomponents.push(ocharcomp);
}
//alert(vm.chars.length);
我可以尝试解释正在发生的事情,尽管我不清楚您为什么要做自己正在做的事情。
让我们从这里开始:
var ocharcomp = new ccharcomp({
propsData: {
char: ch
}
});
vm.charcomponents.push(ocharcomp);
这将创建ccharcomp
组件的新实例,实际上就是CharComponent
。然后将每个这些都添加到数组中。
这些Vue实例均未安装。他们永远不会被渲染。它们只是被创建并推送到数组上。他们将没有$el
,并且永远不会调用mounted
钩子。
然后在您的模板中有了这个:
<charcomponent
v-for = "c in charcomponents"
v-bind:char="c.char"
></charcomponent>
此循环遍历同一数组,并为每个条目创建一个新的CharComponent
实例。 char
的值从数组中的每个组件复制到模板中创建的相应组件。
将在模板中创建的组件进行渲染,安装并具有$el
。您正在从mounted
挂钩中看到日志。
然后我们有了这个:
showchars() {
for (var c of this.charcomponents) {
c.showinfo("it's different later");
}
}
这遍历了原始的组件数组,这些组件从未安装过。这些没有$el
,他们从来没有。模板创建的组件仍然存在,并且仍然具有$el
,但它们不在数组中。
我无法具体建议如何解决您的问题,因为我不太了解您为什么以这种奇怪的方式创建子组件。更为正常的模式是:
['a','b','c']
中具有数组data
。ref
和父级中的$refs
访问子组件,然后使用$el
抓取每个子元素。但是,如果您只想应用样式,则通常不建议像这样抓取元素。相反,您应该在模板中使用:class
或:style
绑定,以使Vue为您应用样式。您可能需要引入额外的data
属性来保存基础状态,以便模板可以确定在哪些位置应用样式。
您正在通过此方法实例化的组件(声明式):
<charcomponent
v-for = "c in charcomponents"
v-bind:char="c.char"
></charcomponent>
与您在此处创建的(编程的)有所不同:
var ccharcomp = Vue.extend(CharComponent);
for (var ch of ['a','b','c']) {
var ocharcomp = new ccharcomp({
propsData: {
char: ch
}
});
vm.charcomponents.push(ocharcomp);
}
最初的警报系列是由第一组组件(说明性)中已安装的挂钩触发的。肯定地,这里存在$ el对象,因为标记已经是DOM的一部分,并且它还使用了Vue实例中具有的本地声明]
components: {
charcomponent: CharComponent
},
对于存储在名为charcomponents的数组中的第二组组件,没有任何已安装的元素。请注意,在使用Vue.extend时,仅创建Vue实例的子类,因此必须通过$ mount方法挂载实例化的新对象。
showchars() {
for (var c of this.charcomponents) {
c.showinfo("it's different later");
}
}
有效地,访问第二批组件的$ el元素,尚未定义。
我创建了一个简单的实现here in JSFiddle,以显示不同的实现。
@ skirtle和@Jose Mari Ponce的回答帮助我了解了为什么我的工作不起作用。我打算再次查看模板中的类/样式绑定,这是完成此特定应用程序所需的更好方法,但我也想遵循此方法,因为似乎遍历已知的组件列表并访问$ el具有更广泛的适用性。
原来只是用JS v-for
替换HTML appendChild
,然后将动态创建的组件安装到新的子元素上,这是简单的问题:
HTML
<div id="components">
</div>
JS
var ccharcomp = Vue.extend(CharComponent);
var container = document.getElementById("components");
for (var ch of ['a','b','c']) {
var p = document.createElement("p");
container.appendChild(p);
var ocharcomp = new ccharcomp({
propsData: {
char: ch
}
});
vm.charcomponents.push(ocharcomp.$mount(p));
}