普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月2日首页

Arco Design Layout 中使用 ResizeBox 实现可拖拽侧边栏

作者 好_快
2025年12月2日 10:01

Arco Design Layout 中使用 ResizeBox 实现可拖拽侧边栏

问题

a-layout-sider 虽然有 width 属性可以设置宽度,但没有拖拽事件来动态调整宽度。直接使用 a-resize-box 替换会导致布局混乱。

解决方案

核心要点:必须使用 <a-layout :has-sider="true"> 包裹 a-resize-box

<a-layout :has-sider="true">
  <a-resize-box
    :directions="['right']"
    :width="sidebarWidthImmediate"
    @moving="handleSidebarResize"
    @moving-end="handleSidebarResizeEnd"
  >
    <div>侧边栏内容</div>
  </a-resize-box>
  <a-layout-content>
    主内容区
  </a-layout-content>
</a-layout>

性能优化:双变量设计

问题

如果只用一个变量,拖拽过程中会频繁触发子组件更新和计算属性重新计算,导致卡顿。

方案

使用两个变量分离视觉反馈和数据传递:

// 视觉反馈变量:高频更新,只影响 ResizeBox
const sidebarWidthImmediate = ref(200)

// 数据传递变量:低频更新,用于子组件和计算属性
const sidebarWidth = ref(200)

function handleSidebarResize(size: { width: number; height: number }) {
  // 拖拽过程中:只更新视觉反馈变量
  sidebarWidthImmediate.value = Math.max(minSidebarWidth, size.width)
}

function handleSidebarResizeEnd() {
  // 拖拽结束时:同步数据传递变量,触发一次子组件更新
  sidebarWidth.value = sidebarWidthImmediate.value
}

性能对比

方案 拖拽时子组件渲染 性能表现
单变量 高频(每秒数十次) ❌ 卡顿
双变量 低频(结束时1次) ✅ 流畅

完整示例

<template>
  <a-layout>
    <a-layout-header>Header</a-layout-header>
    
    <a-layout :has-sider="true">
      <a-resize-box
        :directions="['right']"
        :width="sidebarWidthImmediate"
        @moving="handleSidebarResize"
        @moving-end="handleSidebarResizeEnd"
      >
        <div class="sidebar">侧边栏内容</div>
      </a-resize-box>
      
      <a-layout-content>
        <MainContent
          :sidebar-width="sidebarWidth"
          :width="contentWidth"
        />
      </a-layout-content>
    </a-layout>
  </a-layout>
</template>

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

const minSidebarWidth = 200
const sidebarWidthImmediate = ref(minSidebarWidth) // 视觉反馈变量
const sidebarWidth = ref(minSidebarWidth) // 数据传递变量
const resizerWidth = 6
const containerWidth = ref(1200)

const contentWidth = computed(() => {
  return containerWidth.value - sidebarWidth.value - resizerWidth
})

function handleSidebarResize(size: { width: number; height: number }) {
  sidebarWidthImmediate.value = Math.max(minSidebarWidth, size.width)
}

function handleSidebarResizeEnd() {
  sidebarWidth.value = sidebarWidthImmediate.value
}
</script>

注意事项

  1. 必须设置 has-sider="true":否则布局会混乱
  2. 宽度计算需减去拖拽条宽度:通常为 6px
  3. 设置最小宽度限制:防止侧边栏过小
  4. 使用双变量模式:避免拖拽时频繁触发子组件更新
❌
❌