SplitLayout使用方法
基础示例
推荐将 SplitLayout 置于顶级组件或者 CodeLayout 的 centerArea 插槽并设置宽高占满屏幕。
WARNING
本组件设计为占满父级容器,请为父级容器设置 position: relative;
样式以及一个确定的高度,否则组件将无法正确计算高度、无法正常显示。
要使用 SplitLayout ,有以下步骤:
- 需要导入组件.
- 定义插槽与内容:在组件中,内容是以“面板”为单位来组织的,所以需要添加面板数据,然后在插槽中渲染。
例如,下方是一个最简单的示例:
面板操作
定义:
- 网格:网格是一个容器,它可以包含多个面板,多个面板以Tab模式组成,但同时只能有一个显示的面板;或者可以是包含不同方向分割的子网格的父面板,父面板有横向与竖向两个布局方向,布局方向仅用于子网格,子面板以Tab模式显示。
- 面板:面板,内容是以“面板”为单位来组织的,面板是最终让你渲染内容的基本单元。用户对每个面板都可以进行拖动、关闭操作。
你可以向组件中添加你的面板,或者获取面板实例进行对应操作或者设置。
要操作 SplitLayout 组件,需要先获取它的实例,然后调用实例上的方法:
import { CodeLayoutSplitNInstance } from 'vue-code-layout';
//将 splitLayoutRef 变量通过 ref 属性绑定到 SplitLayout 组件上
const splitLayoutRef = ref<CodeLayoutSplitNInstance>();
获取根网格
组件提供了获取根网格方法:
const grid = splitLayoutRef.value.getRootGrid();
根网格方向
根网格布局方向默认是水平 ('horizontal'
)(布局方向仅用于子网格,子面板以Tab模式显示), 你也可以将其改为垂直 ('vertical'
)。
const grid = splitLayoutRef.value.getRootGrid();
grid.direction = 'vertical';
添加网格/面板
你可以向根中添加网格,例如,下面的代码向根中添加了一个网格:
const grid1 = grid.addGrid({
name: 'grid1',
visible: true,
size: 0,
});
网格方向默认与父级垂直,例如父级网格是水平 ('horizontal'
),则添加的子网格方向是垂直 ('vertical'
)。
获取到网格后,你可以在自定义网格中添加面板:
grid1.addPanel({
title: `Panel title`,
tooltip: `Panel Help`,
name: `datahelp`,
iconSmall: () => h(IconMarkdown),
});
注:面板的 name
属性必须保证唯一,但网格不需要。
获取面板
添加面板时 name
属性必须保证唯一,因此你可以使用name查询已添加的面板实例,并对其更改:
//获取面板并修改badge
const file1 = splitLayoutRef.value.getPanelByName('file1')
file1.badge = '3';
关闭面板
面板支持用户关闭操作。
关闭按钮
面板支持关闭按钮,在创建面板时指定关闭按钮,也可获取实例后修改属性:
const grid1 = grid.addGrid({
name: 'grid1',
visible: true,
size: 0,
closeType: 'close', //显示关闭按钮
});
//获取面板并修改 closeType
const file1 = splitLayoutRef.value.getPanelByName('file1')
file1.closeType = 'unSave'; //显示没有保存按钮
- unSave 显示一个圆点提示当前文件没有保存
- close 显示一个关闭按钮(x)
- none 没有关闭按钮(默认)
关闭处理
设置关闭按钮后,当用户点击关闭按钮时,会在顶级触发 panelClose
事件,你可以在其中处理自己的业务逻辑, 保存文件等等,可以异步执行关闭操作,完成后调用 resolve 删除面板,或者是调用 reject 取消删除面板。
//面板关闭回调
function onPanelClose(panel: CodeLayoutPanelInternal, resolve: () => void, reject: (e: any) => void) {
console.log('onPanelClose', panel.name);
resolve();
}
手动关闭
在代码中也可以手动调用面板实例上的 closePanel
函数手动执行关闭操作,此操作与用户点击关闭效果一致。
const file1 = splitLayoutRef.value.getPanelByName('file1')
file1.closePanel(); //手动关闭
网格禁止自动收缩
用户允许在网格之间拖拽面板,在默认情况下,当一个网格中所有的面板都被移除后,这个面板将进行自动收缩(移除自己),以为其他面板腾出空间。
const grid1 = grid.addGrid({
name: 'grid1',
visible: true,
size: 0,
noAutoShink: true,
});
如果你不希望自己手动添加的面板被收缩掉,可以在创建面板时指定禁止收缩,这样当网格为空时,不会被移除,并且渲染时会调用 tabEmptyContentRender 插槽,你可以在此插槽中渲染自定义内容。
获取当前激活的网格/面板
你有时候需要获取当前激活的网格/面板,例如保存用户当前正在编辑的文件,你可以通过 getActiveGird
获取当前激活的网格。
const grid = splitLayoutRef.value?.getActiveGird();
获取网格后,可以访问实例上的 activePanel
获取当前激活的面板。如果你在面板上绑定了自己的编辑器上下文,就可以调用它。
const panel = grid?.activePanel;
if (panel != null) {
panel.data.save(); //调用我的编辑器上下文中的保存方法
}
TIP
可以监听 SplitLayout 的 gridActive
事件来获取用户最新激活的面板。
标记、图标、标题、自定义操作
一个面板支持以下配置字段来控制一些信息的显示,它的显示位置如图所示:
你可以在创建时指定这些属性,也可以在创建后通过实例属性修改。
grid2.addPanel({
name: 'file1',
//标题文字
title: 'File name',
//鼠标悬浮时显示的工具提示
tooltip: 'File path',
//标记,推荐2个数字内
badge: '2',
//图标
iconSmall: () => h(IconFile),
//自定义操作,自定义操作会在面板激活时头部右侧以按钮形式显示
actions: [
{
name: 'test',
icon: () => h(IconSearch),
onClick() {},
},
{
name: 'test2',
icon: () => h(IconFile),
onClick() {},
},
]
});
面板菜单
面板可以自定义用户右键点击时的菜单,通过 panelContextMenu
事件显示菜单。
<template>
<SplitLayout
ref="splitLayoutRef"
@panelContextMenu="onPanelMenu"
>
<!--省略其他代码-->
</SplitLayout>
</template>
<script setup lang="ts">
//...省略其他代码
function onPanelMenu(panel: CodeLayoutPanelInternal, e: MouseEvent) {
e.stopPropagation();
e.preventDefault();
//这里使用 vue3-context-menu 显示菜单,你也可以使用你自己喜欢的菜单库
ContextMenuGlobal.showContextMenu({
x: e.x,
y: e.y,
items: [
{
label: "Menu of " + panel.name,
onClick: () => {
alert("You click a menu item");
}
},
],
});
}
</script>
自定义渲染面板头
自定义标签页头部
SplitLayout 支持自定义渲染标签页按钮,你可以自定义渲染某个部分,或者是全部自定义渲染。
您可以使用 tabItemRender
插槽渲染标签页条目,该插槽允许整个覆盖渲染。
如果只需要自定义渲染某些部分,可以导入默认的标签页组件 SplitTabItem
,它支持默认标签页的功能,但同时也允许你自定义 其中的某一部分。
<template>
<SplitLayout
ref="splitLayoutRef"
>
<!--省略其他代码-->
<template #tabItemRender="{ index, panel, active, onTabClick, onContextMenu }">
<SplitTabItem
:panel="(panel as CodeLayoutSplitNPanelInternal)"
:active="active"
@click="onTabClick"
@contextmenu="onContextMenu($event)"
>
<template #title>
<span :style="{ color: colors[panel.data] }">{{ panel.title }}</span>
</template>
<template #icon>
<MyIcon />
</template>
<template #badge>
<span class="badge">99+</span>
</template>
<template #close>
<MyCloseIcon />
</template>
</SplitTabItem>
</template>
</SplitLayout>
</template>
<script setup lang="ts">
import { SplitLayout, SplitTabItem } from 'vue-code-layout';
//...省略其他代码
</script>
自定义标签页尾部
您可以使用 tabHeaderExtraRender
插槽渲染标签页尾部区域,例如,下方的示例在标签页尾部增加了一个“添加面板”的按钮。
<template>
<SplitLayout
ref="splitLayoutRef"
>
<!--省略其他代码-->
<template #tabHeaderExtraRender="{ grid }">
<button @click="onAddPanel(grid)">+ 添加面板</button>
</template>
</SplitLayout>
</template>
保存与加载数据
SplitLayout支持你保存用户拖拽后的布局至JSON数据中,在下一次进入后重新从JSON数据加载恢复原布局。
SplitLayout 支持 canLoadLayout
、canSaveLayout
两个事件,事件回调中会返回当前组件实例,你可以在事件回调中执行加载与保存操作,也可以在其他时机通过调用组件实例上的 loadLayout
, saveLayout
函数自由控制加载与保存操作。
<template>
<SplitLayout
ref="splitLayout"
style="height: 400px"
@canLoadLayout="loadLayout"
@canSaveLayout="saveLayout"
/>
</template>
<script lang="ts" setup>
const splitLayout = ref<CodeLayoutSplitNInstance>();
//可以在事件回调中执行加载与保存操作,默认事件回调会在组件初始化与卸载时触发
//事件会传递组件实例 ref,可以直接调用,等同于 splitLayout.value
function loadLayout(ref: CodeLayoutSplitNInstance) {
//在这里加载
}
function saveLayout(ref: CodeLayoutSplitNInstance) {
//在这里保存
}
//也可以在其他自定时机通过调用组件实例方法来加载/保存数据
onMounted(() => {
splitLayout.value.loadLayout();
})
</script>
保存数据
通过调用 saveLayout 方法保存布局数据。
const json = splitLayout.value.saveLayout();
localStorage.setItem('SplitLayoutData', json);
加载数据
布局数据仅保存每个布局的基础位置、大小等信息,并不包含无法序列化的信息(例如回调函数,图标),所以你还需要在 loadLayout 的回调,根据面板名称填充这些数据,以实例化面板。
const data = localStorage.getItem('SplitLayoutData');
if (data) {
//If load layout from data, need fill panel data
splitLayout.value.loadLayout(JSON.parse(data), (panel) => {
switch (panel.name) {
case 'file1':
panel.title = 'File 1';
panel.tooltip = 'File 1 path';
panel.badge = '2';
panel.iconLarge = () => h(IconFile);
break;
}
return panel;
});
} else {
//No data, create new layout
//...
}
组件卸载提示
提示:以下两种情况,Vue可能会将你的组件卸载重新创建:
- 用户拖拽一个面板至其他面板
- 在开发模式下,当你修改了代码后,HMR重载
这时Vue可能会将你的组件卸载重新创建,组件状态会丢失,所以你需要处理自己的组件,在卸载时保存相关状态。