split.vue 5.78 KB
<template>
  <div ref="outerWrapper" :class="wrapperClasses">
    <div v-if="isHorizontal" :class="`${prefix}-horizontal`">
      <div :style="{right: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'left-pane']"><slot name="left"/></div>
      <div :class="`${prefix}-trigger-con`" :style="{left: `${offset}%`}" @mousedown="handleMousedown">
        <slot name="trigger">
          <trigger mode="vertical"/>
        </slot>
      </div>
      <div :style="{left: `${offset}%`}" :class="[`${prefix}-pane`, 'right-pane']"><slot name="right"/></div>
    </div>
    <div v-else :class="`${prefix}-vertical`">
      <div :style="{bottom: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'top-pane']"><slot name="top"/></div>
     <div :class="`${prefix}-trigger-con`" :style="{top: `${offset}%`}" @mousedown="handleMousedown">
        <slot name="trigger">
          <trigger mode="horizontal"/>
        </slot>
      </div>
      <div :style="{top: `${offset}%`}" :class="[`${prefix}-pane`, 'bottom-pane']"><slot name="bottom"/></div>
    </div>
  </div>
</template>

<script>
import { oneOf } from '../../utils/assist';
import { on, off } from '../../utils/dom';
import Trigger from './trigger.vue';
export default {
    name: 'Split',
    components: {
        Trigger
    },
    props: {
        value: {
            type: [Number, String],
            default: 0.5
        },
        mode: {
            validator (value) {
                return oneOf(value, ['horizontal', 'vertical']);
            },
            default: 'horizontal'
        },
        min: {
            type: [Number, String],
            default: '40px'
        },
        max: {
            type: [Number, String],
            default: '40px'
        }
    },
  /**
   * Events
   * @on-move-start
   * @on-moving 返回值:事件对象,但是在事件对象中加入了两个参数:atMin(当前是否在最小值处), atMax(当前是否在最大值处)
   * @on-move-end
   */
    data () {
        return {
            prefix: 'ivu-split',
            offset: 0,
            oldOffset: 0,
            isMoving: false
        };
    },
    computed: {
        wrapperClasses () {
            return [
                `${this.prefix}-wrapper`,
                this.isMoving ? 'no-select' : ''
            ];
        },
        isHorizontal () {
            return this.mode === 'horizontal';
        },
        anotherOffset () {
            return 100 - this.offset;
        },
        valueIsPx () {
            return typeof this.value === 'string';
        },
        offsetSize () {
            return this.isHorizontal ? 'offsetWidth' : 'offsetHeight';
        },
        computedMin () {
            return this.getComputedThresholdValue('min');
        },
        computedMax () {
            return this.getComputedThresholdValue('max');
        }
    },
    methods: {
        px2percent (numerator, denominator) {
            return parseFloat(numerator) / parseFloat(denominator);
        },
        getComputedThresholdValue (type) {
            let size = this.$refs.outerWrapper[this.offsetSize];
            if (this.valueIsPx) return typeof this[type] === 'string' ? this[type] : size * this[type];
            else return typeof this[type] === 'string' ? this.px2percent(this[type], size) : this[type];
        },
        getMin (value1, value2) {
            if (this.valueIsPx) return `${Math.min(parseFloat(value1), parseFloat(value2))}px`;
            else return Math.min(value1, value2);
        },
        getMax (value1, value2) {
            if (this.valueIsPx) return `${Math.max(parseFloat(value1), parseFloat(value2))}px`;
            else return Math.max(value1, value2);
        },
        getAnotherOffset (value) {
            let res = 0;
            if (this.valueIsPx) res = `${this.$refs.outerWrapper[this.offsetSize] - parseFloat(value)}px`;
            else res = 1 - value;
            return res;
        },
        handleMove (e) {
            let pageOffset = this.isHorizontal ? e.pageX : e.pageY;
            let offset = pageOffset - this.initOffset;
            let outerWidth = this.$refs.outerWrapper[this.offsetSize];
            let value = this.valueIsPx ? `${parseFloat(this.oldOffset) + offset}px` : (this.px2percent(outerWidth * this.oldOffset + offset, outerWidth));
            let anotherValue = this.getAnotherOffset(value);
            if (parseFloat(value) <= parseFloat(this.computedMin)) value = this.getMax(value, this.computedMin);
            if (parseFloat(anotherValue) <= parseFloat(this.computedMax)) value = this.getAnotherOffset(this.getMax(anotherValue, this.computedMax));
            e.atMin = this.value === this.computedMin;
            e.atMax = this.valueIsPx ? this.getAnotherOffset(this.value) === this.computedMax : this.getAnotherOffset(this.value).toFixed(5) === this.computedMax.toFixed(5);
            this.$emit('input', value);
            this.$emit('on-moving', e);
        },
        handleUp () {
            this.isMoving = false;
            off(document, 'mousemove', this.handleMove);
            off(document, 'mouseup', this.handleUp);
            this.$emit('on-move-end');
        },
        handleMousedown (e) {
            this.initOffset = this.isHorizontal ? e.pageX : e.pageY;
            this.oldOffset = this.value;
            this.isMoving = true;
            on(document, 'mousemove', this.handleMove);
            on(document, 'mouseup', this.handleUp);
            this.$emit('on-move-start');
        }
    },
    watch: {
        value () {
            this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100;
        }
    },
    mounted () {
        this.$nextTick(() => {
            this.offset = (this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000 / 100;
        });
    }
};
</script>