vue实现可新增、删除、修改、复制、复原及提交的表格

引用vxe-table@4.5.21表格功能

目录

一. 效果展示

二. template

1. vxe-table属性解析

2. vxe-column属性解析

三. script

1. data

2. computed

3. methods

四. style


一. 效果展示

编辑操作

选中单元格

选中行

新增、标记删除、修改、复制

二. template

<vxe-table
  ref="tableRef"
  :data="tableData"
  keep-source
  :edit-config="{ trigger: 'dblclick', mode: 'cell', showStatus: true, enabled: canEdit }"
  style="width: 100%; user-select: text"
  height="100%"
  class="editable-vxe"
  :row-class-name="setRowClassName"
  :cell-class-name="setCellClassName"
  :row-config="{ useKey: true }"
  v-loading="loading"
  border
  :scroll-x="{ enabled: true, gt: 10 }"
  :scroll-y="{ enabled: true, gt: 100 }"
  @cell-click="cellClickEvent"
>
  <vxe-column
    v-for="(item, index) in tableColumn"
    :key="index"
    :field="item.prop"
    :title="item.label"
    show-header-overflow="title"
    min-width="180"
    show-overflow="title"
    :edit-render="{ enabled: !!item.label, autofocus: '.el-input__inner' }"
  >
    <template #edit="{ row }">
      <el-input v-model="row[item.prop]" type="text" :placeholder="setDefaultPlaceHolder(row, item)"></el-input>
    </template>
  </vxe-column>
</vxe-table>
1. vxe-table属性解析

keep-source:需区分编辑样式、做临时删除及还原数据操作的要加上

edit-config:此处选用单元格编辑模式cell,视情况可选行编辑row;showStatus配合keep-source属性可实现区分新增行、修改单元格或行与原数据的样式区分

row-class-name:给原选中行附加类名,修改默认样式

cell-class-name:给原选中单元格附加类名,修改默认样式

row-config:useKey可默认表格每行数据的唯一标识

scroll-x/scroll-y:虚拟滚动配置,大数据量可配

2. vxe-column属性解析

edit-render:autofocus实现打开编辑立刻聚焦文本

placeholder:可设置编辑文本区的默认提示值

相关属性点击查看

三. script

tip: 以下规则均按单一选择设置

1. data
import { VxeTableInstance, VxeTableEvents } from 'vxe-table';
const initTableData = ref<any[]>([]); // 初始数据(用于还原)
const tableData = ref<any[]>([]); // 表格绑定数据
const tableColumn = ref<any[]>([]); // 表格每列相关值(表头、默认提示值、是否可编辑等)
const previewUpdateParams = ref<any>({}); // 预览需携带的相关参数
const tableRef = ref<VxeTableInstance>();  // 表格ref绑定
const currSelectedCell = ref<any[]>([]); // 当前选中(可单一单元格,单行,多单元格,多行)

2. computed
// 是否可编辑
const canEdit = computed(() => {
  // 接口返回是否可编辑状态
  return ...;
});
// 是否可复制
const copyDisabled = computed(() => {
  return !currSelectedCell.value[0]?.row;
});
// 是否可删除
const delDisabled = computed(() => {
  return !currSelectedCell.value[0]?.row;
});
// 是否可撤销所选条目
const cancelDisabled = computed(() => {
  const $table = tableRef.value;
  if ($table && currSelectedCell.value[0]) {
    // isInsertByRow isUpdateByRow可能存在性能问题
    // 复制或新增行
    if (!!$table.isInsertByRow(currSelectedCell.value[0].row)) return false;
    if (
      currSelectedCell.value[0].field &&
      $table.isUpdateByRow(currSelectedCell.value[0].row, currSelectedCell.value[0].field)
    ) {
      // cell
      return false;
    }
    if (!currSelectedCell.value[0].field && $table.isUpdateByRow(currSelectedCell.value[0].row)) {
      // row
      return false;
    }
    // 标记删除
    if (isPendingRecords(currSelectedCell.value[0].row)) {
      return false;
    }
  }
  return true;
});
3. methods

表格属性及事件绑定

onMounted(() => {
  window.addEventListener('dblclick', dblclickEventListenerFn);
});
onUnmounted(() => {
  window.removeEventListener('dblclick', dblclickEventListenerFn);
});
// 此处采取双击表格外区域取消选中
const dblclickEventListenerFn = (event?: any) => {
  currSelectedCell.value = [];
};
const cellClickEvent: VxeTableEvents.CellClick = ({ row, rowIndex, column, columnIndex, $event }) => {
  if (!canEdit.value) return;
  // 默认选中行
  const cellOrRow = {
    row,
    rowIndex,
  };
  if (columnIndex != 0) {
    // 选中单元格
    Object.assign(cellOrRow, { field: column.field, columnIndex });
  }
  // 此处可补充多选(ctrl/shift等操作)
  currSelectedCell.value = [cellOrRow];
};
const setRowClassName = ({ rowIndex }: any) => {
  if (!currSelectedCell.value[0]?.columnIndex && currSelectedCell.value[0]?.rowIndex == rowIndex) {
    return '选中行类名';
  }
  return '';
};
const setCellClassName = ({ rowIndex, columnIndex }: any) => {
  if (currSelectedCell.value[0]?.rowIndex == rowIndex && currSelectedCell.value[0]?.columnIndex == columnIndex) {
    return '选中单元格类名';
  }
  return '';
};
const setDefaultPlaceHolder = (row: any, item: any) => {
  let result = '';
  const $table = tableRef.value;
  if ($table) {
    // 此处设置默认提示值
    ...
  }
  return result;
};

 表格数据获取及操作方法

/**
 * 表格数据获取
 * @param headers 表头数据
 * @param datas 数据映射
 */
const getTableData = (headers: any[], datas: any[]) => {
  const tablePropsMap = {} as any;
  for (let i in headers) {
    tablePropsMap[i] = headers[i].prop;
  }
  let result = [] as any[];
  for (let i in datas) {
    let temp = {} as any;
    for (let j in datas[i]) {
      temp[tablePropsMap[j]] = datas[i][j];
    }
    result.push(temp);
  }
  tableData.value = result;
  initTableData.value = JSON.parse(JSON.stringify(result));
}
/**
 * 表格数据是否新增、编辑、复制及临时删除
 */
const isEdited = () => {
  const $table = tableRef.value;
  let res = false;
  if ($table) {
    const records = $table.getRecordset();
    const { insertRecords, updateRecords, pendingRecords } = records;
    res = [...insertRecords, ...updateRecords, ...pendingRecords].length > 0;
  }
  return res;
};
/**
 * 新增行
 * @param row 指定位置、null从第一行插入、-1 从最后插入
 */
const insertEvent = async (row?: number) => {
  const $table = tableRef.value;
  if ($table) {
    const insertRecords = $table.getInsertRecords();
    const record: any = {};
    tableColumn.value.map((item: any) => {
      record[item.prop] = null;
    })
    record['Row Number'] = tableData.value[tableData.value.length - 1]['Row Number'] * 1 + insertRecords.length + 1
    const { row: newRow } = await $table.insertAt(record, row);
    await $table.setEditCell(newRow, tableColumn.value[1].prop);
  }
};
/**
 * 复制行
 */
const copyEvent = async () => {
  const $table = tableRef.value;
  if ($table && currSelectedCell.value[0]?.row) {
    const insertRecords = $table.getInsertRecords();
    const record = {
      ...currSelectedCell.value[0].row,
      'Row Number': tableData.value[tableData.value.length - 1]['Row Number'] * 1 + insertRecords.length + 1,
    };
    record['_X_ROW_KEY'] && delete record['_X_ROW_KEY'];
    const { row: newRow } = await $table.insertAt(record, -1);
    await $table.setEditCell(newRow, tableColumn.value[1].prop);
  }
};
/**
 * 删除行(原数据做临时删除,新增或复制则直接删除)
 * @param status true:标记为删除,false:还原
 */
const delEvent = (status: boolean) => {
  const $table = tableRef.value;
  if ($table) {   
    if (!!$table.isInsertByRow(currSelectedCell.value[0].row)) {
      // 删除复制或新增行
      $table.remove(currSelectedCell.value[0].row);
    } else {
      // 还原数据
      $table.revertData(currSelectedCell.value[0].row);
      $table.setPendingRow(currSelectedCell.value[0].row, status);
    }
  }
};
/**
 * 撤销所选项目
 */
const cancelSelectedEvent = () => {
  const $table = tableRef.value;
  if ($table) {
    if (isPendingRecords(currSelectedCell.value[0].row)) {
      // 还原临时删除
      delEvent(false);
    } else if (!!$table.isInsertByRow(currSelectedCell.value[0].row)) {
      // 删除复制或新增行
      $table.remove(currSelectedCell.value[0].row);
    } else if (currSelectedCell.value[0].field) {
      // cell
      $table.revertData(currSelectedCell.value[0].row, currSelectedCell.value[0].field);
    } else {
      // row
      $table.revertData(currSelectedCell.value[0].row);
    }
  }
};
/**
 * 预览修改
 */
const previewModify = () => {
  if (!isEdited()) return;
  const $table = tableRef.value;
  if ($table) {
    const records = $table.getRecordset();
    // 新增、临时删除、编辑数据
    const { insertRecords, pendingRecords, updateRecords } = records;
    ...
  }
};
/**
 * 提交修改
 */
const submitModify = () => {
  if (!isEdited()) return;
  ...
};

四. style

以下为参考样式,除选中样式需添加,其余可沿用默认样式

.editable-vxe { 
  .selected-row {
    // 选中行样式
    box-shadow: inset 0 -0.5px 0 2px #00f;
  }
  .selected-cell {
    // 选中单元格样式
    box-shadow: inset 0 0 0 2px #00f;
  }
  .col--dirty {
    background-color: 编辑后的背景色;
    &::before {
      // 屏蔽原样式
      display: none;
    }
  }
  .row--new {
    background-color: 新增或复制后的背景色;
    .vxe-body--column {
      &::before {
        // 屏蔽原样式
        display: none;
      }
    }
  }
  .row--pending {
    background-color: 临时删除的背景色;
    // 覆盖原样式
    color: inherit;
    text-decoration: none;
    cursor: default;
    .vxe-body--column::after {
      display: none;
    }
  }
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
下面是一个使用 Vue.js 和 Mock.js 实现新增编辑删除表格数据的示例。 首先,确保你已经安装了 Vue.js 和 Mock.js。然后,创建一个 Vue 组件,包含一个表格和相应的按钮用于新增编辑删除数据。 HTML 模板代码如下: ```html <div id="app"> <table> <thead> <tr> <th>Name</th> <th>Age</th> <th>Email</th> <th>Action</th> </tr> </thead> <tbody> <tr v-for="(item, index) in items" :key="index"> <td>{{ item.name }}</td> <td>{{ item.age }}</td> <td>{{ item.email }}</td> <td> <button @click="editItem(index)">Edit</button> <button @click="deleteItem(index)">Delete</button> </td> </tr> </tbody> </table> <form @submit.prevent="addItem" v-show="showForm"> <input type="text" v-model="formData.name" placeholder="Name"> <input type="number" v-model="formData.age" placeholder="Age"> <input type="email" v-model="formData.email" placeholder="Email"> <button type="submit">Add</button> </form> <button @click="showForm = true">Add New</button> </div> ``` JavaScript 代码如下: ```javascript // 引入 Mock.js 库 const Mock = require('mockjs'); // 使用 Mock.js 拦截 AJAX 请求并返回随机数据 Mock.mock('/api/items', 'get', { 'items|5-10': [{ 'name': '@cname', 'age|18-60': 0, 'email': '@email' }] }); // 创建 Vue 实例 new Vue({ el: '#app', data() { return { items: [], showForm: false, formData: { name: '', age: '', email: '' }, editingIndex: -1 }; }, mounted() { // 发送 AJAX 请求获取表格数据 this.fetchItems(); }, methods: { fetchItems() { // 模拟发送 AJAX 请求 axios.get('/api/items') .then(response => { this.items = response.data.items; }) .catch(error => { console.error(error); }); }, addItem() { // 模拟发送 AJAX 请求 axios.post('/api/items', this.formData) .then(() => { this.fetchItems(); this.resetForm(); }) .catch(error => { console.error(error); }); }, editItem(index) { this.editingIndex = index; this.formData = { ...this.items[index] }; this.showForm = true; }, updateItem() { // 模拟发送 AJAX 请求 axios.put(`/api/items/${this.editingIndex}`, this.formData) .then(() => { this.fetchItems(); this.resetForm(); }) .catch(error => { console.error(error); }); }, deleteItem(index) { // 模拟发送 AJAX 请求 axios.delete(`/api/items/${index}`) .then(() => { this.fetchItems(); }) .catch(error => { console.error(error); }); }, resetForm() { this.formData = { name: '', age: '', email: '' }; this.editingIndex = -1; this.showForm = false; } } }); ``` 在上述代码中,我们使用 Mock.js 来拦截 `/api/items` 的 GET 请求,并返回随机生成的数据。你可以根据需要修改这个接口的 URL 和响应数据。 注意,在实际的项目中,你需要使用真实的后端 API 来处理新增编辑删除数据的请求,并更新前端的表格数据。这里的代码只是一个简单的示例,使用 Mock.js 模拟这些操作。 当你运行这个示例时,你将看到一个包含表格和按钮的界面。点击 "Add New" 按钮将显示一个表单,你可以在表单中输入数据并点击 "Add" 按钮来新增一行数据。点击表格中的 "Edit" 按钮可以编辑对应行的数据,点击 "Delete" 按钮可以删除对应行的数据。 请注意,示例中使用的是 Mock.js 来模拟 AJAX 请求和返回随机数据,实际项目中需要替换成真实的后端接口。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值