Vue custom component: center line split drag disk

Component effect:

Source code:
Create a new file named MiddleMoveLine.vue and introduce the declaration where it is used.

<template>
  <!-- Re-optimized the overall implementation logic...one disk is divided into two parts, A/B---
  You need to first understand the positioning layout [child absolute parent phase] --- child absolute positioning / parent relative positioning (the most commonly used combination) before you can understand the layout in this component
  In addition, z-index can only be set for positioned elements---not setting it is similar to stacking behavior. Those written first are suppressed below.

  usage: just nest

  <MiddleMoveLine :safe-distance="[50,50]" :percent-a="30">
    <template v-slot:paneA>
      <div style="background-color: #5ee012;width: 100%;height: 100%;font-size: 50px">I am the first panA</div>
    </template>

    <template v-slot:paneB>

      <MiddleMoveLine direction="y" :safe-distance="[50,50]" :percent-a="60">
        <template v-slot:paneA>
          <div style="background-color: #c512e0;width: 100%;height: 100%;font-size: 50px">I am the second panA</div>
        </template>

        <template v-slot:paneB>
          <div style="background-color: #c70b2c;width: 100%;height: 100%;font-size: 50px">I am the second panB</div>

        </template>
      </MiddleMoveLine>
    </template>
  </MiddleMoveLine>
  -->
  <div class="line-pane-view" :class="{cursor}" ref="line-pane" @mouseup="mouseUp" @mousemove="mouseMove">
    <div :class="[direction==='x'?'pane-ax':'pane-ay']" :style="paneABstyle[0]">
      <slot name="paneA"></slot>
    </div>
    <div class="middle-line active" ref="mouse-ctrl" :style="middleLineStyle"
         :class="[direction==='x'?'middle-line-x':'middle-line-y']"
         @mousedown="mouseD">
    </div>
    <div :class="[direction==='x'?'pane-bx':'pane-by']" :style="paneABstyle[1]">
      <slot :style="{'z-index':zIndex}" name="paneB"></slot>
    </div>
  </div>
</template>

<script>

export default {<!-- -->
  name: "MiddleMoveLine",
  props: {<!-- -->//Data passed by the parent component
    direction: {<!-- -->// Describes the direction and appearance of the dividing center line
      default: 'x' // x--the center line is divided into two parts A and B in the x direction on the x axis, that is, in the left and right directions.
    },
    safeDistance: {<!-- -->
      default: function () {<!-- -->
        return [30, 40]//A’s safety distance is 30px, B’s safety distance is 40px
      }
    },
    zIndex: {<!-- -->// The level of the second element. Because the second element often suppresses the first one, you may need to add this to change the level.
      default: 1
    },
    percentA: {<!-- -->
      default: 55//A accounts for 55%, B accounts for 45% = 1 - 50%
    },
  },
  data() {<!-- -->
    return {<!-- -->
      active: false,

      percentX: 20,// 20% midline x
      percentY: 10,// Used when the center line is y

      mouseX: 0,//The position of the mouse in line-pane-view coordinates
      mouseY: 0,
      parentWidth: 0,//The width and height of the parent element line-pane-view
      parentHeight: 0
    };
  },
  mounted() {<!-- -->
    this.percentX = this.percentA
    this.percentY = 100 - this.percentA
  },
  computed: {<!-- -->
    paneABstyle() {<!-- -->// Change the length and width of A and B through styles
      // x--The center line is divided in the left and right directions. At this time, A and B are related to each other. When moving the center line, the width of A and B should be changed.
      const x = this.percentX;
      const y = this.percentY;
      if (this.direction === 'x') {<!-- -->// Return the styles of A and B at the same time
        return [{<!-- -->['width']: x + '%'}, {<!-- -->['width']: 100 - x + '%'}]
      } else {<!-- -->
        return [{<!-- -->['height']: y + '%'}, {<!-- -->['height']: 100 - y + '%'},]
      }
    },
    middleLineStyle() {<!-- -->//The middle line also needs to be changed synchronously
      const left = this.percentX
      const top = this.percentY
      if (this.direction === 'x') {<!-- -->
        return {<!-- -->['left']: left + "%"}
      } else {<!-- -->
        return {<!-- -->['top']: top + "%"}
      }
    },
    cursor() {<!-- -->// Set the mouse dragging style according to whether it is activated or not
      return this.active ? (this.direction === 'x' ? 'row-resize' : 'col-resize') : ''
    },
  },
  methods: {<!-- -->
    mouseMove(e) {<!-- -->
      // The mouse is not pressed or not triggered
      if (e.buttons === 0 || e.which === 0) {<!-- -->
        this.active = false
      }
      if (!this.active) return;
      // console.log("Mouse movement:", e,"e.currentTarget:",e.currentTarget);
      const parentRect = e.currentTarget.getBoundingClientRect();
      let x = e.clientX - parentRect.left;

      let y = e.clientY - parentRect.top;
      const w = parentRect.width;
      const h = parentRect.height;
      const safeDistance = this.safeDistance

      // Judgment that Bu is within a safe distance, exception handling:
      x = x < safeDistance[0] ? safeDistance[0] : x
      x = x > (w - safeDistance[1]) ? (w - safeDistance[1]) : x
      y = y < safeDistance[0] ? safeDistance[0] : y
      y = y > (h - safeDistance[1]) ? (h - safeDistance[1]) : y

      this.mouseX = x
      this.mouseY = y
      this.parentWidth = w;
      this.parentHeight = h;
      console.log("Mouse movement: this.mouseX,Y", this.mouseX, this.mouseY, "this.parentWidth,H:", this.parentWidth, this.parentHeight);
      console.log("Mouse movement:left,top:", (this.mouseX / this.parentWidth) * 100 + "%", (this.mouseY / this.parentHeight) * 100 + "%");

      this.percentX = (x / w) * 100;
      this.percentY = (y / h) * 100;
      // You can send events to the parent component so that the parent component can handle the proportion of other components to adapt
      this.$emit('change-view-size', {<!-- -->x, y, w, h})

    },
    mouseUp() {<!-- -->
      console.log("Mouse released---event of the entire panel");
      if(this.active)
        this.active = false
    },
    //Mouse events on the center line
    mouseD() {<!-- -->
      console.log("Mouse pressed");
      if (!this.active)
        this.active = true
    },
  },
  watch: {<!-- -->
    // There is currently no need to dynamically change the initial proportion...
    // percentA(newVal, oldVal) {// The initial load in vue2 will not run (the data is not considered to have changed), and it can only run if the data is changed during operation // In vue3, it can run during initialization (see the vue3 official website for specific configuration)
    // // console.log("percentA has changed...", newVal, oldVal)
    // // this.percentX = newVal
    // // this.percentY = 100 - newVal
    // },
  }
}
;
</script>

<style scoped lang="scss">
.line-pane-view {<!-- -->
  width: 100%;
  height: 100%;
  position: relative; /*The son must be the same as the father---since the children are absolute, the father must be positioned to be trapped*/
  user-select: none;
}

.middle-line {<!-- -->
  /* Set the positioning method of the element to absolute positioning, positioning relative to the nearest positioning context */
  position: absolute;
  /* Set the box model to border-box, the width and height of the element include content, padding and border */
  //-moz-box-sizing: border-box; /* For Firefox browser */
  //-webkit-box-sizing: border-box; /* Applicable to WebKit core browsers (such as Chrome, Safari) */
  box-sizing: border-box; /* Standard writing method, suitable for most modern browsers */
  background-color: #0D0D0D;
  /* Set the opacity of the element to 0.1, with a value ranging from 0 (fully transparent) to 1 (fully opaque) */
  opacity: .1;
  /* Set the stacking order of elements to control the display priority of elements in the stacking order */
  z-index: 2;
  /* Set the background clipping method to padding-box, and the background is only drawn in the padding area */
  -moz-background-clip: padding; /* Applicable to Firefox browser */
  -webkit-background-clip: padding; /* Applicable to WebKit core browsers (such as Chrome, Safari) */
  background-clip: padding-box; /* Standard writing method, suitable for most modern browsers */
}


/*x--Midline left and right division */
.middle-line-x {<!-- -->
  width: 11px;
  height: 100%;
  margin-left: -5px;
  border-left: 5px solid rgba(255, 255, 255, 0);
  border-right: 5px solid rgba(255, 255, 255, 0);
  cursor: col-resize;
}

.middle-line-y {<!-- -->
  height: 11px;
  margin: -5px 0;
  border-top: 5px solid rgba(255, 255, 255, 0);
  border-bottom: 5px solid rgba(255, 255, 255, 0);
  cursor: row-resize;
  width: 100%;
}

// A represents top and left | B represents bottom and right
.pane-ay {<!-- -->
  position: absolute;
  top: 0; /*top --- when the center line is y*/
  width: 100%;
}

.pane-by {<!-- -->
  position: absolute;
  bottom: 0; /*bottom --- when the center line is y*/
  width: 100%;
  padding-top: 3px;
}

.pane-ax {<!-- -->
  position: absolute;
  left: 0; /*Left --- when the center line is x*/
  height: 100%;
  padding-right: 3px;
}

.pane-bx {<!-- -->
  position: absolute;
  right: 0; /*right --- when the center line is x*/
  height: 100%;
  padding-left: 3px;
}

.active:hover {<!-- -->
  background-color: mediumvioletred;

}

.middle-move-line.active {<!-- -->
  background-color: #575555;
}
</style>