已经基本完成文档的开发 vue-fantable 开发已经初步完成,如果遇到了任何组件和文档有关问题,可以提交 issue
English | 中文
如果我看的更远,那是因为我站在巨人的肩膀上。
如果你的项目使用 vue2,建议使用 vue-easytable
本项目由 vue-easytable 更新而来,支持 Vue3,使用 ESM(建议 node V18+)体积更小,像使用 vue-easytable 一样,使用 vue-fantable 吧。
- 采用虚拟滚动技术,支持 30 万行数据展示和实时编辑
- 永久开源免费。当然你也可以选择捐赠,保证项目长期维护和功能加速开发
文档正在逐步完善,大家可以参照 vue-easytable 的文档。组件使用方式和原组件一致。
确保 Vue 版本至少为 3.2
npm install vue-fantable
# or
yarn add vue-fantable
讲一下内容添加到 main.js:
import { createApp } from "vue";
import "vue-fantable/libs/theme-default.css";
import App from './app.vue'
import VueFantable from "vue-fantable";
const app = createApp(App)
app.use(VueFantable);
app.mounted('#app')
<template>
<fan-table :columns="columns" :table-data="tableData" :max-height="400"/>
</template>
<script >
export default {
data() {
return {
columns: [
{ field: "name", key: "a", title: "Name", align: "center" },
{ field: "date", key: "b", title: "Date", align: "left" },
{ field: "hobby", key: "c", title: "Hobby", align: "right" },
{ field: "address", key: "d", title: "Address" },
],
tableData: [
{
name: "John",
date: "1900-05-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Shanghai",
},
{
name: "Dickerson",
date: "1910-06-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Beijing",
},
{
name: "Larsen",
date: "2000-07-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Chongqing",
},
{
name: "Geneva",
date: "2010-08-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Xiamen",
},
{
name: "Jami",
date: "2020-09-20",
hobby: "coding and coding repeat",
address: "No.1 Century Avenue, Shenzhen",
},
],
};
},
};
</script>
<template>
<div class="spreadsheet">
<fan-table style="word-break: break-word" fixed-header :scroll-width="0" :max-height="500" border-y :columns="columns"
:table-data="tableData" row-key-field-name="rowKey" :virtual-scroll-option="virtualScrollOption"
:cell-autofill-option="cellAutofillOption" :edit-option="editOption"
:contextmenu-body-option="contextmenuBodyOption" :contextmenu-header-option="contextmenuHeaderOption"
:row-style-option="rowStyleOption" :column-width-resize-option="columnWidthResizeOption" />
</div>
</template>
<script lang="jsx">
const COLUMN_KEYS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']
export default {
name: 'SpreadSheet',
data() {
return {
// start row index
startRowIndex: 0,
columnWidthResizeOption: {
enable: true,
},
virtualScrollOption: {
// 是否开启
enable: true,
scrolling: this.scrolling,
},
cellAutofillOption: {
directionX: true,
directionY: true,
beforeAutofill: ({
direction,
sourceSelectionRangeIndexes,
targetSelectionRangeIndexes,
sourceSelectionData,
targetSelectionData,
}) => { },
afterAutofill: ({
direction,
sourceSelectionRangeIndexes,
targetSelectionRangeIndexes,
sourceSelectionData,
targetSelectionData,
}) => { },
},
// edit option 可控单元格编辑
editOption: {
beforeCellValueChange: ({ row, column, changeValue }) => { },
afterCellValueChange: ({ row, column, changeValue }) => { },
},
// contextmenu header
contextmenuHeaderOption: {
// before contextmenu show. 你可以在这里更改 contextmenu 配置
beforeShow: ({
isWholeColSelection,
selectionRangeKeys,
selectionRangeIndexes,
}) => {
// do something
},
afterMenuClick: ({
type,
selectionRangeKeys,
selectionRangeIndexes,
}) => {
// do something
},
contextmenus: [
{ type: 'CUT', },
{ type: 'COPY', },
{ type: 'SEPARATOR', },
{ type: 'EMPTY_COLUMN', },
{ type: 'SEPARATOR', },
{ type: 'LEFT_FIXED_COLUMN_TO', },
{ type: 'CANCEL_LEFT_FIXED_COLUMN_TO', },
{ type: 'RIGHT_FIXED_COLUMN_TO', },
{ type: 'CANCEL_RIGHT_FIXED_COLUMN_TO', },
],
},
contextmenuBodyOption: {
// before contextmenu show. 你可以在这里更改 contextmenu 配置
beforeShow: ({
isWholeRowSelection,
selectionRangeKeys,
selectionRangeIndexes,
}) => {
console.log('---contextmenu body beforeShow--')
console.log('isWholeRowSelection::', isWholeRowSelection)
console.log('selectionRangeKeys::', selectionRangeKeys)
console.log(
'selectionRangeIndexes::',
selectionRangeIndexes,
)
},
afterMenuClick: ({
type,
selectionRangeKeys,
selectionRangeIndexes,
}) => {
console.log('---contextmenu body afterMenuClick--')
console.log('type::', type)
console.log('selectionRangeKeys::', selectionRangeKeys)
console.log('selectionRangeIndexes::', selectionRangeIndexes)
},
contextmenus: [
{ type: 'CUT', },
{ type: 'COPY', },
{ type: 'SEPARATOR', },
{ type: 'INSERT_ROW_ABOVE', },
{ type: 'INSERT_ROW_BELOW', },
{ type: 'SEPARATOR', },
{ type: 'REMOVE_ROW', },
{ type: 'EMPTY_ROW', },
{ type: 'EMPTY_CELL', },
],
},
rowStyleOption: {
clickHighlight: false,
hoverHighlight: false,
},
tableData: [],
}
},
computed: {
// current local
columns() {
let columns = [
{
field: 'index',
key: 'index',
// is operation column
operationColumn: true,
title: '',
width: 55,
fixed: 'left',
renderBodyCell: this.renderRowIndex,
},
]
columns = columns.concat(
COLUMN_KEYS.map((keyValue) => {
return {
title: keyValue,
field: keyValue,
key: keyValue,
width: 90,
edit: true,
}
}),
)
return columns
},
},
created() {
this.initTableData()
},
methods: {
// 渲染 row index
renderRowIndex({ row, column, rowIndex }) {
return (<span>{rowIndex + this.startRowIndex + 1}</span>)
},
scrolling({
startRowIndex,
visibleStartIndex,
visibleEndIndex,
visibleAboveCount,
visibleBelowCount,
}) {
this.startRowIndex = startRowIndex
},
initTableData() {
const tableData = []
for (let i = 0; i < 5000; i++) {
const dataItem = {
rowKey: i,
}
COLUMN_KEYS.forEach((keyValue) => {
dataItem[keyValue] = ''
})
if (i === 1 || i === 3) {
dataItem.C = 'YOU'
dataItem.D = 'CAN'
dataItem.E = 'TRY'
dataItem.F = 'ENTER'
dataItem.G = 'SOME'
dataItem.H = 'WORDS'
dataItem.I = '!!!'
}
tableData.push(dataItem)
}
this.tableData = tableData
},
},
}
</script>
<style lang="less">
.spreadsheet {
padding: 0 100px;
margin: 30px 0;
}
</style>
其它基础组件
Table 组件
开发计划详情可看:https://flowus.cn/share/7fea404b-8e1f-4eaa-8ccf-cacb79a929f6
- [x] 保证项目的打包构建
- [x] 修复升级到 Vue3 后的问题
- [x] 发布文档,并解决文档中遇到的问题,详情查看 文档
- [ ] 新功能添加
- [ ] 添加 hooks
- [ ] 实现导入导出表格为 excel 文件,做成工具
- [ ] 测试
- [x] 舍弃 jest 全局 API 使用 vitest api
- [ ] 调整适配原测试内容
- [ ] 添加新的测试
- [ ] 关注性能和优化
- [ ] 减少 DOM,使用 transform 代替 position:absolute
- [ ] 加上防抖和节流
- [ ] 减少更新渲染卡顿问题(单次渲染时长超过 100ms)
- [ ] 移除过时以及兼容性 API(使用新的 web 标准)
- [ ] setTimeout 优化
- [x] 使用 CSS 变量
- [x] 重写 Loading 组件
- [ ] 异步加载模式,拆分为三步进行加载
- [ ] 使用 TS 重构应用(V1.0)
- [x] 添加 TS 类型支持
- [ ] 组件改写为组合式 API 形式
- [ ] TS 重写组件
- [ ] 最后支持原生(V2.0无框架依赖)
- [ ] 使用 shadow dom 替代
如果没有你想要的的功能,请告诉我
- 所有现代浏览器
Edge | Firefox | Chrome | Safari | Opera |
---|---|---|---|---|
Edge | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
感谢 easytable 原项目工作者们,以及维护者 huangshuwei 🙏,本项目继承自 vue-easytable@2.27.1。
- 点击 ⭐ 让更多的人了解到我们
- 如果你希望参与贡献,欢迎 Pull Request