Невозможно получить доступ к $ el компонента Vue, кроме подключенного $ - PullRequest
0 голосов
/ 31 октября 2019

Попытка перебрать массив компонентов Vue и получить доступ к элементу DOM каждого компонента. Это кажется довольно простой потребностью, но я много искал и, хотя в той же области есть много вопросов, я не нашел решения этой проблемы.

Контекст: мое приложениеполучит доступ к элементу DOM для стилизации текста в соответствии с логикой приложения. Для этого поста я создал урезанное минимальное приложение для воспроизведения моей проблемы, поэтому оно не выполняет стилизацию, а просто отображает innerText элемента.

JSFiddle или см. тот же код ниже. Вы увидите, что этот код успешно обращается к компоненту $el кратко, только в обработчике событий $ mount. После этого это не определено. Я мог бы сохранить ссылку в обработчике событий, но кажется странным думать, что это будет необходимо ... что я пропускаю?

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 ]

1 голос
/ 31 октября 2019

Компоненты, которые вы создаете с помощью этого метода (декларативно):

<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элемент для второй партии компонентов, он еще не определен.

Я создаю простую реализацию здесь, в JSFiddle , чтобы показать различные реализации.

1 голос
/ 31 октября 2019

Я могу попытаться объяснить, что происходит, хотя мне несколько непонятно, почему вы делаете то, что делаете.

Давайте начнем здесь:

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 свойства для хранения базового состояния, чтобы шаблон мог определить, какие стили применять, где.

0 голосов
/ 31 октября 2019

Очень информативные ответы @skirtle и @Jose Mari Ponce помогли мне понять, почему то, что у меня не получалось. Я намерен еще раз взглянуть на привязку классов / стилей в шаблоне как, возможно, лучший способ выполнить то, что нужно этому конкретному приложению, но я хотел бы выполнить это тоже, так как кажется, что циклически просматривается известный список компонентов и доступ к $ el такженеобходимо, поскольку логика приложения должна определять значения, к которым привязан шаблон. Я также думаю, что это нечто гораздо более широкое применение, чем это приложение.

Оказалось, что это просто вопрос замены моего HTML v-for на JS 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

...