index.vue 2.88 KB
<template>
  <div ref :style="{ cursor, userSelect}" class="vue-splitter-container clearfix" @mouseup="onMouseUp" @mousemove="onMouseMove">
    <pane class="splitter-pane splitter-paneL" :split="split" :style="{ [type]: percent+'%'}">
      <slot name="paneL"></slot>
    </pane>
    <resizer :style="{ [resizeType]: percent+'%'}" :split="split" :onMouseDown="onMouseDown" @click="onClick"></resizer>
    <pane class="splitter-pane splitter-paneR" :split="split" :style="{ [type]: 100-percent+'%'}">
      <slot name="paneR"></slot>
    </pane>
  </div>
</template>

<script>
  import Resizer from './Resizer';
  import Pane from './Pane';
  export default {
    name: 'splitPane',
    components: { Resizer, Pane },
    props: {
      margin: {
        type: Number,
        default: 10
      },
      split: {
        validator(value) {
          return ['vertical', 'horizontal'].indexOf(value) >= 0
        },
        required: true
      }
    },
    data() {
      return {
        active: false,
        hasMoved: false,
        height: null,
        percent: 50,
        type: this.split === 'vertical' ? 'width' : 'height',
        resizeType: this.split === 'vertical' ? 'left' : 'top'
      }
    },
    computed: {
      userSelect() {
        return this.active ? 'none' : ''
      },
      cursor() {
        return this.active ? 'col-resize' : ''
      }
    },
    methods: {
      onClick() {
        if (!this.hasMoved) {
          this.percent = 50;
          this.$emit('resize');
        }
      },
      onMouseDown() {
        this.active = true;
        this.hasMoved = false;
      },
      onMouseUp() {
        this.active = false;
      },
      onMouseMove(e) {
        if (e.buttons === 0 || e.which === 0) {
          this.active = false;
        }
        if (this.active) {
          let offset = 0;
          let target = e.currentTarget;
          if (this.split === 'vertical') {
            while (target) {
              offset += target.offsetLeft;
              target = target.offsetParent;
            }
          } else {
            while (target) {
              offset += target.offsetTop;
              target = target.offsetParent;
            }
          }

          const currentPage = this.split === 'vertical' ? e.pageX : e.pageY;
          const targetOffset = this.split === 'vertical' ? e.currentTarget.offsetWidth : e.currentTarget.offsetHeight;
          const percent = Math.floor(((currentPage - offset) / targetOffset) * 10000) / 100;
          if (percent > this.margin && percent < 100 - this.margin) {
            this.percent = percent;
          }
          this.$emit('resize');
          this.hasMoved = true;
        }
      }
    }
  }
</script>

<style scoped>
.clearfix:after {
  visibility: hidden;
  display: block;
  font-size: 0;
  content: " ";
  clear: both;
  height: 0;
}

.vue-splitter-container {
  height: 100%;
  /*display: flex;*/
  position: relative;
}
</style>