20260902173133
This commit is contained in:
1 parent
6b9cda5424
commit
db7813a2d2
16 files changed
+1350
-675
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useSlots, watch } from 'vue'
|
||||
import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, useSlots, watch } from 'vue'
|
||||
import { StkTable } from 'stk-table-vue'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { createSelectionColumn, isSelectionColumn } from './utils/createSelectionCellRenderers'
|
||||
@@ -10,7 +10,9 @@ defineOptions({ inheritAttrs: false })
|
||||
const props = defineProps({
|
||||
virtual: { type: Boolean, default: true },
|
||||
virtualX: { type: Boolean, default: true },
|
||||
colResizable: { type: Boolean, default: true },
|
||||
// 列宽拖拽默认开启;false=关闭;{ disabled: (col) => boolean }=按列禁用
|
||||
// (铺满容器的弹性列应禁用拖拽,见库文档「列宽铺满容器hack方式」)
|
||||
colResizable: { type: [Boolean, Object], default: true },
|
||||
// 边框自绘:true=外框圆角描边+行分隔线(默认);false=无外框仅行分隔线(嵌入卡片场景)。
|
||||
// stk-table 库内边框恒为 false,不用其渐变边框。
|
||||
bordered: { type: [Boolean, String], default: true },
|
||||
@@ -28,9 +30,6 @@ const props = defineProps({
|
||||
activeRowKey: { type: [String, Number], default: null },
|
||||
// 行拖拽排序:开启后显示拖拽手柄,并通过 row-order-change 回传排序后的完整数据。
|
||||
rowDraggable: { type: Boolean, default: false },
|
||||
// 行拖拽触发方式:true=仅拖拽手柄列(默认,显示手柄图标);
|
||||
// false=整行可拖拽(不显示手柄列,拖拽任意单元格即可排序;输入/复选框控件除外,避免破坏编辑)。
|
||||
rowDragHandle: { type: Boolean, default: true },
|
||||
// 存在 editor 配置的列默认可编辑;设为 false 可整体禁用编辑。
|
||||
editable: { type: Boolean, default: true },
|
||||
// 默认跟随应用深浅色模式,也允许单个表格显式覆盖。
|
||||
@@ -54,12 +53,28 @@ const effectiveVirtual = computed(
|
||||
() => props.virtual && props.dataSource.length > MIN_VIRTUAL_ROW_COUNT,
|
||||
)
|
||||
|
||||
// 横向虚拟门控:列数不超过阈值时关闭。库在 virtualX prop 为 true 时会把每列
|
||||
// 宽度钉死为 minWidth ?? width ?? 100(cellStyleMap 的 --cw + width/min-width/
|
||||
// max-width 三重锁),未设 width 的列失去「按比例铺满容器」的原生自适应。
|
||||
// 列数少、总宽不超容器的表用不上横向虚拟,关掉以恢复原生列宽分配。
|
||||
const MIN_VIRTUAL_X_COLUMN_COUNT = 20
|
||||
const effectiveVirtualX = computed(
|
||||
() => props.virtualX && displayColumns.value.length > MIN_VIRTUAL_X_COLUMN_COUNT,
|
||||
)
|
||||
|
||||
const rootRef = ref(null)
|
||||
const tableRef = ref(null)
|
||||
const slots = useSlots()
|
||||
const appStore = useAppStore()
|
||||
const tableTheme = computed(() => props.theme ?? (appStore.darkMode ? 'dark' : 'light'))
|
||||
|
||||
// 父组件是否绑定 v-model:columns。未绑定时拖列宽/列序无处回写(拖了松手回弹),
|
||||
// 直接关闭这两个功能。声明了 update:columns emit 后监听器不会进 attrs,
|
||||
// 需从 vnode.props 探测;绑定关系在模板编写时确定,运行期不会变化,无需响应式。
|
||||
const columnsBound =
|
||||
'onUpdate:columns' in (getCurrentInstance()?.vnode.props ?? {})
|
||||
const effectiveColResizable = columnsBound ? props.colResizable : false
|
||||
|
||||
// Tab 面板从隐藏恢复时,等到容器拥有有效尺寸再刷新虚拟滚动布局。
|
||||
// rAF 将同一帧内的多次 ResizeObserver 通知合并,避免重复重排。
|
||||
let refreshRafId = 0
|
||||
@@ -102,20 +117,8 @@ onMounted(() => {
|
||||
})
|
||||
resizeObserver.observe(rootRef.value)
|
||||
}
|
||||
// 整行拖拽:挂载后等表格渲染完再给数据行加 draggable
|
||||
setupWholeRowDrag()
|
||||
})
|
||||
|
||||
// 数据/开关变化后重跑整行拖拽初始化(行增删、虚拟滚动重建时兜底)
|
||||
watch(
|
||||
() => [props.rowDraggable, props.rowDragHandle, props.dataSource?.length],
|
||||
async () => {
|
||||
await nextTick()
|
||||
setupWholeRowDrag()
|
||||
},
|
||||
{ flush: 'post' },
|
||||
)
|
||||
|
||||
const NAVIGATION_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Tab'])
|
||||
const rowEditingStates = new WeakMap()
|
||||
let activeEditingRow = null
|
||||
@@ -274,7 +277,7 @@ const seqConfig = computed(() => {
|
||||
}
|
||||
})
|
||||
const columnDragConfig = computed(() => {
|
||||
if (!props.columnDraggable) return false
|
||||
if (!columnsBound || !props.columnDraggable) return false
|
||||
const configured = props.columnDraggable === true ? {} : props.columnDraggable
|
||||
return {
|
||||
...configured,
|
||||
@@ -325,7 +328,7 @@ const displayColumns = computed(() => {
|
||||
resizable: false,
|
||||
})
|
||||
}
|
||||
if (props.rowDraggable && props.rowDragHandle) cols.unshift(dragRowColumn)
|
||||
if (props.rowDraggable) cols.unshift(dragRowColumn)
|
||||
if (hasRowSelection.value) cols.unshift(selectionColumn)
|
||||
return cols.map((column) => ({
|
||||
...column,
|
||||
@@ -356,106 +359,6 @@ function handleRowOrderChange(sourceIndex, targetIndex) {
|
||||
emit('row-order-change', [...rows], sourceIndex, targetIndex)
|
||||
}
|
||||
|
||||
/* ================= 整行拖拽(无需手柄列) =================
|
||||
* stk-table 原生行拖拽必须通过 dragRow 手柄列触发;当 rowDraggable && !rowDragHandle
|
||||
* 时改用「整行可拖拽」:MutationObserver 给 tbody 数据行加 draggable 属性(兜底虚拟
|
||||
* 滚动新建的行),根节点上 dragstart/dragover/drop 事件委托落点与手柄模式一致。 */
|
||||
const wholeRowDragSource = ref(-1)
|
||||
let wholeRowDragTr = null
|
||||
let wholeRowOverTr = null
|
||||
let rowDragObserver = null
|
||||
|
||||
function applyDraggableToRows() {
|
||||
const root = rootRef.value
|
||||
if (!root) return
|
||||
root.querySelectorAll('tbody tr[data-row-i]').forEach((tr) => {
|
||||
tr.setAttribute('draggable', 'true')
|
||||
})
|
||||
}
|
||||
|
||||
function setupWholeRowDrag() {
|
||||
teardownWholeRowDrag()
|
||||
if (!props.rowDraggable || props.rowDragHandle || !rootRef.value) return
|
||||
applyDraggableToRows()
|
||||
const tbody = rootRef.value.querySelector('.stk-tbody-main')
|
||||
if (tbody) {
|
||||
rowDragObserver = new MutationObserver(applyDraggableToRows)
|
||||
rowDragObserver.observe(tbody, { childList: true, subtree: true })
|
||||
}
|
||||
}
|
||||
|
||||
function teardownWholeRowDrag() {
|
||||
rowDragObserver?.disconnect()
|
||||
rowDragObserver = null
|
||||
clearWholeRowDragVisuals()
|
||||
wholeRowDragSource.value = -1
|
||||
}
|
||||
|
||||
function clearWholeRowDragVisuals() {
|
||||
wholeRowDragTr?.classList.remove('tr-dragging')
|
||||
wholeRowDragTr = null
|
||||
wholeRowOverTr?.classList.remove('tr-dragging-over')
|
||||
wholeRowOverTr = null
|
||||
}
|
||||
|
||||
function isInteractiveDragTarget(target) {
|
||||
return !!target?.closest?.(
|
||||
'input, textarea, select, button, a, [contenteditable], .fms-checkbox, .fms-cell-editor-root',
|
||||
)
|
||||
}
|
||||
|
||||
function onWholeRowDragStart(e) {
|
||||
if (!props.rowDraggable || props.rowDragHandle) return
|
||||
const tr = e.target?.closest?.('tr[data-row-i]')
|
||||
if (!tr) return
|
||||
if (isInteractiveDragTarget(e.target)) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
wholeRowDragSource.value = Number(tr.dataset.rowI)
|
||||
wholeRowDragTr = tr
|
||||
tr.classList.add('tr-dragging')
|
||||
if (e.dataTransfer) {
|
||||
e.dataTransfer.effectAllowed = 'move'
|
||||
e.dataTransfer.setData('text/plain', String(wholeRowDragSource.value))
|
||||
e.dataTransfer.setDragImage?.(tr, 0, tr.offsetHeight / 2)
|
||||
}
|
||||
}
|
||||
|
||||
function onWholeRowDragOver(e) {
|
||||
if (wholeRowDragSource.value < 0) return
|
||||
e.preventDefault()
|
||||
if (e.dataTransfer) e.dataTransfer.dropEffect = 'move'
|
||||
const tr = e.target?.closest?.('tr[data-row-i]')
|
||||
if (tr && tr !== wholeRowOverTr) {
|
||||
wholeRowOverTr?.classList.remove('tr-dragging-over')
|
||||
wholeRowOverTr = tr
|
||||
tr.classList.add('tr-dragging-over')
|
||||
}
|
||||
}
|
||||
|
||||
function onWholeRowDrop(e) {
|
||||
const source = wholeRowDragSource.value
|
||||
if (source < 0) return
|
||||
e.preventDefault()
|
||||
const tr = e.target?.closest?.('tr[data-row-i]')
|
||||
clearWholeRowDragVisuals()
|
||||
wholeRowDragSource.value = -1
|
||||
if (!tr) return
|
||||
const target = Number(tr.dataset.rowI)
|
||||
if (Number.isNaN(target) || target === source) return
|
||||
const rows = [...props.dataSource]
|
||||
const [moved] = rows.splice(source, 1)
|
||||
rows.splice(target, 0, moved)
|
||||
tableRef.value?.clearSelectedArea?.()
|
||||
emit('row-order-change', rows, source, target)
|
||||
}
|
||||
|
||||
function onWholeRowDragEnd() {
|
||||
clearWholeRowDragVisuals()
|
||||
wholeRowDragSource.value = -1
|
||||
}
|
||||
|
||||
// 行高/表头行高通过 prop 传给 StkTable:库内部会将其注入为滚动容器上的
|
||||
// --row-height / --header-row-height / --footer-row-height,并参与虚拟滚动计算,
|
||||
// 此处只补充库不管理的表头/表尾背景色。
|
||||
@@ -669,7 +572,6 @@ onBeforeUnmount(() => {
|
||||
clearTimeout(resizeDebounceTimer)
|
||||
resizeObserver?.disconnect()
|
||||
resizeObserver = null
|
||||
teardownWholeRowDrag()
|
||||
removeNavigationListeners()
|
||||
clearEditActivateTimer()
|
||||
pressedNavigationKeys.clear()
|
||||
@@ -690,15 +592,8 @@ defineExpose({
|
||||
<div
|
||||
ref="rootRef"
|
||||
class="fms-table"
|
||||
:class="[
|
||||
{ 'is-whole-row-drag': rowDraggable && !rowDragHandle },
|
||||
bordered ? 'fms-table--bordered' : '',
|
||||
]"
|
||||
:class="[bordered ? 'fms-table--bordered' : '']"
|
||||
@keydown.capture="handleKeydownCapture"
|
||||
@dragstart="onWholeRowDragStart"
|
||||
@dragover="onWholeRowDragOver"
|
||||
@drop="onWholeRowDrop"
|
||||
@dragend="onWholeRowDragEnd"
|
||||
>
|
||||
<StkTable
|
||||
ref="tableRef"
|
||||
@@ -709,15 +604,15 @@ defineExpose({
|
||||
:row-height="props.rowHeight"
|
||||
:header-row-height="props.headerRowHeight"
|
||||
:virtual="effectiveVirtual"
|
||||
:virtual-x="virtualX"
|
||||
:virtual-x="effectiveVirtualX"
|
||||
:smooth-scroll="true"
|
||||
:auto-resize="false"
|
||||
:col-resizable="colResizable"
|
||||
:col-resizable="effectiveColResizable"
|
||||
:header-drag="columnDragConfig"
|
||||
:columns="displayColumns"
|
||||
@update:columns="onColumnsUpdate"
|
||||
:data-source="dataSource"
|
||||
:drag-row-config="{ mode: rowDraggable && rowDragHandle ? 'insert' : 'none' }"
|
||||
:drag-row-config="{ mode: rowDraggable ? 'insert' : 'none' }"
|
||||
:row-key="rowKey"
|
||||
:no-data-full="noDataFull"
|
||||
:show-overflow="showOverflow"
|
||||
@@ -756,20 +651,6 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
/* 整行拖拽:数据行鼠标提示可拖拽;拖拽中的行半透明、落点高亮 */
|
||||
.fms-table.is-whole-row-drag .stk-tbody-main tr[data-row-i] {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.fms-table.is-whole-row-drag .stk-tbody-main tr[data-row-i].tr-dragging {
|
||||
cursor: grabbing;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.fms-table.is-whole-row-drag .stk-tbody-main tr[data-row-i].tr-dragging-over {
|
||||
box-shadow: inset 0 2px 0 0 var(--fms-primary);
|
||||
}
|
||||
|
||||
.fms-table__inner {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -798,10 +679,20 @@ defineExpose({
|
||||
.fms-table__inner.stk-table {
|
||||
th,
|
||||
td {
|
||||
border-right: 1px solid var(--fms-border);
|
||||
border-bottom: 1px solid var(--fms-border);
|
||||
}
|
||||
}
|
||||
|
||||
/* 列宽铺满容器(库文档「列宽铺满容器hack方式」):
|
||||
开启 col-resizable 后库默认把 .stk-table-main 设为 flex:none + fit-content,
|
||||
表格收缩到内容宽。非 virtual-x(列数 ≤ 阈值、未设宽列走原生自适应)时覆盖回
|
||||
flex:1 使表格铺满容器;配合「固定列设 width、弹性列设 minWidth 且禁用其拖拽」
|
||||
的列配置约定使用。宽表(virtual-x,横向滚动)保持库的收缩行为。 */
|
||||
.fms-table__inner.stk-table:not(.virtual-x) .stk-table-main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.fms-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<script setup>
|
||||
/**
|
||||
* 图标输入:text 输入 + 预览。
|
||||
* - 输入 "lucide:chevron-down" 形式 → 渲染 lucide 图标(名称自动归一化)
|
||||
* - 输入其他字符串 → 视为 SVG 标记直接渲染
|
||||
* 预览在失焦后渲染,避免输入过程中逐字符重建 SVG。
|
||||
* 渲染统一走 getIcon(),与侧边栏/菜单树一致。
|
||||
*/
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { getIcon } from '@/utils/lucideIcons'
|
||||
import Input from '@/components/ui/input/input.vue'
|
||||
|
||||
const props = defineProps({
|
||||
/** 双向绑定的图标值("lucide:Name" 或 SVG 标记字符串) */
|
||||
modelValue: { type: String, default: '' },
|
||||
/** 禁用态 */
|
||||
disabled: { type: Boolean, default: false },
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change', 'clear'])
|
||||
|
||||
// 预览基于已提交(失焦)的值:输入过程中不实时渲染,避免 SVG 逐字符重建闪烁
|
||||
const committed = ref(props.modelValue)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(v) => {
|
||||
if (v === committed.value) return
|
||||
// 外部赋值(重载/切换菜单)时立即同步预览;仅用户输入时不更新
|
||||
committed.value = v
|
||||
},
|
||||
)
|
||||
|
||||
function onBlur() {
|
||||
committed.value = props.modelValue
|
||||
}
|
||||
|
||||
const previewIcon = computed(() => getIcon(committed.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="icon-input" :class="{ 'icon-input-disabled': disabled }">
|
||||
<div class="icon-input__field">
|
||||
<Input
|
||||
:model-value="modelValue"
|
||||
:disabled="disabled"
|
||||
allow-clear
|
||||
@update:model-value="(v) => emit('update:modelValue', v)"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="previewIcon" class="icon-input__preview" :title="committed">
|
||||
<component :is="previewIcon" class="icon-input__preview-icon" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.icon-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
max-width: 720px;
|
||||
}
|
||||
|
||||
.icon-input__field {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.icon-input__preview {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
color: var(--fms-text);
|
||||
|
||||
:deep(svg) {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -168,7 +168,13 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="rootEl" :class="rootClasses" :style="itemStyle" @focusout="onRootFocusOut">
|
||||
<div
|
||||
ref="rootEl"
|
||||
:class="rootClasses"
|
||||
:style="itemStyle"
|
||||
:data-field="String(props.name)"
|
||||
@focusout="onRootFocusOut"
|
||||
>
|
||||
<label
|
||||
v-if="label !== '' || $slots.label"
|
||||
class="fms-form-item-label"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, onMounted, ref, useSlots } from 'vue'
|
||||
import { cloneVNode, computed, onBeforeUnmount, onMounted, ref, useSlots } from 'vue'
|
||||
import SplitterPanel from './panel.vue'
|
||||
|
||||
/* ---------- props / emits / slots ---------- */
|
||||
@@ -43,16 +43,23 @@ const isVertical = computed(() => props.direction === 'vertical')
|
||||
function camelize(str) {
|
||||
return str.replace(/-(\w)/g, (_, c) => c.toUpperCase())
|
||||
}
|
||||
const panelItems = computed(() =>
|
||||
(slots.default?.() ?? [])
|
||||
.filter((node) => node.type === SplitterPanel)
|
||||
.map((node) => {
|
||||
const raw = node.props ?? {}
|
||||
const props = {}
|
||||
for (const key of Object.keys(raw)) props[camelize(key)] = raw[key]
|
||||
return { node, props }
|
||||
}),
|
||||
)
|
||||
|
||||
// 收集默认插槽中的 SplitterPanel 节点,统一为 { node, props } 结构。
|
||||
// 注意:必须是普通函数并在渲染时调用 —— slot 内容每次渲染都可能是新的(父组件更新
|
||||
// 面板内容时会生成新 vnode),不能用 computed 缓存,否则父组件更新后仍渲染旧 vnode,
|
||||
// 导致 <component :is> 对已失效的 vnode 执行 patch,报 null vnode 错误。
|
||||
function getPanelItems() {
|
||||
const items = (slots.default?.() ?? []).filter((node) => node.type === SplitterPanel)
|
||||
return items.map((node, index) => {
|
||||
const raw = node.props ?? {}
|
||||
const normalized = {}
|
||||
for (const key of Object.keys(raw)) normalized[camelize(key)] = raw[key]
|
||||
// 计算当前面板的显示尺寸:受控 size > 拖拽固定 > default-size
|
||||
const size = normalized.size ?? innerSizes.value[index] ?? normalized.defaultSize
|
||||
const vnode = cloneVNode(node, { size })
|
||||
return { node: vnode, props: normalized, isLast: index === items.length - 1 }
|
||||
})
|
||||
}
|
||||
|
||||
/* ---------- 尺寸工具 ---------- */
|
||||
function clamp(value, min, max) {
|
||||
@@ -80,26 +87,18 @@ function measurePanelSizes() {
|
||||
return Array.from(nodes).map((el) => (isVertical.value ? el.offsetHeight : el.offsetWidth))
|
||||
}
|
||||
|
||||
// 传给面板的显示尺寸:受控 size > 内部固定 > default-size
|
||||
function displaySize(index) {
|
||||
const panel = panelItems.value[index]
|
||||
if (!panel) return undefined
|
||||
if (panel.props.size !== undefined) return panel.props.size
|
||||
if (innerSizes.value[index] !== undefined) return innerSizes.value[index]
|
||||
return panel.props.defaultSize
|
||||
}
|
||||
|
||||
// 分隔条两侧面板都可调整时才允许拖拽/聚焦
|
||||
function canResize(index) {
|
||||
const prev = panelItems.value[index]
|
||||
const next = panelItems.value[index + 1]
|
||||
const items = getPanelItems()
|
||||
const prev = items[index]
|
||||
const next = items[index + 1]
|
||||
return prev && next && prev.props.resizable !== false && next.props.resizable !== false
|
||||
}
|
||||
|
||||
/* ---------- ARIA 值(预计算,避免模板内计算) ---------- */
|
||||
const ariaValues = computed(() => {
|
||||
const container = containerSize.value
|
||||
const items = panelItems.value
|
||||
const items = getPanelItems()
|
||||
if (!container || items.length < 2) return []
|
||||
// 各面板估算 px:内部固定 > size/default-size 换算 > 自动均分剩余
|
||||
const pxList = items.map((panel, i) => {
|
||||
@@ -133,10 +132,11 @@ function applyOffset(index, startSizes, container, delta) {
|
||||
let offset = delta
|
||||
const prev = startSizes[index]
|
||||
const next = startSizes[index + 1]
|
||||
const prevMin = toPx(panelItems.value[index].props.min, container) ?? 0
|
||||
const prevMax = toPx(panelItems.value[index].props.max, container) ?? container
|
||||
const nextMin = toPx(panelItems.value[index + 1].props.min, container) ?? 0
|
||||
const nextMax = toPx(panelItems.value[index + 1].props.max, container) ?? container
|
||||
const items = getPanelItems()
|
||||
const prevMin = toPx(items[index].props.min, container) ?? 0
|
||||
const prevMax = toPx(items[index].props.max, container) ?? container
|
||||
const nextMin = toPx(items[index + 1].props.min, container) ?? 0
|
||||
const nextMax = toPx(items[index + 1].props.max, container) ?? container
|
||||
offset = clamp(offset, prevMin - prev, prevMax - prev)
|
||||
offset = clamp(offset, next - nextMax, next - nextMin)
|
||||
const result = [...startSizes]
|
||||
@@ -158,7 +158,7 @@ function applySizes(result, index) {
|
||||
// (如侧栏折叠、窗口缩放)时剩余空间无法被自动填满
|
||||
function releaseAutoPanels() {
|
||||
const next = [...innerSizes.value]
|
||||
panelItems.value.forEach((panel, i) => {
|
||||
getPanelItems().forEach((panel, i) => {
|
||||
if (next[i] !== undefined && panel.props.size == null && panel.props.defaultSize == null) {
|
||||
delete next[i]
|
||||
}
|
||||
@@ -268,10 +268,10 @@ onBeforeUnmount(() => {
|
||||
|
||||
<template>
|
||||
<div ref="rootRef" class="fms-splitter" :class="`fms-splitter-${direction}`">
|
||||
<template v-for="(item, index) in panelItems" :key="index">
|
||||
<component :is="item.node" :size="displaySize(index)" />
|
||||
<template v-for="(item, index) in getPanelItems()" :key="index">
|
||||
<component :is="item.node" />
|
||||
<div
|
||||
v-if="index < panelItems.length - 1"
|
||||
v-if="!item.isLast"
|
||||
class="fms-splitter-bar"
|
||||
:class="{
|
||||
'fms-splitter-bar-active': activeBar === index,
|
||||
|
||||
Reference in new issue
Block a user