Vue централизовать события прокрутки и изменения размера (избегая повторения в компонентах) - PullRequest
0 голосов
/ 15 января 2019

У меня есть Vue-структура, подобная этой:

App
 |--{ data: { scrollInfo {...} } }
 |
 |--Component1
 |      |--{ data: { sidebarWidth: 500 }
 |
 |--Component2
 |      |--{ data: { overlayItemWidth: 389 }
 |
 |--Component3
 ...
 ...

В каждом из моих компонентов есть элементы с переменными, которые должны изменяться при прокрутке и изменении размера (например, sidebarWidth или overlayItemWidth). Я нашел этот пост здесь , который показывает этот способ добавления слушателя для прокрутки и изменения размера.

Я добавил его в основной экземпляр, вот так:

data: {
  scrollInfo: {
    scrollFromTop: 0,
    viewportHeight: 0,
    viewportWidth: 0,
    pageHeight: 0
  }
},
created() {
  window.addEventListener( 'scroll', this.calculateScroll );
  window.addEventListener( 'resize', this.calculateViewport );
  window.addEventListener( 'resize', this.calculatePageScrollSpecs );
  this.calculateViewport();
  this.calculateScroll();
  this.calculatePageScrollSpecs();
},
destroyed() {
  window.removeEventListener( 'scroll', this.calculateScroll );
  window.removeEventListener( 'resize', this.calculateViewport );
  window.removeEventListener( 'resize', this.calculatePageScrollSpecs );
}

Я не буду показывать содержимое методов (calculateScroll, calculateViewport, ...), так как это не имеет отношения к этому вопросу.

Теперь ... В моих компонентах есть переменные, которые должны изменяться и переоцениваться при прокрутке и при изменении размера. Но каждый раз, когда у меня есть такая переменная, я в настоящее время добавляю тех же слушателей в created и destroyed, а затем добавляю тех же слушателей событий к данному компоненту, а затем выполняю вычисления из нового метода. Это кажется длинным и неуклюжим.

Есть ли способ обойти эти window.AddEventListener в каждом компоненте, но только в моем корневом экземпляре?

... Я думал, если бы у меня был массив «вещей, которые нужно пересчитать при прокрутке или изменении размера» в моем главном экземпляре, но я не уверен, что это будет загроможден, поскольку переменные для компонентов тогда фактически не будут храниться в компоненте, а вместо этого будут ссылаться с this.$root.sidebarWidth. И это также сделало бы мой основной экземпляр массивным.

Есть предложения?

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Ладно ... Ответов нет вообще, - так что я сам погрузился в это. Это лучшее, что я мог придумать. Я надеюсь, что это помогает другим, нуждающимся в том же.

Я разрывался между использованием extends ( источник ) или mixins ( источник ).

После небольшого исследования я в конечном итоге использовал миксины ( это видео ударило по голове о том, чего я пытался достичь и как его решить). Если вы хотите сделать миксин глобальным для всех компонентов, посмотрите это видео около 4:11 и далее. Я не делаю это в нижеследующем объяснении.

Обратите внимание, что я использую webpack наряду с laravel-mix с нижеприведенным решением. Используется в WordPress-установке.

Раскрытие

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

Mixins-файл (./mixins/scrollAndResize.js).

export const scrollAndResizeMixin = {
  created() {
    console.log( 'scrollAndResizes loaded' );
    this.calcScroll();
    this.calcPageAndViewport();
  },
  data: function() {
    return {
      scrollFromTop: 0,
      viewportHeight: 0,
      viewportWidth: 0,
      pageHeight: 0
    }
  },
  methods: {
    calcScroll: function (){
      let doc = document.documentElement;
      this.scrollFromTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);

      // DEBUG (uncomment and scroll, to check if it works)
      // console.log( (window.pageYOffset || doc.scrollTop) );
      // console.log( (doc.clientTop || 0) );
    },
    calcPageAndViewport: function(){
      // Viewport info
      this.viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
      this.viewportWidth = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);

      // Page length
      var body = document.body;
      var html = document.documentElement;
      this.pageHeight = Math.max(
        body.scrollHeight,
        body.offsetHeight,
        html.clientHeight,
        html.scrollHeight,
        html.offsetHeight
      );
    },

  }
};

Основной js-файл (./app.js).

// Vue
import Vue from 'vue';

// Mixins
import { scrollAndResizeMixin } from './mixins/scrollAndResize';

// The Application
const app = new Vue({
  mixins: [
    scrollAndResizeMixin
  ],
  computed: {
    mobile: function() {
      return this.viewportWidth < 992; // This uses the mixin
    }
  },
  created() {
    window.addEventListener( 'scroll', this.calcScroll );
    window.addEventListener( 'resize', this.calcPageAndViewport );
  },
  destroyed() {
    window.removeEventListener( 'scroll', this.calcScroll );
    window.removeEventListener( 'resize', this.calcPageAndViewport );
  }
}); 

И / или использовать его только в таком компоненте, как ...

<template>

  <div>
    <p v-if="viewportWidth > 992">
      Desktop
    </p>
    <p v-else>
      Mobile
    </p>   
  </div>

</template>



<script>
  import { scrollAndResizeMixin } from '../mixins/scrollAndResize';

  export default {
    mounted() {
    },
    mixins: [
      scrollAndResizeMixin
    ],
    created() {
      window.addEventListener('scroll', this.calcScroll);
      window.addEventListener('resize', this.calcPageAndViewport);
    },
    destroyed() {
      window.removeEventListener('scroll', this.calcScroll);
      window.removeEventListener('resize', this.calcPageAndViewport);
    }
  }
</script>
0 голосов
/ 10 февраля 2019

Вы должны создать пользовательский компонент, который может принимать как изменяемые объекты и выполнять все необходимые операции (например, добавлять и удалять прослушиватели событий).

...