首页
/ Element Plus Splitter 分割面板组件完整指南:拖拽布局、折叠与懒加载模式深度解析

Element Plus Splitter 分割面板组件完整指南:拖拽布局、折叠与懒加载模式深度解析

2026-09-10 18:55:27作者:平淮齐Percy

Splitter 是 Element Plus 提供的一款布局分割组件(beta 状态),它可以将容器区域按水平或垂直方向划分为多个面板,并通过拖拽分隔条自由调整各面板大小,同时支持面板折叠、最小/最大尺寸约束与懒更新等能力。读完本文,你将掌握 el-splitterel-splitter-panel 的全部配置项、事件用法、插槽与暴露方法,并能结合源码理解其尺寸分配、拖拽边界与折叠恢复的底层实现。

Splitter 组件概览

Splitter 的核心设计是一对一的父子结构:ElSplitter 作为容器负责整体布局与拖拽状态管理,ElSplitterPanel 作为面板承载具体内容。在 packages/components/splitter/index.ts 中可以看到,ElSplitter 通过 withInstall(Splitter, { SplitPanel }) 注册,因此既可以使用 <el-splitter><el-splitter-panel /></el-splitter> 的组合写法,也可以单独引入 ElSplitterElSplitterPanel;两个组件均已接入全局组件注册表(见 packages/element-plus/component.ts 中的 ElSplitter, ElSplitterPanel 导出)。

从源码结构看,splitter 模块由容器组件 splitter.vue、面板组件 split-panel.vue、分隔条组件 split-bar.vue 以及四个逻辑 hooks(useContainerusePaneluseResizeuseSize)组成,职责划分清晰:容器管状态、面板管尺寸、分隔条管交互。

基础用法:自动均分与手动指定尺寸

未传入任何默认尺寸时,Splitter 会依据面板数量自动均分空间。以下是最基础的用法:

<template>
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter>
      <el-splitter-panel size="30%">
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel :min="200">
        <div class="demo-panel">2</div>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

<style scoped>
.demo-panel {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}
</style>

(完整示例见 docs/examples/splitter/basic.vue

示例中第一个面板通过 size="30%" 指定了初始宽度,第二个面板通过 :min="200" 约束最小宽度为 200px。需要注意:Splitter 需要一个确定尺寸的父容器,示例中通过外层 divheight: 250px 提供高度约束,这也是实际项目中必须满足的前提。

关于未指定尺寸时的分配逻辑,可以看 useSize.ts 的实现:组件会把每个面板的 size 属性统一换算成百分比——30% 这类字符串百分比直接取数值,200px 这类像素值按 px / containerSize 换算,纯数字则视为像素值除以容器尺寸;随后将所有百分比求和,若总和小于 1 则把剩余空间平均分给未指定尺寸的面板(avgRest = (1 - totalPtg) / emptyCount),若总和大于 1 则整体等比缩放(scale = 1 / totalPtg)。这一逻辑保证了无论面板数量与初始配置如何,最终尺寸总和始终等于容器大小。

垂直布局

通过 layout="vertical" 可以将分割方向切换为垂直,分隔条变为上下拖拽,光标样式也会相应变为 ns-resize(见 split-bar.vuedraggerStyles 的计算逻辑):

<template>
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter layout="vertical">
      <el-splitter-panel>
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel>
        <div class="demo-panel">2</div>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

(完整示例见 docs/examples/splitter/vertical.vue

水平布局下拖拽偏移取 pageX 差值,垂直布局下取 pageY 差值(见 split-bar.vueonMouseMove)。Splitter 支持任意层级嵌套,例如在某个水平面板内部再嵌一个 layout="vertical" 的 Splitter,即可构造复杂的"田字格"工作区。

面板折叠(Collapsible)

配置 collapsible 后,分隔条两侧会出现折叠箭头按钮,点击即可将相邻面板快速收缩到 0。折叠能力针对每个面板独立配置,collapsible 同时作用于该面板两侧的分隔条。

官方折叠示例(见 docs/examples/splitter/collapsible.vue)演示了面板 1、2、4、5 均开启折叠、面板 3 嵌套垂直 Splitter 的复杂场景:

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

const isCollapsible = ref(true)
</script>

<template>
  <el-switch
    v-model="isCollapsible"
    active-text="enable"
    inactive-text="disable"
    inline-prompt
    class="mb-2"
  />
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter>
      <el-splitter-panel :collapsible="isCollapsible" min="50">
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel :collapsible="isCollapsible">
        <div class="demo-panel">2</div>
      </el-splitter-panel>
      <el-splitter-panel>
        <div class="demo-panel">3</div>
      </el-splitter-panel>
      <el-splitter-panel :collapsible="isCollapsible">
        <el-splitter layout="vertical">
          <el-splitter-panel :collapsible="isCollapsible">
            <div class="demo-panel">4</div>
          </el-splitter-panel>
          <el-splitter-panel :collapsible="isCollapsible">
            <div class="demo-panel">5</div>
          </el-splitter-panel>
        </el-splitter>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

源码层面,usePanel.ts 中的 getCollapsible 把布尔值展开为 { start: boolean, end: boolean } 两个方向的折叠开关,isCollapsible 则判断某条分隔条两侧是否具备可折叠条件:当前面板的 end 侧可折叠且尺寸大于 0,或下一个面板的 start 侧可折叠且当前面板有尺寸,两种情况都会显示折叠按钮。折叠切换的具体尺寸转移逻辑在 useResize.tsonCollapse 中实现:折叠时把当前面板尺寸转移给相邻面板并缓存原尺寸(cacheCollapsedSize),再次点击时按缓存值还原,并通过 clamp 保证还原尺寸不会超出两者总尺寸范围。

折叠按钮的默认图标来自 @element-plus/icons-vue:水平布局为左右箭头,垂直布局为上下箭头(见 split-bar.vue)。需要自定义按钮外观时,可使用面板暴露的 start-collapsibleend-collapsible 插槽。

禁用拖拽(resizable)

当任一面板设置 resizable=false 时,与之相邻的分隔条拖拽即被禁用——分隔条是否可拖取决于其左右(或上下)两个面板是否都允许调整。官方示例(见 docs/examples/splitter/disableDrag.vue)用开关控制中间面板的 resizable

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

const resizable = ref(false)
</script>

<template>
  <el-switch
    v-model="resizable"
    active-text="enable"
    inactive-text="disable"
    inline-prompt
    class="mb-2"
  />
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter>
      <el-splitter-panel>
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel :resizable="resizable">
        <div class="demo-panel">drag {{ resizable ? 'enable' : 'disable' }}</div>
      </el-splitter-panel>
      <el-splitter-panel>
        <div class="demo-panel">3</div>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

split-bar.vueonMousedown 中,if (!props.resizable) return 直接拦截了拖拽起点事件;同时光标样式变为 auto,分隔条类名会附加 is-disabled。值得注意的是,禁用拖拽并不影响折叠按钮,折叠仍可通过点击箭头触发。

面板尺寸:v-model:size 双向绑定

通过 v-model:size 可以读取并控制面板尺寸,尺寸支持像素与百分比两种单位。官方示例(见 docs/examples/splitter/size.vue)将第二个面板的实时尺寸渲染到面板内容中,并同时监听三个拖拽事件:

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

const size = ref(100)

const handleResizeStart = (index: number, sizes: number[]) => {
  console.log('resizeStart', index, sizes)
}

const handleResize = (index: number, sizes: number[]) => {
  console.log('resize', index, sizes)
}

const handleResizeEnd = (index: number, sizes: number[]) => {
  console.log('resizeEnd', index, sizes)
}
</script>

<template>
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter
      @resize-start="handleResizeStart"
      @resize-end="handleResizeEnd"
      @resize="handleResize"
    >
      <el-splitter-panel>
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel v-model:size="size" :max="200" :min="50">
        <div class="demo-panel">{{ size }}px</div>
      </el-splitter-panel>
      <el-splitter-panel>
        <div class="demo-panel">3</div>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

该示例同时展示了 minmax 的约束效果:面板初始 100px,拖拽时被限制在 50px 到 200px 之间。从 split-panel.ts 的定义看,sizeminmax 的类型均为 string | number,即 50"50px" 等价,"50%" 则以容器尺寸百分比生效。

尺寸约束在 useResize.ts 中落实:拖拽计算时依次校验起始面板与结束面板的 min/maxgetLimitSize 会把百分比换算成像素),任一方向越界都会把实际偏移量 mergedOffset 钳制到合法区间,保证面板永远不会被拖出边界。

懒加载模式(Lazy)

lazy 模式适用于面板内容较重、拖拽过程中不希望频繁重排的场景。开启后,拖拽时分隔条会跟随鼠标移动,但各面板的实际尺寸(以及 v-model:sizeresize 事件)只在拖拽结束时一次性更新。示例(见 docs/examples/splitter/lazy.vue)为三个面板同时开启折叠与懒模式:

<template>
  <div style="height: 250px; box-shadow: var(--el-border-color-light) 0px 0px 10px">
    <el-splitter lazy>
      <el-splitter-panel collapsible min="50">
        <div class="demo-panel">1</div>
      </el-splitter-panel>
      <el-splitter-panel collapsible>
        <div class="demo-panel">2</div>
      </el-splitter-panel>
      <el-splitter-panel collapsible>
        <div class="demo-panel">3</div>
      </el-splitter-panel>
    </el-splitter>
  </div>
</template>

其底层实现在 useResize.ts:拖拽过程中 onMoving 只把待提交的尺寸暂存进 updatePanelSizes 闭包,并借助 lazyOffset 让分隔条在视觉上先行移动(容器样式 --el-splitter-bar-offsetsplitter.vue 计算);onMoveEnd 时才真正执行 updatePanelSizes() 提交尺寸。同时 splitter.vue 在懒模式下不会触发 resize 事件,只在结束后触发 resizeEnd

另外,源码对"拖拽中途切换 lazy 开关"做了兜底:useResizewatch(lazy) 检测到开启状态变化时会主动派发一次 mouseup 事件结束当前拖拽(useResize.ts),避免状态悬空。

Splitter API 详解

Splitter Attributes

名称 说明 类型 默认值
layout 分割方向 ^[enum]'horizontal' | 'vertical' horizontal
lazy ^(2.11.0) 是否启用懒加载模式 ^[boolean] false

属性定义见 splitter.tslayout 通过 values 白名单约束取值,lazy 为纯布尔开关。

Splitter Events

名称 说明 类型
resize-start 开始拖拽某条分隔条时触发,index 为分隔条索引 ^[Function](index: number, sizes: number[]) => void
resize 拖拽过程中触发,index 为分隔条索引 ^[Function](index: number, sizes: number[]) => void
resize-end 拖拽结束时触发,index 为分隔条索引 ^[Function](index: number, sizes: number[]) => void
collapse ^(2.10.3) 面板被折叠或展开时触发,index 为分隔条索引,type 表示折叠方向 ^[Function](index: number, type: 'start' | 'end', sizes: number[]) => void

事件回调的第二个参数 sizes 是当前所有面板的像素尺寸数组,可用于持久化布局状态。事件在 splitter.ts 中声明,并由 splitter.vueonResizeStartonResizeonResizeEndonCollapsible 四个包装函数统一发出;其中 collapse 事件在拖拽结束、尺寸真正落定(nextTick 之后)才触发。

SplitterPanel API 详解

SplitterPanel Attributes

名称 说明 类型 默认值
size / v-model:size 面板尺寸(像素或百分比) ^[string] / ^[number] -
min 面板最小尺寸(像素或百分比) ^[string] / ^[number] -
max 面板最大尺寸(像素或百分比) ^[string] / ^[number] -
resizable 面板是否可被拖拽调整 ^[boolean] true
collapsible 面板是否可折叠 ^[boolean] false

属性默认值可对照 split-panel.tsresizable 默认 truecollapsible 默认 falsesize/min/max 不设默认值(缺省时按均分规则分配)。collapsibleusePanel.ts 中还会被展开为 { start, end } 两个方向分别判断。

SplitterPanel Events

名称 说明 类型
update:size 面板尺寸变化时触发 ^[Function](size: number) => void

update:sizev-model:size 配套使用,定义于 split-panel.ts

SplitterPanel Slots

名称 说明
default 面板默认内容
start-collapsible 起始侧折叠按钮的自定义内容
end-collapsible 结束侧折叠按钮的自定义内容

两个折叠插槽在 split-bar.vue 的模板中渲染,若不提供则使用内置的左右/上下箭头图标。

SplitterPanel Exposes

名称 说明 类型
splitterPanelRef ^(2.11.9) SplitterPanel 的 DOM 元素 ^[object]Ref<HTMLDivElement>

splitterPanelRef 自 2.11.9 起可用,用于在需要直接操作面板 DOM(如测量高度、绑定第三方库)的场景下获取元素引用。

源码级原理:拖拽与折叠的工作机制

尺寸计算管线

整个组件的尺寸状态流可概括为:面板通过 provide/inject 向容器注册(registerPanel,见 splitter.vuesplit-panel.vue 的上下文注入校验,面板脱离容器使用时会被 throwError 提示正确用法)→ useSize 将各面板 prop 换算为百分比并填充未分配空间 → pxSizes 映射为像素数组 → useResize 基于像素数组执行拖拽偏移与折叠操作。拖拽只改相邻两个面板的尺寸,其他面板保持不变,这保证了交互的局部性与性能。

拖拽交互细节

分隔条同时支持鼠标与触摸事件(mousedown/mousemove/mouseuptouchstart/touchmove/touchend,见 split-bar.vue),触摸场景设置了 touchAction: 'none' 防止页面滚动干扰。拖拽过程中容器还会渲染一层 el-splitter__mask 遮罩(见 splitter.vue),用于防止 iframe 等元素吞掉拖拽事件。当多个分隔条重叠时,useResizeonMoving 会向上回溯寻找最近的可拖拽索引(useResize.ts),适配嵌套场景下的命中判断。

最小/最大尺寸与折叠的交互

折叠与尺寸约束共享同一套限制逻辑:被折叠的面板尺寸为 0,再次展开时恢复到折叠前尺寸,但受 min/max 与相邻面板总尺寸的 clamp 约束,展开后的尺寸不会超过可分配范围。这一点与官方文档中"使用 min 属性可以防止折叠后再通过拖拽展开"的说明相呼应——折叠后面板处于 0 尺寸,若其 min 大于 0,拖拽恢复时会立刻被钳制到 min 值。

使用建议与注意事项

  1. 容器必须有确定尺寸:Splitter 依赖容器尺寸计算百分比,父元素需显式设置宽高,否则面板无法正确布局。
  2. 尺寸单位约定sizeminmax 支持 px% 后缀或裸数字(按像素处理),百分比换算依据 useSize.tsisPct/isPx/getPct/getPx 实现。
  3. 性能敏感场景启用 lazy:内容重、更新开销大的面板建议开启懒模式,把高频的 resize 计算收敛到拖拽结束的一次提交。
  4. 布局持久化:通过 @resize-endcollapse 事件获取的 sizes 数组可直接序列化保存,下次渲染时作为各面板的 size 初始值回填。
  5. 组件版本标注lazy 属性自 2.11.0 起可用,collapse 事件自 2.10.3 起可用,splitterPanelRef 自 2.11.9 起可用,使用前请确认依赖版本;整个组件当前仍标记为 beta(^(beta)),API 存在微调可能。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.16 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.83 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
932
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.95 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
606
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23