代码之家  ›  专栏  ›  技术社区  ›  Zeth

Vue集中化滚动和调整事件大小(避免组件中的重复)

  •  3
  • Zeth  · 技术社区  · 6 年前

    我的Vue结构如下:

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

    在我的每个组件中,我都有一些元素,这些元素的变量在滚动和调整大小时应该改变(例如 sidebarWidth overlayItemWidth )1.我找到了这个 post here 这显示了为滚动和调整大小添加侦听器的方法。

    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 回复  |  直到 6 年前
        1
  •  1
  •   Zeth    6 年前

    可以根本没有答案-所以我自己就开始了。这是我能想到的最好的了。我希望它能帮助其他有同样需要的人。

    我左右为难,左右为难 extends ( source mixins ( source ).

    this video 关于我试图实现的目标以及如何解决它,一针见血)。如果您想使mixin成为全局的,那么请在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>
    
        2
  •  1
  •   Loilo Afzal Hossain    5 年前

    很高兴您为自己找到了一个解决方案,但对于未来可能需要更舒适/通用的解决方案的访问者来说:几个月前我遇到了同样的问题,并在npm上安装了一个Vue mixin,它可以在每个生命周期处理一次全局数据,而不是在每个安装的组件上处理一次。

    它叫 Reactivator 这就是如何为 window.resize

    // viewport-width.js
    
    export default {
      // Reactivator uses `getInitialState` to fetch the
      // initial value before any listener was attached.
      getInitialState() {
        return window.innerWidth
      },
    
      // Reactivator calls `listen` when the first component using
      // it is created and executes the returned cleanup callback
      // when it's the last component using it is destroyed.
      listen(set) {
        const resizeHandler = () => set(window.innerWidth)
    
        window.addEventListener('resize', resizeHandler)
    
        return () => window.removeEventListener('resize', resizeHandler)
      }
    }
    
    
    // component.js
    
    import reactivator from 'vue-reactivator'
    import viewportWidth from './viewport-width.js'
    
    export default {
      mixins: [
        // `viewportWidth` will now be a reactive property in this component!
        reactivator({ viewportWidth })
      ]
    }
    

    这就是说,观察视口大小是一种常见的情况,因此我将其(以及其他有用的东西,如滚动位置或鼠标位置)放入了一个额外的通用重新激活器实现包中。你可以在npm上找到它 vue-browser-state .

        3
  •  0
  •   Michael    6 年前