3
\$\begingroup\$

I reviewed the code in Resizable split DIVs Vue.js, suggesting that the OP use computed properties and bound styles to simplify the code (at least reducing the need to use $refs to access DOM elements) . Below are two variants I devised. They are very similar, the main difference is that the second uses -1 for the initial values and ternary operators to check if the data values are set. Are those good improvements? What else would you change?

The user can drag the vertical bar, as well as the two horizontal bars to resize the containers.

Note: this appears to only work with Chrome, Opera, IE and Edge. There is something with the OPs original code that doesn't allow the dragging to work with FF or Safari. It appears clientX and clientY values are not set in those browsers, which maybe the same as this issue.

sample screenshot

Non-ternary approach with empty strings as initial values

var app = new Vue({
  el: '#app',
  data: {
    lrDividerPos: '',
    rtbDividerPos: '',
    ltbDividerPos: '',
  },
  computed: {
    bottomLeftStyle: function() {
      const style = {};
      if (this.lrDividerPos) {
        style.width = this.lrDividerPos + 'px';
      }
      if (this.ltbDividerPos) {
        style.height = (window.innerHeight - this.ltbDividerPos) + 'px';
        style.top = this.ltbDividerPos + 'px';
      }
      return style;
    },
    bottomRightStyle: function() {
      const style = {};
      if (this.lrDividerPos) {
        style.left = this.lrDividerPos + 'px';
        style.width = (window.innerWidth - this.lrDividerPos + 2) + 'px';
      }
      if (this.rtbDividerPos) {
        style.top = this.rtbDividerPos + 'px';
        style.height = (window.innerHeight - this.rtbDividerPos) + 'px';
      }
      return style;
    },
    leftDividerStyles: function() {
      if (this.lrDividerPos) {
        return {
          width: (this.lrDividerPos + 2) + 'px'
        };
      }
      return {};
    },
    ltbDividerStyles: function() {
      const style = {};
      if (this.lrDividerPos) {
        style.width = this.lrDividerPos + 2 + 'px';
      }
      if (this.ltbDividerPos) {
        style.top = this.ltbDividerPos + 'px';
      }
      return style;
    },
    lrDividerStyles: function() {
      if (this.lrDividerPos) {
        return {
          left: this.lrDividerPos + 'px'
        };
      }
      return {};
    },
    rtbDividerStyles: function() {
      const style = {};
      if (this.lrDividerPos) {
        style.left = this.lrDividerPos + 'px';
        style.width = (window.innerWidth - this.lrDividerPos + 2) + 'px';
      }
      if (this.rtbDividerPos) {
        style.top = this.rtbDividerPos + 'px';
      }
      return style;
    },
    topLeftStyle: function() {
      const style = {};
      if (this.ltbDividerPos) {
        style.height = this.ltbDividerPos + 'px';
      }
      if (this.lrDividerPos) {
        style.width = this.lrDividerPos + 'px';
      }
      return style;
    },
    topRightStyle: function() {
      const style = {};
      if (this.lrDividerPos) {
        style.left = this.lrDividerPos + 'px';
        style.width = (window.innerWidth - this.lrDividerPos + 2) + 'px';
      }
      if (this.rtbDividerPos) {
        style.height = this.rtbDividerPos + 'px';
      }
      return style;
    }
  },
  methods: {
    lrDividerDrag: function(e) {
      if (e.clientX) {
        this.lrDividerPos = e.clientX;
      }
    },
    ltbDividerDrag: function(e) {
      if (e.clientY) {
        this.ltbDividerPos = e.clientY;
      }
    },
    rtbDividerDrag: function(e) {
      if (e.clientY) {
        this.rtbDividerPos = e.clientY;
      }
    },
    dividerDragStart: function(e) {
      e.dataTransfer.setDragImage(new Image, 0, 0);
    }
  }
});
.text-area {
  margin: 10px;
}
.container {
  position: absolute;
  overflow: scroll;
  top: 0;
  left: 0;
  height: 50%;
  width: 50%;
}
.top-left {
  background-color: pink;
}

.top-right {
  background-color: lightgreen;
  left: 50%;
}

.bottom-left {
  background-color: lightblue;
  top: 50%;
}

.bottom-right {
  background-color: lightyellow;
  top: 50%;
  left: 50%;
}

.divider {
  position: absolute;
  background-color: black;
}

.left-right {
  width: 4px;
  height: 100%;
  top: 0;
  left: calc(50% - 4px / 2);
}

.right-top-bottom {
  width: 50%;
  height: 4px;
  top: calc(50% - 4px / 2);
  left: 50%;
}

.left-top-bottom {
  width: 50%;
  height: 4px;
  top: calc(50% - 4px / 2);
  left: 0;
}

.left-right:hover {
  cursor: col-resize;
}

.left-top-bottom:hover,
.right-top-bottom:hover {
  cursor: row-resize;
}

::-webkit-scrollbar {
  height: 0;
  width: 0;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <div>
    <div class="top-left container" :style="topLeftStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="top-right container" :style="topRightStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="bottom-left container" :style="bottomLeftStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="bottom-right container" :style="bottomRightStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>

    <div class="left-right divider" draggable="true" @dragstart="dividerDragStart" @drag="lrDividerDrag" :style="lrDividerStyles"></div>
    <div class="right-top-bottom divider" draggable="true" @drag="rtbDividerDrag" @dragstart="dividerDragStart" :style="rtbDividerStyles"></div>
    <div class="left-top-bottom divider" draggable="true" @drag="ltbDividerDrag" @dragstart="dividerDragStart" :style="ltbDividerStyles"></div>
  </div>
</div>

Ternary approach with negative initial values

var app = new Vue({
  el: '#app',
  data: {
    lrDividerPos: -1,
    rtbDividerPos: -1,
    ltbDividerPos: -1,
  },
  computed: {
    bottomLeftStyle: function() {
      return {
        height: this.ltbDividerPos > -1 ? (window.innerHeight - this.ltbDividerPos) + 'px' : '',
        top: this.ltbDividerPos > -1 ? this.ltbDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : ''
      };
    },
    bottomRightStyle: function() {
      return {
        height: this.rtbDividerPos > -1 ? (window.innerHeight - this.rtbDividerPos) + 'px' : '',
        left: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : '',
        top: this.rtbDividerPos > -1 ? this.rtbDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? (window.innerWidth - this.lrDividerPos + 2) + 'px' : ''
      };
    },
    leftDividerStyles: function() {
      return {
        width: this.lrDividerPos > -1 ? (this.lrDividerPos + 2) + 'px' : ''
      };
    },
    ltbDividerStyles: function() {
      return {
        top: this.ltbDividerPos > -1 ? this.ltbDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? this.lrDividerPos + 2 + 'px' : ''
      };
    },
    lrDividerStyles: function() {
      return {
        left: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : ''
      };
    },
    rtbDividerStyles: function() {
      return {
        left: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : '',
        top: this.rtbDividerPos > -1 ? this.rtbDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? (window.innerWidth - this.lrDividerPos + 2) + 'px' : ''
      };
    },
    topLeftStyle: function() {
      return {
        height: this.ltbDividerPos > -1 ? this.ltbDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : ''
      };
    },
    topRightStyle: function() {
      return {
        height: this.rtbDividerPos > -1 ? this.rtbDividerPos + 'px' : '',
        left: this.lrDividerPos > -1 ? this.lrDividerPos + 'px' : '',
        width: this.lrDividerPos > -1 ? (window.innerWidth - this.lrDividerPos + 2) + 'px' : ''
      };
    }
  },
  methods: {
    lrDividerDrag: function(e) {
      if (e.clientX) {
        this.lrDividerPos = e.clientX;
      }
    },
    ltbDividerDrag: function(e) {
      if (e.clientY) {
        this.ltbDividerPos = e.clientY;
      }
    },
    rtbDividerDrag: function(e) {
      if (e.clientY) {
        this.rtbDividerPos = e.clientY;
      }
    },
    dividerDragStart: function(e) {
      e.dataTransfer.setDragImage(new Image, 0, 0);
    }
  }
});
.text-area {
  margin: 10px;
}

.container {
  position: absolute;
  overflow: scroll;
  top: 0;
  left: 0;
  height: 50%;
  width: 50%;
}

.top-left {
  background-color: pink;
}

.top-right {
  background-color: lightgreen;
  left: 50%;
}

.bottom-left {
  background-color: lightblue;
  top: 50%;
}

.bottom-right {
  background-color: lightyellow;
  top: 50%;
  left: 50%;
}

.divider {
  position: absolute;
  background-color: black;
}

.left-right {
  width: 4px;
  height: 100%;
  top: 0;
  left: calc(50% - 4px / 2);
}

.right-top-bottom {
  width: 50%;
  height: 4px;
  top: calc(50% - 4px / 2);
  left: 50%;
}

.left-top-bottom {
  width: 50%;
  height: 4px;
  top: calc(50% - 4px / 2);
  left: 0;
}

.left-right:hover {
  cursor: col-resize;
}

.left-top-bottom:hover,
.right-top-bottom:hover {
  cursor: row-resize;
}

::-webkit-scrollbar {
  height: 0;
  width: 0;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <div>
    <div class="top-left container" :style="topLeftStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="top-right container" :style="topRightStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="bottom-left container" :style="bottomLeftStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>
    <div class="bottom-right container" :style="bottomRightStyle">
      <div class="text-area">
        <h3>Resize me using the black bars</h3>

        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
        in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
      </div>
    </div>

    <div class="left-right divider" draggable="true" @dragstart="dividerDragStart" @drag="lrDividerDrag" :style="lrDividerStyles"></div>
    <div class="right-top-bottom divider" draggable="true" @drag="rtbDividerDrag" @dragstart="dividerDragStart" :style="rtbDividerStyles"></div>
    <div class="left-top-bottom divider" draggable="true" @drag="ltbDividerDrag" @dragstart="dividerDragStart" :style="ltbDividerStyles"></div>
  </div>
</div>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.