可拖动中分线左右布局

在Web开发中,经常会遇到需要实现左右布局的需求,而有时用户希望能够自由调整左右两列的宽度,这就是可拖动中分线左右布局的用武之地。这种布局不仅可以提供更灵活的界面设计,还增强了用户体验。在本文中,我们将探讨可拖动中分线左右布局的原理和过程,并提供示例代码,包括HTML、Vue组件和React组件。

原理和过程

可拖动中分线左右布局的原理相对简单,主要涉及到HTML、CSS和JavaScript。以下是其基本原理和过程:

  1. HTML结构:首先,我们需要创建一个HTML结构,其中包括左侧列、中分线和右侧列的元素。这些元素将在布局中占据不同的区域。

  2. CSS样式:我们使用CSS来定义布局的外观和样式。通常,左侧和右侧列会具有相同的样式,而中分线可能会有一个特定的样式以区分它。

  3. JavaScript交互:JavaScript的作用是使中分线可以拖动,并根据用户的拖动来动态调整左右列的宽度。我们需要监听鼠标事件,当用户按下鼠标并拖动中分线时,计算新的宽度,并将其应用到左右列上。

  4. 交互结束:当用户释放鼠标按钮时,拖动操作结束,停止监听鼠标事件。

HTML示例

以下是一个简单的HTML示例,演示了可拖动中分线左右布局的基本结构:

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>左右联动布局</title>
    <style>
      /* 设置容器和左右列的样式 */
      .container {
        display: flex;
        height: 100vh;
      }

      .left-column,
      .right-column {
        flex-grow: 1;
        overflow: auto;
        border: 1px solid #ddd;
        padding: 10px;
        /* transition: width 0.2s; */
      }

      /* 设置中分线的样式 */
      .splitter {
        width: 10px;
        cursor: col-resize;
        background-color: #ccc;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="left-column">
        <!-- 左侧内容 -->
        <h2>左侧列</h2>
        <p>这是左侧列的内容。</p>
      </div>
      <div class="splitter" id="splitter"></div>
      <div class="right-column">
        <!-- 右侧内容 -->
        <h2>右侧列</h2>
        <p>这是右侧列的内容。</p>
      </div>
    </div>

    <script>
      const splitter = document.getElementById("splitter");
      const leftColumn = document.querySelector(".left-column");
      const rightColumn = document.querySelector(".right-column");
      const container = document.querySelector(".container");

      let isResizing = false;
      let initialX = 0;
      let initialLeftWidth = 0;

      splitter.addEventListener("mousedown", (e) => {
        isResizing = true;
        initialX = e.clientX;
        initialLeftWidth = leftColumn.offsetWidth;

        document.addEventListener("mousemove", resize);
        document.addEventListener("mouseup", stopResize);

        e.preventDefault();
      });

      function resize(e) {
        if (!isResizing) return;

        const containerRect = container.getBoundingClientRect();
        const offsetX = e.clientX - initialX;
        const newLeftWidth = initialLeftWidth + offsetX;
        const newRightWidth = containerRect.width - newLeftWidth;

        leftColumn.style.width = newLeftWidth + "px";
        rightColumn.style.width = newRightWidth + "px";
      }

      function stopResize() {
        isResizing = false;

        document.removeEventListener("mousemove", resize);
        document.removeEventListener("mouseup", stopResize);
      }
    </script>
  </body>
</html>

Vue组件示例

以下是一个使用Vue 3的setup语法和TypeScript编写的可拖动中分线左右布局的示例:

html 复制代码
<template>
    <div class="tow-container" ref="containerRef">
        <div class="left-column" ref="leftColumn">
            <slot name="left"></slot>
        </div>
        <div class="splitter" ref="splitter" @mousedown="startResize"></div>
        <div class="right-column" ref="rightColumn">
            <slot name="right"></slot>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const leftColumn = ref<HTMLElement | null>(null)
const splitter = ref<HTMLElement | null>(null)
const rightColumn = ref<HTMLElement | null>(null)
const containerRef = ref<HTMLElement | null>(null)
const isResizing = ref(false)
const initialX = ref(0)
const initialLeftWidth = ref(0)

const startResize = (e: MouseEvent) => {
    isResizing.value = true
    initialX.value = e.clientX
    initialLeftWidth.value = leftColumn.value?.offsetWidth || 0

    document.addEventListener('mousemove', resize)
    document.addEventListener('mouseup', stopResize)

    e.preventDefault()
}

const resize = (e: MouseEvent) => {
    if (!isResizing.value) return

    const containerRect = containerRef.value!.getBoundingClientRect()
    const offsetX = e.clientX - initialX.value
    const newLeftWidth = initialLeftWidth.value + offsetX
    const newRightWidth = containerRect?.width ? containerRect.width - newLeftWidth : 0

    // 使用 requestAnimationFrame 来平滑调整宽度
    requestAnimationFrame(() => {
        leftColumn.value!.style.width = newLeftWidth + 'px'
        rightColumn.value!.style.width = newRightWidth + 'px'
    })
}

const stopResize = () => {
    isResizing.value = false

    document.removeEventListener('mousemove', resize)
    document.removeEventListener('mouseup', stopResize)
}
</script>

<style scoped>
/* 设置容器和左右列的样式 */
.tow-container {
    display: flex;
    height: 100%;
    width: 100%;
}

.left-column,
.right-column {
    width: 50%;
    flex-grow: 1;
    overflow: auto;
    border: 1px solid #ddd;
    padding: 10px;
    transition: width 0.3s;
}

/* 设置中分线的样式 */
.splitter {
    width: 4px;
    cursor: col-resize;
    background-color: #ccc;
}
</style>

React组件示例

以下是一个使用React的可拖动中分线左右布局的示例:

jsx 复制代码
import React, { useRef, useState } from "react";

function DraggableSplitLayout({ children }) {
  const leftColumnRef = useRef(null);
  const splitterRef = useRef(null);
  const rightColumnRef = useRef(null);
  const containerRef = useRef(null);
  const [isResizing, setIsResizing] = useState(false);
  const [initialX, setInitialX] = useState(0);
  const [initialLeftWidth, setInitialLeftWidth] = useState(0);

  const startResize = (e) => {
    setIsResizing(true);
    setInitialX(e.clientX);
    setInitialLeftWidth(leftColumnRef.current.offsetWidth);

    document.addEventListener("mousemove", resize);
    document.addEventListener("mouseup", stopResize);

    e.preventDefault();
  };

  const resize = (e) => {
    if (!isResizing) return;

    const offsetX = e.clientX - initialX;
    const newLeftWidth = initialLeftWidth + offsetX;

    leftColumnRef.current.style.width = newLeftWidth + "px";

    requestAnimationFrame(() => {
      const containerRect = containerRef.current.getBoundingClientRect();
      const newRightWidth = containerRect.width - newLeftWidth;
      rightColumnRef.current.style.width = newRightWidth + "px";
    });
  };

  const stopResize = () => {
    setIsResizing(false);

    document.removeEventListener("mousemove", resize);
    document.removeEventListener("mouseup", stopResize);
  };

  return (
    <div className="container" ref={containerRef}>
      <div className="left-column" ref={leftColumnRef}>
        {children.left}
      </div>
      <div className="splitter" ref={splitterRef} onMouseDown={startResize}></div>
      <div className="right-column" ref={rightColumnRef}>
        {children.right}
      </div>
    </div>
  );
}

export default DraggableSplitLayout;

结论

可拖动中分线左右布局是一种有用的Web布局方式,可以为用户提供更灵活的界面设计。无论你使用HTML、Vue还是React,通过适当的HTML结构、CSS样式和JavaScript交互,你都可以实现这一功能。希望这个示例和解释对你有所帮助,可以帮助你在项目中创建出更具交互性和灵活性的布局。

相关推荐
Мартин.3 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
一 乐4 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
昨天;明天。今天。4 小时前
案例-表白墙简单实现
前端·javascript·css
数云界4 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd4 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常4 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer4 小时前
Vite:为什么选 Vite
前端
小御姐@stella4 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing4 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing4 小时前
WebGL在低配置电脑的应用
javascript