尝试遍历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);
答案 0 :(得分:1)
我可以尝试解释正在发生的事情,尽管我不清楚你为什么要做自己正在做的事情。
让我们从这里开始
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
属性来保留基础状态,以便模板可以确定在哪些位置应用样式。
答案 1 :(得分:1)
您要通过此方法实例化的组件(声明式):
<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,以显示不同的实现。
答案 2 :(得分:0)
@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));
}