Vue实现在当前表格数据复制后可编辑、保存功能代码

本文介绍如何在Vue项目中实现数据列表的复制功能,并支持复制后的数据编辑与保存。通过具体代码示例展示了如何利用Vue的特性来实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在用vue做项目的时候遇到一个在当前数据列表里面实现可复制,并且可以编辑然后保存功能,如果是单纯的复制,那很简单,直接往数据里面添加一条数据就可以了。
但是需求是要求复制,并可以编辑保存。自己想了一下,然后写了一些demo.

最终效果如下图所示:

这里写图片描述

代码如下:

<template>
  <div class="demo">
    <div class="weightbox" v-show="weight.isShow">
      <span v-for="(item, index) in weight.data" :key="index" @click="chooseWeight(index, weight.index)">
        <label>{{item.name}}<input type="radio" name="a" @click="stopPropa()"></label>
      </span>
    </div>
    <table>
      <tr>
        <td>姓名</td>
        <td>身高</td>
        <td>体重</td>
        <td>等级</td>
        <td style="width:350px;">操作</td>
      </tr>
      <tr v-for="(item, index) in items" :key="index">
        <td>
          <p v-show="!item.isClone">{{item.name}}</p>
          <input type="text" v-model="item.name" v-show="item.isClone"/>
        </td>
        <td>
          <p v-show="!item.isClone">{{item.hight}}</p>
          <input type="text" v-model="item.hight" v-show="item.isClone"/>
        </td>
        <td>
          <p v-show="!item.isClone">{{item.weight.name}}</p>
          <input type="text" v-model="item.weight.name" v-show="item.isClone" @click="showWeight(item.weight.id, index)" readonly class="ds-select" style="cursor: pointer;"/>
        </td>
        <td>
          <p v-show="!item.isClone">{{item.rank.name}}</p>
          <select v-model="item.rank.id" v-show="item.isClone" class="ds-select">
            <option value="1">一级</option>
            <option value="2">二级</option>
            <option value="3">三级</option>
          </select>
        </td>
        <td>
          <p v-show="!item.isClone">
            <span>查看</span>
            <span @click="del(index, item.id)">删除</span>
            <span>修改</span>
            <span @click="useclone(item.id, index)">复制</span>
          </p>
          <p v-show="item.isClone">
            <span @click="save(index)">保存</span>
            <span>刷新</span>
            <span @click="del(index, item.id)">删除</span>
          </p>
        </td>
      </tr>
    </table>
  </div>
</template>
<script type="text/javascript">
  export default {
    name: 'tb',
    data () {
      return {
        items: [{
          id: 1,
          name: 'zhansgan1',
          hight: '168cm',
          weight: {id: 1, name: '168kg'},
          rank: {id: 1, name: '一级1'},
          isClone: false
        }, {
          id: 2,
          name: 'zhansgan2',
          hight: '168cm',
          weight: {id: 2, name: '167kg'},
          rank: {id: 2, name: '一级2'},
          isClone: false
        }, {
          id: 3,
          name: 'zhansgan3',
          hight: '168cm',
          weight: {id: 3, name: '166kg'},
          rank: {id: 3, name: '一级3'},
          isClone: false
        }],
        rank: [],
        weight: {
          data: [{
            id: 1,
            name: '168kg'
          }, {
            id: 2,
            name: '167kg'
          }, {
            id: 3,
            name: '166kg'
          }],
          index: -100,
          isShow: false
        }
      };
    },
    methods: {
      // 复制用户
      useclone (id, index) {
        let arr = this.items.slice(index, index + 1)[0];
        // 注意:转成json再反转回来,不能直接使用赋值,不然会和复制的一层公用同一个内存单元地址,会得到一样的结果
        let obj = JSON.stringify(arr);
        let newObj = JSON.parse(obj);
        console.log(newObj);
        /** 这里可以对复制的数据进行操作 ***/
        newObj.name = ''; // 清空名字
        newObj.isClone = true; // 显示操作按钮
        /** 这里可以对复制的数据进行操作 ***/
        this.items.splice(index + 1, 0, newObj);
      },
      // 选择体重弹窗
      showWeight (id, index) {
          this.weight.isShow = true;
          this.weight.index = index;
          console.log(this.weight);
      },
      // 体重弹窗选择对应体重
      chooseWeight (index, dbIndex) {
          console.log(this.items[dbIndex]);
          console.log(this.weight.data[index]);
          this.items[dbIndex].weight = this.weight.data[index];
      },
      // 保存用户信息
      save (index) {
        alert(JSON.stringify(this.items[index]));
        console.log(this.items[index]);
      },
      // 删除用户信息
      del (index, userId) {
        this.items.splice(index, 1);
        console.log(userId);
      },
      // 阻止冒泡
      stopPropa () {
        let e = event || window.event;
        e.stopPropagation();
        return false;
      }
    },
    created () {
      // 初始化rank
      this.rank = [{
        id: 1,
        name: '一级1'
      }, {
        id: 2,
        name: '一级2'
      }, {
        id: 3,
        name: '一级3'
      }];
    }
  };

</script>
<style lang="less">
    #layout{display:none;}
    table{
      border:1px solid #ccc;
      width:1000px;
      margin:50px auto;
      color:#333;
    }
    .weightbox{height:100px;width:400px;margin:50px auto;}
    .weightbox span{padding:10px;border:1px solid #ccc;color:#333;}
    .weightbox span input[type='radio']{-webkit-appearance:radio;}
    .ds-select{-webkit-appearance:menulist;}
    table td{height:50px;border:1px solid #ccc;text-align:center;}
    table td span{color:blue;cursor: pointer;}
    table td input{width:100px;height:30px;background:none;}
    table td select{width:100px;height:30px;background:none;}
</style>

### 如何在 Element Plus 中实现可编辑表格功能 #### 实现概述 为了实现在 Element Plus 的 `el-table` 组件中支持行内直接编辑输入框、单选或多选框以及复选框等功能,可以通过监听单元格事件动态切换渲染模式来完成。具体来说,可以利用 Vue 3 的响应式特性绑定数据模型,通过状态管理控制当前正在编辑的单元格位置。 以下是详细的实现方式: --- #### 数据结构设计 定义一个对象用于存储表格的状态信息,例如当前正被编辑的行索引和列索引: ```javascript const state = reactive({ tableData: [], // 表格数据源 tableRowEditIndex: null, // 当前行编辑索引 tableColumnEditIndex: null, // 当前列编辑索引 }); ``` 当用户点击某个单元格进入编辑模式时,更新上述两个属性即可[^1]。 --- #### 单元格编辑逻辑 对于不同的字段类型(如字符串、布尔值等),可以根据实际需求自定义对应的编辑器组件。例如,针对文本类型的字段提供 `<el-input>` 输入框;而对于布尔型字段,则使用 `<el-checkbox>` 或者 `<el-radio-group>`。 下面是一个简单的例子展示如何根据不同条件渲染合适的控件: ```html <template> <el-table :data="tableData"> <!-- 遍历每一列 --> <el-table-column v-for="(column, index) in columns" :key="index" :label="column.label"> <template #default="{ row }"> <div v-if="isEditing(row, column)"> <!-- 编辑状态下显示相应控件 --> <component :is="getEditorComponent(column.type)" v-model="row[column.property]" /> </div> <span v-else>{{ row[column.property] }}</span> <!-- 默认只读视图 --> </template> </el-table-column> </el-table> </template> <script setup> import { computed } from 'vue'; // 假设这是你的表头配置数组 const columns = [ { label: '姓名', property: 'name', type: 'text' }, { label: '性别', property: 'gender', type: 'select' } ]; function isEditing(row, column) { const rowIndex = tableData.indexOf(row); return state.tableRowEditIndex === rowIndex && state.tableColumnEditIndex === column.index; } function getEditorComponent(type) { switch (type) { case 'text': return 'el-input'; case 'select': return 'el-select'; // 自己扩展更多选项... default: throw new Error(`Unsupported editor type "${type}"`); } } </script> ``` 此代码片段展示了基于不同列的数据类型动态决定应该呈现哪种形式的交互界面[^2]。 --- #### 更新操作处理 每当用户修改了一个值之后都需要及时保存更改到服务器端或者本地缓存起来等待批量提交。这里给出了一种通用做法——借助工具函数封装 API 调用过程中的细节部分。 ```typescript export async function editRemarksFunc(apiUrl:string,data:any){ try{ await axios.post(apiUrl,{id:data.id,value:data.newValue}) console.log(`${data.id} updated successfully`) }catch(error){ alert('Failed to update record.') } } ``` 调用该方法可以在每次确认改动后立即触发网络请求同步最新情况给后台数据库. 另外还有一种更灵活的方式就是先收集所有的变更记录等到最后再统一发送过去减少频繁通信带来的性能开销. --- #### 添加右键菜单增强体验(可选) 如果希望进一步提升用户体验还可以考虑加入上下文菜单允许快速访问某些特定命令比如复制粘贴删除等等. ```css /* CSS */ .context-menu { position:absolute; background-color:white; border:solid thin black; padding:.5em; z-index:999; } ``` 配合 JavaScript 监听鼠标按下事件定位弹窗位置同时阻止默认行为防止页面跳转影响正常浏览流程[^3]. ```javascript document.addEventListener('contextmenu',(e)=>{ e.preventDefault(); let menu=document.querySelector('.context-menu'); if(!menu){ menu=createMenu(); document.body.appendChild(menu); } const rect=e.target.getBoundingClientRect(); menu.style.left=`${rect.left}px`; menu.style.top=`${rect.bottom}px`; },false); function createMenu(){ const div=document.createElement('div'); div.className='context-menu'; ['Cut','Copy','Paste'].forEach(item=>{ const btn=document.createElement('button'); btn.textContent=item.toLowerCase(); btn.onclick=()=>console.warn(`Action ${item}`); div.append(btn,' '); }); return div; } ``` 这样就完成了基本的功能开发同时也兼顾到了一些额外的小技巧让整体看起来更加完善实用性强很多哦! ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值