From 62fe6810a73881a19fc327d1c7953343e4b84af8 Mon Sep 17 00:00:00 2001 From: skycurtain Date: Thu, 3 Apr 2025 11:05:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=9D=A2=E6=9D=BF=E5=B0=BA=E5=AF=B8):=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=9D=A2=E6=9D=BF=E5=B0=BA=E5=AF=B8=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在SplitLayout组件中添加updatePaneSize方法,用于在外部size属性变化时更新面板尺寸。SplitPanel组件通过watch监听size属性变化,调用父组件的updatePaneSize方法实现尺寸同步。App.vue中添加输入控件,演示面板尺寸的双向绑定功能。 --- src/App.vue | 63 ++++++++++++++++++++++++++++++++++ src/components/SplitLayout.vue | 23 +++++++++++++ src/components/SplitPanel.vue | 17 ++++++++- 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/App.vue b/src/App.vue index a1558b3..5c495c5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,10 @@ @@ -114,4 +151,30 @@ h2 { margin-bottom: 10px; color: #1890ff; } + +.control-panel { + display: flex; + gap: 20px; + margin-bottom: 15px; + background-color: #f5f5f5; + padding: 15px; + border-radius: 4px; +} + +.control-item { + display: flex; + align-items: center; + gap: 8px; +} + +.control-item input { + width: 60px; + padding: 5px; + border: 1px solid #d9d9d9; + border-radius: 2px; +} + +.control-item label { + font-weight: 500; +} diff --git a/src/components/SplitLayout.vue b/src/components/SplitLayout.vue index d74f367..617b116 100644 --- a/src/components/SplitLayout.vue +++ b/src/components/SplitLayout.vue @@ -94,6 +94,29 @@ provide('splitter-context', { panes.value.splice(index, 1) } }, + /** + * 更新面板尺寸方法 + * 子组件在外部size属性变化时调用此方法更新面板尺寸 + * @param index 面板在数组中的索引 + * @param newSize 新的尺寸百分比 + */ + updatePaneSize: (index: number, newSize: number) => { + if (index >= 0 && index < panes.value.length) { + // 保存旧尺寸,用于计算差值 + const oldSize = panes.value[index].size + // 更新面板尺寸 + panes.value[index].size = newSize + + // 重新计算所有面板尺寸,确保总和为100% + calculateSizes() + + // 触发resize事件,将所有面板的最新尺寸信息传递给父组件 + emit( + 'resize', + panes.value.map((pane) => ({ id: pane.id, size: pane.size })), + ) + } + }, }) /** diff --git a/src/components/SplitPanel.vue b/src/components/SplitPanel.vue index d92cac2..c735adc 100644 --- a/src/components/SplitPanel.vue +++ b/src/components/SplitPanel.vue @@ -5,7 +5,7 @@ * 该组件作为SplitLayout的子组件,表示一个可调整大小的面板。 * 通过provide/inject机制与SplitLayout父组件通信,实现面板的注册、尺寸计算和更新。 */ -import { ref, inject, computed, onMounted, onBeforeUnmount, useId } from 'vue' +import { ref, inject, computed, onMounted, onBeforeUnmount, useId, watch } from 'vue' // 定义组件属性 const props = defineProps({ @@ -51,6 +51,7 @@ const splitterContext = inject('splitter-context') as { panes: { value: Array<{ id: string; size: number; minSize: number; maxSize: number }> } registerPane: (id: string, size: number, minSize: number, maxSize: number) => number unregisterPane: (index: number) => void + updatePaneSize: (index: number, newSize: number) => void } /** @@ -97,6 +98,20 @@ onBeforeUnmount(() => { // 注销面板,传入索引值 splitterContext.unregisterPane(paneIndex.value) }) + +/** + * 监听size属性变化 + * 当外部组件修改size值时,调用父组件的updatePaneSize方法更新面板尺寸 + */ +watch( + () => props.size, + (newSize) => { + // 只有当面板已注册且size值有效时才更新 + if (paneIndex.value >= 0 && newSize > 0) { + splitterContext.updatePaneSize(paneIndex.value, newSize) + } + }, +)