Как передать ClientWidth в свойство компонента?

Я пытаюсь передать clientWidth родителя в компонент, но получаю ошибку: TypeError: Cannot read property 'clientWidth' of undefined. Подскажите, пожалуйста, как её исправить?

Vue.component('my-component', {
  template: '<p>{{ clientWidth }}</p>', 
  props: ['clientWidth'], 
}); 
new Vue({ el: '#app' }); 
<div id="app">
  <div class="parent" ref="parent">
    <my-component :client-width="$refs.parent.clientWidth"></my-component>
  </div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script> 


Ответы (2 шт):

Автор решения: HTMLProgrammer

Похоже $refs инициализируется после рендера компонента, но до выполнения mounted. Поэтому в шаблоне $refs.parent возвращает undefined.

Vue.component('my-component', {
  template: '<p>{{ clientWidth }}</p>', 
  props: ['clientWidth']
}); 
new Vue({ el: '#app',
   data(){
       return {parentWidth: 0};
   },
   mounted(){
      this.parentWidth = this.$refs.parent.clientWidth;
  } 
}); 
<div id="app">
  <div class="parent" ref="parent">
    <my-component :client-width="parentWidth"></my-component>
  </div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script> 

→ Ссылка
Автор решения: yar85

Простой глобальный миксин решает задачу отслеживания изменения состояния жизненного цикла компонента на "смонтирован":

Vue.mixin({
  computed: {
    $isMounted() {
      return this._lc.isMounted; 
    }, 
  }, 
  created() {
    this._lc = Vue.observable({ isMounted: false }); 
  }, 
  mounted() {
    this.$nextTick(() => void(this._lc.isMounted = true)); 
  },
});

Vue.component('my-component', {
  template: '<p>clientWidth: {{ clientWidth }}px</p>', 
  props: ['clientWidth'], 
}); 
new Vue({ el: '#app' });
<div id="app">
  <div class="parent" ref="parent">
    <my-component v-if="$isMounted" :client-width="$refs.parent.clientWidth"></my-component>
  </div>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>

То есть, поместив этот вызов Vue.mixin в main.js (до создания корневого экземпляра Vue), можно в шаблоне любого компонента использовать реактивное свойство $isMounted без каких-либо локальных бойлерплейтов.

// При желании, можно расширить миксин дополнительными свойствами отражающими состояние компонента. Но именно из жизненного цикла, обычно требуется отслеживать только монтирование (т.к. остальные задачи уже имеют специфичные для каждого компонента локальные побочные эффекты - и поэтому, они решаются локальными хуками).


То же самое, но уже не миксином, а через Composition API:

/* src/composables/useIsMounted.js */
import { reactive, computed, onMounted } from 'vue';

export default function() {                         //   Вообще, тут можно и `ref` использовать, т.к. значение одиночное:
  const _lc = reactive({ isMounted: false }),       // | const _isMounted = ref(false),
        isMounted = computed(() => _lc.isMounted);  // |       isMounted = computed(() => _isMounted.value);
  onMounted(() => void(_lc.isMounted = true));      // | onMounted(() => void(_isMounted.value = true));
  return isMounted;
};

И в компоненте:

import useIsMounted from '@/composables/useIsMounted';

export default {
  // ...
  setup() {
    // ...
    return {
      isMounted: useIsMounted(),
      // ...
    };
  },
};

В шаблоне свойство используется уже с именем isMounted, то есть без $!
// Потому что такой префикс имеет смысл только с глобальным миксином.


Почитать:

→ Ссылка