无法访问$ el of Vue组件,但在$ mount

时间:2019-10-31 02:18:24

标签: javascript vue.js dom vuejs2 vue-component

尝试遍历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);

3 个答案:

答案 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,但它们不在数组中。

由于无法真正理解为什么您会以这种奇怪的方式创建子组件,因此我无法就如何解决您的问题提出具体建议。更为正常的模式是:

  1. ['a','b','c']中具有相关父组件的数组data
  2. 在模板中遍历该数组以创建子代。
  3. 使用模板中的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));
}

JSFiddle