Vue3 draggable left and right panel split component implementation

Vue3 draggable left and right panel split component implementation

Recently, when using vue, I encountered a requirement to realize that the left and right divs can be adjusted in width by dragging the middle part. This article will organize it and share it with you. The details are as follows:

Rendering

Breaking down components

Use flex layout as a whole

Left Panel

  • The specific content of the panel is passed in through the slot named slot.
  • The title is passed in through prop
  • Draggable. To ensure that the content style is not destroyed by dragging, set the maximum/minimum value for the width of the panel.

Right panel

  • The width of the right panel changes with the width of the left panel. Note that the width of the content is automatically adapted using flex-auto.
  • Need to be adapted to mobile devices.
  • Adaptive use of Tailwind media queries

Input parameter decomposition

props

  • @param {Number} maxWidth Maximum width
  • @param {Number} minWidth minimum width
  • @param {String} leftTitle left title
  • @param {String} rightTitle Right title?
  • @param {Boolean} storeReage whether to store with localstorege

slots

  • left-content {Element} left content
  • right-content {Element} right content

Specific implementation

How to drag?

Add a hidden box between the left and right panels, and hide this box in box-shadow. Specific events are implemented in this div

<div id="line" class="w-2 cursor-move hidden md4:block"onMousedown={hnadleMouseDown}>
</div>

Event Listening

    const hnadleMouseDown = (evt: MouseEvent) => {
      /* Get the starting point and store it*/
      let { pageX, pageY } = evt;
      basePosition.pageX = pageX;
      basePosition.pageY = pageY;
      /* Listen for mouse movement events*/
      document.addEventListener("mousemove", handleMouseMove);
      document.addEventListener("mouseup", handleMouseUp);
    };
    const handleMouseMove = evt => {
      /* Prevent browser default events from triggering the browser's gesture function*/
      evt.preventDefault();
      /* Set the timer to prevent DOM from reflowing multiple times*/
      clearTimeout(timer.value);
      timer.value = setTimeout(() => {
        let { pageX } = evt;
        const baseDiv = document.querySelector(".right-border-shadow");
        /* Process width, whether it is between the maximum/minimum value*/
        let baseWidth: Number | undefined =
          Number(baseDiv?.clientWidth) + (pageX - basePosition.pageX);
        baseWidth =
          baseWidth > Number(props?.maxWidth) ? props.maxWidth : baseWidth;
        baseWidth =
          Number(baseWidth) < Number(props?.minWidth)
            ? props.minWidth
            : baseWidth;
        baseDiv?.setAttribute("style", `width:${baseWidth}px`);
        /* emit width changed event */
        ctx.emit("drugend");
        /* Store to store */
        setStore(baseWidth);
      }, 50);
    };
    const handleMouseUp = evt => {
      /* After dragging ends, cancel event listening and emit the final width*/
      const width = document.querySelector(".right-border-shadow")?.clientWidth;
      document.removeEventListener("mousemove", handleMouseMove);
      document.removeEventListener("mouseup", handleMouseUp);
      ctx.emit("drugend", width);
    };

Width processing

style={`width:${
            store.get("split-width")
              ? store.get("split-width")
              : props.minWidth
              ? props.minWidth
              : 384
          }px`}

optimization

Manually change the browser window width

nextTick(() => {
        ctx.emit("load", ctx);
        MutationObserver = window.MutationObserver;
        if (MutationObserver) {
          /* Monitor browser window changes, this API is required in some cases */
          mo = new MutationObserver(function() {
            const __wm = document.querySelector("#rezie-id");
            // Re-call __canvasWM only when the __wm element changes
            if (!__wm) {
              //Avoid triggering mo.disconnect() all the time;
              mo = null;
              ctx.emit("resize");
            }
          });
          mo.observe(document.querySelector("#rezie-id"), {
            attributes: true,
            subtree: true,
            childList: true,
          });
        }
      });

Not effective, please advise

Bugs

An error occurred when getting the slot element node of the child element in the onMounted hook of the parent component. The value is null. The current solution is to throw a load event in the onMounted hook of the child component, and the parent component uses onLoad to handle the subsequent logic.

git address

Warehouse address preview address

This is the end of this article about the implementation of the Vue3 draggable left and right panel split component. For more related Vue3 draggable left and right split panel content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • vue-Split realizes panel segmentation
  • Vue implements drag and slide split panel
  • Vue split panel encapsulation implementation record

<<:  Troubleshooting and solutions for MySQL auto-increment ID oversize problem

>>:  How to install pyenv under Linux

Recommend

Install Linux using VMware virtual machine (CentOS7 image)

1. VMware download and install Link: https://www....

How to create Baidu dead link file

There are two types of dead link formats defined b...

Sample code for implementing interface signature with Vue+Springboot

1. Implementation ideas The purpose of interface ...

HTML basics summary recommendation (paragraph)

HTML Paragraph Paragraphs are defined by the <...

Detailed explanation of the usage of compose function and pipe function in JS

Table of contents compose function Array.prototyp...

Convert XHTML CSS pages to printer pages

In the past, creating a printer-friendly version ...

The principles and defects of MySQL full-text indexing

MySQL full-text index is a special index that gen...

...

JavaScript timer to achieve seamless scrolling of pictures

This article shares the specific code of JavaScri...

A brief discussion of several browser compatibility issues encountered

background Solving browser compatibility issues i...

Detailed Explanation of JavaScript Framework Design Patterns

Table of contents mvc mvp mvvm The source of Vue ...

A brief discussion on the VUE uni-app life cycle

Table of contents 1. Application Lifecycle 2. Pag...

How to allow external network access to mysql and modify mysql account password

The root account of mysql, I usually use localhos...

A brief introduction to mysql mycat middleware

1. What is mycat A completely open source large d...

How to use Docker+DockerCompose to encapsulate web applications

Table of contents Technology Stack Backend build ...