1. 程式人生 > >vue+eleui專案 專案結構(封裝一個全域性元件-滾動條)

vue+eleui專案 專案結構(封裝一個全域性元件-滾動條)

固定高度表格,然後裡面滾動,原生滾動條太難看,而且還有相容問題,好吧,那就自己寫一個吧

<template>
  <div
    class="v-scroll-bar"
    @wheel.prevent="wheelEventHandle"
    :style="{height:height+'px'}"
    ref="jScroll">
    <!--滾動內容-->
    <div class="scroll-content"
      :style="scrollContentStyles">
      <slot></slot>
    </div>
    <!--滾動條-->
    <div
      :class="['scroll-bar-wrap',autoHide?'autoHide':'']"
      :style="scrollWrapStyle"
      @mousedown.prevent.stop="clickBarWrapHandler">
      <div
        ref="bar"
        class="scroll-bar"
        :style="scrollBarStyle"
        @mousedown.prevent.stop="clickBarHandler">
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    name: 'v-scroll-bar',
    props: {
      //  外框高度
      height: {type: Number, default: 100, required: true},
      //  行高
      lineHeight: {type: Number, required: true},
      //  資料的長度
      length: {type: Number, required: true},
      //  速度
      speed: {type: Number, default: 2},
      //自動隱藏
      autoHide: {type: Boolean, default: true},
      //滾動條寬度
      barWidth: {type: Number, default: 6},
      //滾動條跑道顏色
      barWrapColor: {type: String, default: 'transparent'},
      //滾動條顏色
      barColor: {type: String, default: 'rgba(0,0,0,.6)'},
      //圓角
      radius: {type: Number, default: 10},
      //滾動條距離內容的距離
      gap: {type: Number, default: 0},
    },
    data() {
      return {
        //  滾動距離
        scrollTop: 0,
      };
    },
    computed: {
      //  滾動步長  一次滾動多少的距離
      scrollStep() {
        return this.lineHeight / this.speed;
        // return 5;
      },
      //  內容的高度
      scrollHeight() {
        return this.length * this.lineHeight;
      },
      //  可滾動的高度
      useableDistance() {
        return this.scrollHeight - this.height;
      },
      //  滾動內容的樣式
      scrollContentStyles() {
        if (this.scrollHeight < this.height) this.scrollTop = 0;
        return {
          transform: `translateY(${this.scrollTop}px)`,
          paddingRight: `${this.gap}px`,
        };
      },
      //  滾動條外框樣式
      scrollWrapStyle() {
        return {
          width: `${this.barWidth}px`,
          backgroundColor: this.barWrapColor,
          borderRadius: `${this.radius}px`,
        };
      },
      //  滾動條樣式
      scrollBarStyle() {
        this.translateY = (-this.scrollTop * this.height) / this.scrollHeight;

        let translateY = `translateY(${this.translateY}px)`;

        return {
          height: `${this.scrollBarHeight}px`,
          transform: translateY,
          msTransform: translateY,
          webkitTransform: translateY,
          backgroundColor: this.barColor,
          borderRadius: `${this.radius}px`
        };
      },
      //  滾動條高度
      scrollBarHeight() {
        let barHeight = (this.height * this.height) / (this.length * this.lineHeight);
        if (barHeight >= this.height) return 0;
        return barHeight;
      },
    },
    methods: {
      //  滾輪事件處理
      wheelEventHandle(event) {
        let {deltaY} = event;

        if (deltaY > 0) this.prevScorllHandle();
        if (deltaY < 0) this.nextScorllHandle();
      },
      //  向上滾動
      prevScorllHandle() {
        if (-this.useableDistance < this.scrollTop) {
          this.scrollTop -= this.scrollStep;
        }
      },
      //  向下滾動
      nextScorllHandle() {
        if (this.scrollTop < 0) {
          this.scrollTop += this.scrollStep;
        }
      },
      //滑塊點選事件
      clickBarHandler(event) {
        event.stopImmediatePropagation();
        document.addEventListener('mousemove', this.mouseMoveDocumentHandler, false);
        document.addEventListener('mouseup', this.mouseUpDocumentHandler, false);
        document.onselectstart = () => false;

        this.yMove = (
          event.currentTarget.offsetHeight - (event.clientY - event.currentTarget.getBoundingClientRect().top)
        );
      },
      //  滑鼠移動事件
      mouseMoveDocumentHandler(event) {
        let prevPage = this.yMove;

        if (!prevPage) return;
        let thumbClickPosition = this.$refs['bar'].offsetHeight - prevPage;
        this.barMoveHandle(event, this.$el, thumbClickPosition);
      },
      //  滑鼠擡起來的事件
      mouseUpDocumentHandler() {
        this.yMove = 0;
        document.removeEventListener('mousemove', this.mouseMoveDocumentHandler);
        document.onselectstart = null;
      },
      //滑塊外框事件
      clickBarWrapHandler(event) {
        let thumbHalf = this.$refs['bar'].offsetHeight / 2;
        this.barMoveHandle(event, event.target, thumbHalf);
      },
      //  滑塊移動處理
      barMoveHandle(event, dom, position) {
        let offset = Math.abs(dom.getBoundingClientRect()['top'] - event.clientY);
        let thumbPositionPercentage = (offset - position) * 100 / this.$el.offsetHeight;
        let scrollTop = -(thumbPositionPercentage * this.scrollHeight / 100);

        if (-scrollTop >= this.useableDistance) {
          return this.scrollTop = -this.useableDistance
        } else if (scrollTop >= 0) {
          return this.scrollTop = 0;
        }
        this.scrollTop = scrollTop;
      },
      //  如果有iframe 也需要處理
      iframeDocumentHandle() {
        let iframe = document.getElementsByTagName('iframe');

        if (iframe) {
          for (let i = 0; i < iframe.length; i++) {
            let iframeDocument = iframe[i].contentWindow.document;
            iframeDocument.addEventListener('mouseup', this.mouseUpDocumentHandler, false);
          }
        }
      }
    },

    destroyed() {
      document.removeEventListener('mouseup', this.mouseUpDocumentHandler);
    },
    mounted() {
      this.iframeDocumentHandle();
    }
  };
</script>
<style lang="scss"
  rel="stylesheet/scss"
  scoped>
  .v-scroll-bar {
    width: 100%;
    overflow: hidden;
    position: relative;
    &:hover .autoHide {
      opacity: 1;
    }
    .autoHide {
      opacity: 0;
      transition: all 200ms;
    }
    .scroll-bar-wrap {
      position: absolute;
      top: 0;
      right: 0;
      height: 100%;
      overflow: hidden;
      cursor: pointer;
      .scroll-bar {
        width: 100%;
        cursor: ns-resize;
      }
    }
  }
</style>