npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

vue-resizable-table

v1.0.6

Published

A Vue 3 component for resizable and draggable table columns with ViewUI

Readme

ResizableTable

一个功能强大的 Vue 3 可调整列宽表格组件,支持列拖拽排序、字段选择、自动保存配置等功能。

特性

  • 🎯 列宽调整: 支持拖拽调整列宽,自动保存配置
  • 🔄 列拖拽排序: 支持拖拽交换列位置,实时预览效果
  • 👁️ 字段选择: 支持动态显示/隐藏列,灵活控制表格展示
  • 💾 配置持久化: 自动保存列宽、顺序、可见性配置到本地存储
  • 📱 响应式设计: 支持窗口大小变化时自动调整列宽
  • 🎨 美观界面: 现代化 UI 设计,丰富的视觉反馈
  • 高性能: 优化的拖拽算法,流畅的交互体验
  • 🔧 高度可配置: 丰富的配置选项,满足各种使用场景

安装

npm install resizable-table-vue

使用

基础用法

<template>
  <ResizableTable
    :data="tableData"
    :columns="columns"
    :total="total"
    :current-page="currentPage"
    :page-size="pageSize"
    :loading="loading"
    title="用户列表"
    @on-page-change="handlePageChange"
    @on-page-size-change="handlePageSizeChange"
    @on-column-resize="handleColumnResize"
    @on-column-reorder="handleColumnReorder"
    @on-selection-change="handleSelectionChange"
  />
</template>

<script setup>
import { ref } from 'vue'
import ResizableTable from 'resizable-table-vue'

const tableData = ref([
  { id: 1, name: '张三', age: 25, email: '[email protected]', status: 'active' },
  { id: 2, name: '李四', age: 30, email: '[email protected]', status: 'inactive' },
  { id: 3, name: '王五', age: 28, email: '[email protected]', status: 'active' }
])

const columns = ref([
  { 
    key: 'id', 
    title: 'ID', 
    width: 80, 
    sortable: true,
    resizable: true,
    draggable: true
  },
  { 
    key: 'name', 
    title: '姓名', 
    minWidth: 120, 
    sortable: true,
    resizable: true,
    draggable: true
  },
  { 
    key: 'age', 
    title: '年龄', 
    width: 100, 
    sortable: true,
    resizable: true,
    draggable: true
  },
  { 
    key: 'email', 
    title: '邮箱', 
    minWidth: 200,
    resizable: true,
    draggable: true
  },
  {
    key: 'status',
    title: '状态',
    width: 120,
    resizable: true,
    draggable: true,
    render: (h, { row }) => {
      const color = row.status === 'active' ? 'success' : 'error'
      const text = row.status === 'active' ? '激活' : '禁用'
      return h('Tag', { props: { color } }, text)
    }
  },
  {
    key: 'action',
    title: '操作',
    width: 180,
    resizable: true,
    draggable: false, // 操作列通常不允许拖拽
    render: (h, { row }) => {
      return h('div', [
        h('Button', { 
          props: { type: 'primary', size: 'small' },
          style: { marginRight: '8px' },
          on: { click: () => handleEdit(row) }
        }, '编辑'),
        h('Button', { 
          props: { type: 'error', size: 'small' },
          on: { click: () => handleDelete(row) }
        }, '删除')
      ])
    }
  }
])

const total = ref(100)
const currentPage = ref(1)
const pageSize = ref(10)
const loading = ref(false)

const handlePageChange = (page) => {
  currentPage.value = page
  // 加载数据逻辑
  loadData()
}

const handlePageSizeChange = (size) => {
  pageSize.value = size
  currentPage.value = 1
  // 加载数据逻辑
  loadData()
}

const handleColumnResize = ({ column, width, deltaX }) => {
  console.log(`列 ${column.title} 宽度调整为: ${width}px`)
}

const handleColumnReorder = ({ fromIndex, toIndex, newOrder, action }) => {
  console.log(`列从位置 ${fromIndex} 移动到位置 ${toIndex}`)
}

const handleSelectionChange = (selection) => {
  console.log('选中的行:', selection)
}

const handleEdit = (row) => {
  console.log('编辑:', row)
}

const handleDelete = (row) => {
  console.log('删除:', row)
}

const loadData = () => {
  loading.value = true
  // 模拟API调用
  setTimeout(() => {
    loading.value = false
  }, 1000)
}
</script>

全局注册

import { createApp } from 'vue'
import ResizableTable from 'resizable-table-vue'

const app = createApp(App)
app.use(ResizableTable)

API

Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | data | Array | [] | 表格数据 | | columns | Array | [] | 表格列配置 | | loading | Boolean | false | 加载状态 | | title | String | '' | 表格标题 | | total | Number | 0 | 数据总数 | | currentPage | Number | 1 | 当前页码 | | pageSize | Number | 10 | 每页条数 | | border | Boolean | true | 是否显示边框 | | stripe | Boolean | true | 是否显示斑马纹 | | height | Number/String | null | 表格高度 | | maxHeight | Number/String | null | 表格最大高度 | | showHeader | Boolean | true | 是否显示表头 | | size | String | 'default' | 表格尺寸 (large/default/small) | | noDataText | String | '暂无数据' | 无数据时显示的文本 | | noFilteredDataText | String | '暂无筛选结果' | 无筛选结果时显示的文本 | | showToolbar | Boolean | true | 是否显示工具栏 | | showPagination | Boolean | true | 是否显示分页器 | | pageSizeOpts | Array | [10, 20, 50, 100] | 每页条数选择器的选项 | | showTotal | Boolean | true | 是否显示总数 | | showElevator | Boolean | true | 是否显示电梯(快速跳转) | | showSizer | Boolean | true | 是否显示分页大小选择器 | | showQuickJumper | Boolean | false | 是否显示快速跳转 | | paginationSize | String | 'default' | 分页器尺寸 | | simple | Boolean | false | 是否使用简洁分页器 | | placement | String | 'bottom' | 分页器位置 | | storageKey | String | 'resizable-table-columns' | 本地存储键名 | | minWidth | Number | 300 | 最小列宽 |

Column 配置

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | key | String | - | 列标识 | | title | String | - | 列标题 | | width | Number | - | 列宽度 | | minWidth | Number | 120 | 最小宽度 | | resizable | Boolean | true | 是否可调整大小 | | draggable | Boolean | true | 是否可拖拽排序 | | sortable | Boolean | false | 是否可排序 | | filterable | Boolean | false | 是否可过滤 | | align | String | 'left' | 对齐方式 | | fixed | String | - | 固定列 (left/right) | | render | Function | - | 自定义渲染函数 | | slot | String | - | 插槽名称 |

Events

| 事件名 | 参数 | 说明 | |--------|------|------| | on-select | selection, row | 在多选模式下,选中某一项时触发 | | on-select-cancel | selection, row | 在多选模式下,取消选中某一项时触发 | | on-select-all | selection | 在多选模式下,点击全选时触发 | | on-select-all-cancel | selection | 在多选模式下,点击取消全选时触发 | | on-selection-change | selection | 在多选模式下,只要选中项发生变化时就会触发 | | on-sort-change | column | 排序变化时触发 | | on-filter-change | filters | 过滤变化时触发 | | on-row-click | row, index | 点击行时触发 | | on-row-dblclick | row, index | 双击行时触发 | | on-expand | row, status | 展开或收起某一行时触发 | | on-expand-change | expandedRows | 展开的行发生变化时触发 | | on-current-change | currentRow, oldCurrentRow | 当前行发生变化时触发 | | on-page-change | page | 页码变化时触发 | | on-page-size-change | pageSize | 每页条数变化时触发 | | on-column-resize | { column, width, deltaX } | 列宽调整时触发 | | on-column-reorder | { fromIndex, toIndex, newOrder, action } | 列排序变化时触发 |

高级功能

列宽调整

组件支持拖拽调整列宽,调整后的宽度会自动保存到本地存储。

<ResizableTable
  :columns="columns"
  :min-width="100"
  storage-key="my-table-config"
  @on-column-resize="handleColumnResize"
/>

特性说明:

  • 鼠标悬停在列边界时显示调整光标
  • 支持设置最小列宽限制
  • 自动保存调整后的列宽到本地存储
  • 支持重置列宽功能

列拖拽排序

支持拖拽交换列位置,提供实时预览效果。

<ResizableTable
  :columns="columns"
  @on-column-reorder="handleColumnReorder"
/>

特性说明:

  • 拖拽时显示视觉反馈和指示器
  • 实时预览拖拽效果
  • 支持禁用特定列的拖拽功能
  • 自动保存列顺序到本地存储

字段选择

用户可以动态选择显示哪些列。

<ResizableTable
  :columns="columns"
  :show-toolbar="true"
/>

特性说明:

  • 工具栏提供字段选择按钮
  • 支持全选/取消全选功能
  • 显示已选择字段数量统计
  • 自动保存字段可见性设置

配置持久化

组件会自动将用户的配置保存到本地存储,包括:

  • 列宽设置:每列的宽度调整
  • 列顺序:拖拽后的列排序
  • 字段可见性:显示/隐藏的列设置
<ResizableTable
  storage-key="my-custom-table-config"
  :columns="columns"
/>

配置管理:

  • 使用 localStorage 进行持久化存储
  • 支持自定义存储键名
  • 提供手动保存和自动保存功能
  • 支持重置所有配置

工具栏功能

组件提供了丰富的工具栏功能:

<ResizableTable
  :show-toolbar="true"
  title="数据列表"
  :total="100"
/>

工具栏包含:

  • 表格标题:显示表格名称
  • 数据统计:显示总记录数
  • 重置列宽:一键重置所有列宽
  • 选择字段:打开字段选择弹窗
  • 保存设置:手动保存当前配置

响应式设计

组件支持响应式布局,在不同屏幕尺寸下自动调整:

/* 移动端适配 */
@media (max-width: 768px) {
  .table-toolbar {
    flex-direction: column;
  }
  
  .pagination-wrapper {
    text-align: center;
  }
}

自定义渲染

支持自定义列内容渲染。

const columns = [
  {
    key: 'status',
    title: '状态',
    render: (h, { row }) => {
      const color = row.status === 'active' ? 'success' : 'error'
      return h('Tag', { props: { color } }, row.status)
    }
  }
]

插槽支持

支持使用插槽自定义列内容。

<ResizableTable :columns="columns">
  <template #status="{ row }">
    <Tag :color="row.status === 'active' ? 'success' : 'error'">
      {{ row.status }}
    </Tag>
  </template>
</ResizableTable>

多选功能

组件完整支持表格的多选功能:

<ResizableTable
  :columns="columnsWithSelection"
  @on-selection-change="handleSelectionChange"
  @on-select-all="handleSelectAll"
/>

多选特性:

  • 支持单行选择和全选
  • 提供选择状态变化事件
  • 支持取消选择操作
  • 选择状态实时反馈

展开行功能

支持表格行的展开和收起:

<ResizableTable
  :columns="columns"
  @on-expand="handleExpand"
  @on-expand-change="handleExpandChange"
/>

方法

| 方法名 | 说明 | 参数 | |--------|------|------| | resetColumnWidths | 重置所有列宽到默认值 | - | | saveSettings | 手动保存当前配置到本地存储 | - | | showFieldSelector | 显示字段选择弹窗 | - | | hideFieldSelector | 隐藏字段选择弹窗 | - | | selectAllFields | 全选所有字段 | - | | unselectAllFields | 取消全选所有字段 | - | | applyFieldSelection | 应用字段选择 | - | | cancelFieldSelection | 取消字段选择 | - |

插槽

| 插槽名 | 说明 | 参数 | |--------|------|------| | default | 表格列内容插槽 | { row, column, index } | | [column.key] | 特定列的内容插槽 | { row, column, index } | | toolbar-left | 工具栏左侧自定义内容 | - | | toolbar-right | 工具栏右侧自定义内容 | - | | empty | 空数据时的自定义内容 | - |

配置存储

组件使用 localStorage 来持久化用户配置,存储的数据结构如下:

{
  columnWidths: {
    [columnKey]: width // 列宽设置
  },
  columnOrder: [columnKey1, columnKey2, ...], // 列顺序
  visibleColumns: {
    [columnKey]: boolean // 列可见性
  }
}

存储键名规则:

  • 默认键名:resizable-table-config
  • 自定义键名:通过 storage-key prop 设置
  • 完整键名:${storageKey}-${configType}

配置类型:

  • widths:列宽配置
  • order:列顺序配置
  • visibility:列可见性配置

组件提供了丰富的 CSS 类名,可以轻松定制样式。

/* 自定义表格样式 */
.resizable-table-container {
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

/* 自定义工具栏样式 */
.table-toolbar {
  background: linear-gradient(90deg, #f8f9fa 0%, #e9ecef 100%);
}

/* 自定义拖拽样式 */
.drag-indicator {
  background: linear-gradient(180deg, #28a745 0%, #20c997 100%);
}

浏览器兼容性

  • Chrome >= 60
  • Firefox >= 60
  • Safari >= 12
  • Edge >= 79

依赖

  • Vue 3.0+
  • View UI Plus (iView)

许可证

MIT License

更新日志

1.0.1

  • 初始版本发布
  • 支持列宽调整
  • 支持列拖拽排序
  • 支持字段选择
  • 支持配置持久化

效果展示

列宽调整

列宽调整

拖拽调整列宽

列排序

列排序

拖拽交换列位置

字段选择

字段选择