无法访问$ el的Vue组件,但在$ mount上除外

问题描述 投票:0回答:3

[尝试遍历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);
javascript vue.js dom vuejs2 vue-component
3个回答
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
投票

您正在通过此方法实例化的组件(声明式):

<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,以显示不同的实现。


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

© www.soinside.com 2019 - 2024. All rights reserved.