ElementPlus ElAutoResizer 组件的使用

ElementPlus 的 TableV2(虚拟化表格)模块中提供了一个 ElAutoResizer 组件,可以用于作为块级容器,自动计算其宽高,并提供给其内部(默认插槽)使用。

由于非通用 UI 组件,ElementPlus 官方未提供该组件的文档,但它可以像其它组件一样引入使用

引入

显式引入:

js
import { ElAutoResizer } from 'element-plus'

完全引入、自动引入、全局注册组件时无需显式引入。

使用

参照官网示例:虚拟化表格-自动调整大小

vue
<template>
  <div style="height: 400px">
    <el-auto-resizer>
      <template #default="{ height, width }">
        <el-table-v2 :columns="columns" :data="data" :width="width" :height="height" fixed />
      </template>
    </el-auto-resizer>
  </div>
</template>

该组件除了省去了给 vue 组件设置 resize 监听外,特别适合内部仅需要对尺寸进行响应式更新的情景。例如 echarts 表格

ElementPlus 官网文档中无该组件文档,TableV2 中的示例比较基础。可以参考其源码

ElAutoResizer 源码分析

ts
import { buildProps, definePropType } from '@element-plus/utils'

import type { ExtractPropTypes } from 'vue'

type AutoResizeHandler = (event: { height: number; width: number }) => void

export const autoResizerProps = buildProps({
  disableWidth: Boolean,
  disableHeight: Boolean,
  onResize: {
    type: definePropType<AutoResizeHandler>(Function),
  },
} as const)

export type AutoResizerProps = ExtractPropTypes<typeof autoResizerProps>
tsx
import { defineComponent } from 'vue'
import { useNamespace } from '@element-plus/hooks'
import { autoResizerProps } from '../auto-resizer'
import { useAutoResize } from '../composables'

const AutoResizer = defineComponent({
  name: 'ElAutoResizer',
  props: autoResizerProps,
  setup(props, { slots }) {
    const ns = useNamespace('auto-resizer')
    const { height, width, sizer } = useAutoResize(props)
    const style = {
      width: '100%',
      height: '100%',
    }

    return () => {
      return (
        <div ref={sizer} class={ns.b()} style={style}>
          {slots.default?.({
            height: height.value,
            width: width.value,
          })}
        </div>
      )
    }
  },
})

export default AutoResizer
ts
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useResizeObserver } from '@vueuse/core'

import type { AutoResizerProps } from '../auto-resizer'

const useAutoResize = (props: AutoResizerProps) => {
  const sizer = ref<HTMLElement>()
  const width$ = ref(0)
  const height$ = ref(0)

  let resizerStopper: ReturnType<typeof useResizeObserver>['stop']
  onMounted(() => {
    resizerStopper = useResizeObserver(sizer, ([entry]) => {
      const { width, height } = entry.contentRect
      const { paddingLeft, paddingRight, paddingTop, paddingBottom } =
        getComputedStyle(entry.target)

      const left = Number.parseInt(paddingLeft) || 0
      const right = Number.parseInt(paddingRight) || 0
      const top = Number.parseInt(paddingTop) || 0
      const bottom = Number.parseInt(paddingBottom) || 0

      width$.value = width - left - right
      height$.value = height - top - bottom
    }).stop
  })

  onBeforeUnmount(() => {
    resizerStopper?.()
  })

  watch([width$, height$], ([width, height]) => {
    props.onResize?.({
      width,
      height,
    })
  })

  return {
    sizer,
    width: width$,
    height: height$,
  }
}

export { useAutoResize }

使用 ElAutoResizer 进行 resize 监听

ElAutoResizer 提供了容器实时尺寸,但有时可能需要监听 resize 事件并处理一些逻辑。下面提供两种使用 ElAutoResizer 组件进行 resize 监听的方法:

resize 事件监听

  • AutoResizer 组件的 resize 事件

参照 AutoResizerProps 类型定义,该组件提供了 resize 事件。

AutoResizer 组件内部应用 use-auto-resize.ts 监听容器尺寸变化并触发组件的 resize 事件

vue
<script setup>
const handleResize = size => console.log(size)
</script>

<template>
  <div style="resize: both; border: 1px solid gray; overflow: auto">
    <ElAutoResizer @resize="handleResize">
      <div>Content</div>
    </ElAutoResizer>
  </div>
</template>
  • 监听尺寸属性

如果 ElAutoResizer 内部是一个组件,可以将尺寸属性作为 props 传递给内部组件,然后在内部组件内监听尺寸变化。

不过既然组件提供了 resize 事件,没必要重复监听。

实例

这里使用 echarts 演示

vue
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import * as echarts from 'echarts'
import { ElAutoResizer } from 'element-plus'

const chartRef = ref()
let echartInstance

const resizeEcharts = () => echartInstance?.resize()

onMounted(() => {
  echartInstance = echarts.init(chartRef.value)
  // ...
  echartInstance.setOption({ ... })
})
onBeforeUnmount(() => {
  echartInstance?.dispose()
})
</script>
<template>
  <ElAutoResizer @resize="resizeEcharts">
    <div ref="chartRef" style="height: 400px"></div>
  </ElAutoResizer>
</template>

Last updated: