---
title: "AutoSizer 自适应尺寸"
description: "随内容变化平滑调整宽高的容器"
category: Primitives
status: beta
since: 0.3.4
tags: [auto-size, layout, animation]
syncStatus: reviewed
verified: true
---

## 用法

### 仅高度
只同步高度，外围布局保持原宽度；状态切换包在 `action()` 里。
:::TuffDemoWrapper{demo="AutoSizerAutoSizerHeightDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const active = ref<'a' | 'b'>('a')
  const sizerRef = ref()

  function setTab(next: 'a' | 'b') {
    sizerRef.value?.action(() => {
      active.value = next
    })
  }
  </script>

  <template>
    <TxButton @click="setTab('a')">Tab A</TxButton>
    <TxButton @click="setTab('b')">Tab B</TxButton>

    <TxAutoSizer ref="sizerRef" :width="false" :duration-ms="250">
      <div v-if="active === 'a'">Short content.</div>
      <div v-else>Long content…</div>
    </TxAutoSizer>
  </template>
---
:::

### flex 容器内的宽度
作为 flex 子项时，不要用 `flex: 1` 或 `width: 100%` 撑满它，否则宽度不再跟随内容。
:::TuffDemoWrapper{demo="AutoSizerAutoSizerWidthInFlexDemo" code-lang="vue"}
---
code: |
  <template>
    <div style="display: flex; gap: 12px;">
      <TxButton @click="toggle">Toggle</TxButton>

      <TxAutoSizer ref="sizerRef" :height="false">
        <TxButton variant="secondary">
          {{ wide ? 'Very very long label' : 'Short' }}
        </TxButton>
      </TxAutoSizer>

      <div style="flex: 1;">Right Area</div>
    </div>
  </template>
---
:::

### 仅宽度
只同步宽度时自动收缩到内容宽度，适合按钮文案变化。
:::TuffDemoWrapper{demo="AutoSizerAutoSizerWidthDemo" code-lang="vue"}
---
code: |
  <template>
    <TxAutoSizer ref="sizerRef" :height="false">
      <TxButton :loading="loading" variant="primary">Submit</TxButton>
    </TxAutoSizer>
  </template>
---
:::

### 数字过渡
搭配 `TxTextMorph`，位数变化时宽度同步过渡。
:::TuffDemoWrapper{demo="AutoSizerAutoSizerTextMorphDemo" code-lang="vue"}
---
code: |
  <template>
    <TxAutoSizer ref="sizerRef" :height="false">
      <TxButton variant="secondary">
        $ <TxTextMorph :text="value" :decimals="2" />
      </TxButton>
    </TxAutoSizer>
  </template>
---
:::

### 文本变换
宽高同时跟随；默认的 `outerClass="overflow-hidden"` 裁掉 blur 的边缘溢出。
:::TuffDemoWrapper{demo="AutoSizerAutoSizerTextTransformerDemo" code-lang="vue"}
---
code: |
  <template>
    <TxAutoSizer
      ref="sizerRef"
      inline
      :duration-ms="duration"
      easing="cubic-bezier(0.2, 0, 0, 1)"
    >
      <TxCard variant="plain" background="mask" :padding="12">
        <TxTextTransformer :text="label" :duration-ms="duration" :blur-px="blurPx" />
      </TxCard>
    </TxAutoSizer>
  </template>
---
:::

### 最佳实践

- 内容区（Tabs、Accordion、下拉）只同步高度；按钮、标签、数字只同步宽度。
- 内容带 blur、scale 或 FLIP 动效时保留 `outerClass="overflow-hidden"`。
- 明确的状态切换包在 `action()` 或 `flip()` 里，不要改完状态再调 `refresh()`，否则拿不到过渡所需的前后快照。
- 只有外层与内层会各自变化尺寸时才设 `observeTarget="both"`。
- 文本保持 `rounding="ceil"`，避免亚像素裁切；父级需要更紧的边界时再用 `floor`。

## API 参考

### 属性

| 属性名 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `as` | `string` | `div` | 外层标签。 |
| `innerAs` | `string` | `div` | 内层标签。 |
| `width` | `boolean` | `true` | 同步宽度。 |
| `height` | `boolean` | `true` | 同步高度。 |
| `inline` | `boolean` | - | 收缩到内容宽度；省略时仅在只同步宽度时启用。 |
| `durationMs` | `number` | `200` | 过渡时长（ms）。 |
| `easing` | `string` | `ease` | 过渡曲线。 |
| `outerClass` | `string` | `overflow-hidden` | 外层 class，排在透传的 class 之前。 |
| `innerClass` | `string` | - | 内层 class。 |
| `rounding` | `'none' \| 'round' \| 'floor' \| 'ceil'` | `ceil` | 测量值的取整方式。 |
| `immediate` | `boolean` | `true` | 挂载后立即测量。 |
| `rafBatch` | `boolean` | `true` | 用 rAF 合并测量。 |
| `observeTarget` | `'inner' \| 'outer' \| 'both'` | `inner` | 自动监听尺寸变化的元素。 |

### 插槽

| 插槽名 | 说明 |
|--------|------|
| `default` | 被测量的内容，渲染在内层中。 |

### 暴露方法

| 名称 | 类型 | 说明 |
|------|------|------|
| `refresh()` | `() => Promise<void>` | 重新测量。 |
| `flip(action)` | `(action: () => void \| Promise<void>) => Promise<void>` | 执行 `action` 并做一次尺寸 FLIP 过渡。 |
| `action(fn, options?)` | `(fn: (el: HTMLElement) => void \| Promise<void>, options?: AutoSizerActionOptions \| detect) => Promise<any>` | 对内层或外层执行变更并过渡，返回前后快照与 `changedKeys`。 |
| `size` | `{ width: number; height: number } \| null` | 最近一次测量结果。 |
| `focus()` | `() => void` | 外层可聚焦时聚焦它。 |
| `outerEl` | `HTMLElement \| null` | 外层元素。 |

## 概述

- 透传的 attrs 落在外层，与 `outerClass` 和尺寸样式合并；内层包裹被测内容，使用 `display: flow-root`。
- 内容尺寸变化（含图片加载、异步渲染）时自动重新测量。
- `flip()` 与 `action()` 执行期间暂停自动测量，过渡结束后重新测量。

## 技术实现

- 自动测量基于 `ResizeObserver`，显式切换走尺寸 FLIP。
- 源码：`packages/tuffex/packages/components/src/auto-sizer/`。

<TuffDocSourceLink />
