vue3使用vxe-table制作一个可单击编辑表头和单元格的表格(可添加行和列,右键菜单可删除列和行)
vxe-table我是全局注册的,首先自己去安装好vxe-table。
·
代码只提供思路,很多地方需要优化,硬搬到项目里可能会出错
表格效果
代码部分
vxe-table我是全局注册的,首先自己去安装好vxe-table,版本4.4.2
<div class="tableBox">
<div style="width: calc(100% - 40px)">
<vxe-table
ref="refTable"
border
show-overflow
:data="tableData"
:column-config="{ resizable: true }"
:edit-config="{ trigger: 'click', mode: 'cell', showIcon: false }"
:max-height="285"
:menu-config="menuConfig"
@menu-click="contextMenuClickEvent"
>
<vxe-column
v-for="(item, index) in columns"
:key="index"
:field="item.field"
:title="item.title"
:edit-render="{ autofocus: '.vxe-input--inner' }"
min-width="100"
>
<template #header>
<div v-if="titleEdit[item.title]">
<vxe-input
v-if="titleEdit[item.title]"
ref="inputRef"
v-model="titleEdit[item.title].title"
@blur="saves(item.title)"
></vxe-input>
</div>
<div
v-else
style="height: 34px; line-height: 34px"
@click="edits(item.title)"
>
{{ item.title }}
</div>
</template>
<template #edit="{ row }">
<vxe-input v-model="row[item.field]" type="text"></vxe-input>
</template>
</vxe-column>
</vxe-table>
</div>
<div class="AddColumn" @click="addColumn"><span>+</span></div>
</div>
<div class="AddRow" @click="addRow"><span>+</span></div>
import { defineComponent, ref, computed, reactive, nextTick, watch } from 'vue'
import { cloneDeep } from 'lodash-es'
setup(props, { emit }) {
const refTable = ref(null)
const inputRef = ref()
const tableData = ref<RowVO[]>([
{
id: 1,
column1: '例:1',
column2: '500',
column3: '200',
column4: '800',
column5: '700',
column6: '630',
},
])
const columns = ref([
{
id: 1,
title: '',
field: 'column1',
},
{
id: 2,
title: '2019-01',
field: 'column2',
},
{
id: 3,
title: '2019-02',
field: 'column3',
},
{
id: 4,
title: '2019-03',
field: 'column4',
},
{
id: 5,
title: '2019-04',
field: 'column5',
},
{
id: 6,
title: '2019-05',
field: 'column6',
},
])
//添加行
const addRow = () => {
let array = []
const num = tableData.value.reduce((pre, cur) => {
array.push(cur.id)
pre = Math.max(...array)
return pre
}, 0)
//深拷贝第一行数据获取属性名,如果不用深拷贝会删掉表格原始数据导致下面contextMenuClickEvent函数获取不到row数据
let columnObj = JSON.parse(JSON.stringify(tableData.value[0]))
//表格的每一条数据都会被加上_X_ROW_KEY属性,表格用来获取指定行数据,这里我们不需要
delete columnObj._X_ROW_KEY
let objKey = Object.keys(columnObj)
let newData = {}
objKey.forEach((item) => {
if (item == 'id') {
newData['id'] = num + 1
} else {
newData[item] = ''
}
})
tableData.value.push(newData)
}
//添加列
const addColumn = () => {
let array = []
const num = columns.value.reduce((pre, cur) => {
array.push(cur.id)
pre = Math.max(...array)
return pre
}, 0)
const newColumn = {
id: num + 1,
field: `column${num + 1}`,
title: `column${num + 1}`,
}
columns.value.push(newColumn)
tableData.value.forEach((item) => {
item[`column${num + 1}`] = ''
})
}
const titleEdit = reactive({}) //用来判断点击的表头单元格
//点击切换表头为input输入框
const edits = (id: number) => {
titleEdit[id] = cloneDeep(
columns.value.filter((item) => id === item.id)[0],
)
//自动获取焦点 vxe-table自带focus()事件
nextTick(() => {
inputRef.value.map((item) => {
item.focus()
})
})
}
//点击保存将 input框的值给columns
const saves = (id: number) => {
if (!titleEdit[id]) return
Object.assign(
columns.value.filter((item) => id === item.id)[0],
titleEdit[id],
)
delete titleEdit[id]
}
//右键菜单配置
const menuConfig = reactive<VxeTablePropTypes.MenuConfig<RowVO>>({
header: {
options: [[{ code: 'removeCol', name: '删除列' }]],
},
body: {
options: [[{ code: 'removeRow', name: '删除行' }]],
},
})
//菜单选项处理逻辑
const contextMenuClickEvent: VxeTableEvents.MenuClick<RowVO> = ({
$table,
column,
menu,
row,
}) => {
if ($table) {
switch (menu.code) {
case 'removeCol':
//留一列防止删除完
if (columns.value.length === 1) return
columns.value = columns.value.filter(
(item) => item.field !== column.field,
)
tableData.value.forEach((item) => {
delete item[column.field]
})
break
case 'removeRow':
//留一行防止删除完
if (tableData.value.length === 1) return
tableData.value = tableData.value.filter(
(item) => item.id !== row.id,
)
break
}
}
}
//监听表头数据变化
watch(
() => columns.value,
(val) => {
console.log(val)
},
{
deep: true,
immediate: true,
},
)
//监听单元格数据变化
watch(
() => tableData.value,
(val) => {
console.log(val)
},
{
deep: true,
immediate: true,
},
)
return {
tableData,
columns,
addRow,
addColumn,
edits,
saves,
refTable,
titleEdit,
inputRef,
menuConfig,
contextMenuClickEvent,
}
},
//css部分
//表头内边距
::v-deep(.vxe-table--render-default .vxe-header--column:not(.col--ellipsis)) {
padding: 5px 0;
}
//清除表格背景
::v-deep(.vxe-table--header-wrapper) {
background-color: transparent !important;
}
.tableBox {
// padding: 0 0 30px;
display: flex;
justify-content: flex-start;
cursor: pointer;
.AddColumn {
display: flex;
justify-content: center;
align-items: center;
border-top: 1px solid rgba(0, 0, 0, 0.15);
border-right: 1px solid rgba(0, 0, 0, 0.15);
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
width: 40px;
height: auto;
span {
font-size: 25px;
color: rgba(0, 0, 0, 0.25);
user-select: none;
}
cursor: pointer;
}
}
.AddRow {
display: flex;
justify-content: center;
align-items: center;
// margin-bottom: 30px;
border-top: 1px solid rgba(0, 0, 0, 0.15);
border-left: 1px solid rgba(0, 0, 0, 0.15);
border-right: 1px solid rgba(0, 0, 0, 0.15);
border-bottom: 1px solid rgba(0, 0, 0, 0.15);
width: calc(100% - 40px);
height: 40px;
span {
font-size: 25px;
color: rgba(0, 0, 0, 0.25);
user-select: none;
}
cursor: pointer;
}
更多推荐
已为社区贡献1条内容
所有评论(0)