vue、react动态新增行

在开发后台管理系统时基本都会有动态新增行,并可以编辑、保存、删除等功能,这个就需要我们动态添加行时生成唯一id或key (本人使用的时vue-antd UI)

 此处我是在新增行触发编辑功能,所以可以直接编辑

考虑到删除时key的缺失,我们就在data中声明个单独的变量,点击新增使其自++,具体请看代码。里面有不需要代码请忽略

<template>
  <div>
    <div style="max- 80%; margin: 40px auto 0;">
      <a-table :columns="columns" :data-source="data" bordered>
        <template v-for="col in ['cctv_name', 'cctv_rtsp', 'order']" :slot="col" slot-scope="text, record, index">
          <div :key="col">
            <a-input
              v-if="record.editable"
              style="margin: -5px 0"
              :value="text"
              @change="e => handleChange(e.target.value, record.key, col)"
            />
            <template v-else>
              {{ text }}
            </template>
          </div>
        </template>
        <template slot="operation" slot-scope="text, record, index">
          <div class="editable-row-operations">
            <span v-if="record.editable">
              <a href="javascript:;" @click="() => save(record.key)">保存</a>
              <a href="javascript:;" @click="() => cancel(record.key)">取消</a>
            </span>
            <span v-else>
              <a href="javascript:;" :disabled="editingKey !== ''" @click="() => edit(record.key)">编辑</a>
              <a href="javascript:;" @click="() => onDelete(record.key)">删除</a>
            </span>
          </div>
        </template>
      </a-table>
      <a-row type="flex" justify="center" class="video">
        <a href="javascript:;" @click="added()"> + 新增视频点位</a>
      </a-row>
    </div>
    <a-form :form="form" style="max- 500px; margin: 40px auto 0;">
      <a-form-item :wrapperCol="{ span: 19, offset: 5 }">
        <a-button style="margin-right: 10px" @click="prevStep">上一步</a-button>
        <a-button :loading="loading" type="primary" @click="nextStep">下一步</a-button>
      </a-form-item>
    </a-form>
  </div>
</template>

<script>
const columns = [
  {
    title: '视频点位名称',
    dataIndex: 'cctv_name',
     '25%',
    scopedSlots: { customRender: 'cctv_name' }
  },
  {
    title: 'rstp地址',
    dataIndex: 'cctv_rtsp',
     '15%',
    scopedSlots: { customRender: 'cctv_rtsp' }
  },
  {
    title: '排序编号',
    dataIndex: 'order',
     '40%',
    scopedSlots: { customRender: 'order' }
  },
  {
    title: '操作',
    dataIndex: 'operation',
    scopedSlots: { customRender: 'operation' }
  }
]
// const data = [
//   {
//     key: 1,
//     cctv_name: '',
//     cctv_rtsp: null,
//     order: '',
//     cctv_status: 'n'
//   }
// ]
import { CCTV, edge_device } from '@/api/factory'
import bus from '@/Bus'
export default {
  name: 'Step2',
  data() {
    // this.cacheData = data.map(item => ({ ...item }))
    return {
      uniq: '',
      labelCol: { lg: { span: 5 }, sm: { span: 5 } },
      wrapperCol: { lg: { span: 19 }, sm: { span: 19 } },
      form: null,
      loading: false,
      timer: 0,
      newTabIndex: 0, //初始key值
      // 表格
      data:[],
      columns,
      editingKey: '',
      cname: '1', //设备别名
      mport: '11', //管理端口
      vport: '9' //视频端口
    }
  },
  created() {
    // 通过中央控件兄弟传值
    // bus.$on('sendByBus', val => {
    //   console.log(val)
    //   this.cname = val.cname
    //   this.mport = val.mport
    //   this.vport = val.vport
    // })
  },
  mounted() {
    this.uniq = this.$route.query.uniq
    if (this.uniq) {
      this.CCTVInfo()
    }
  },
  methods: {
    CCTVInfo() {
      const params = {
        uniq: this.uniq
      }
      // 回显接口
      CCTV(params).then(res => {
        console.log(res)
      })
    },
    nextStep() {
      console.log(this.data)
      const params = {
        cname: this.cname,
        edge_cctv_array: this.data,
        mport: this.mport,
        vport: this.vport
      }
      // 新建接口
      edge_device(params).then(res => {
        if (res.code === '00000') {
          this.loading = true
          setTimeout(() => {
            this.loading = false
            this.$emit('nextStep')
          }, 1000)
        }
      })
    },
    prevStep() {
      this.$emit('prevStep')
    },
    // 表格
    handleChange(value, key, column) {
      const newData = [...this.data]
      const target = newData.filter(item => key === item.key)[0]
      if (target) {
        target[column] = value
        this.data = newData
      }
    },
    //编辑
    edit(key) {
      console.log(key)
      const newData = [...this.data]
      const target = newData.filter(item => key === item.key)[0]
      this.editingKey = key
      if (target) {
        target.editable = true
        this.data = newData
      }
    },
    //保存
    save(key) {
      console.log(key)

      const newData = [...this.data]
      // const newCacheData = [...this.cacheData]
      const target = newData.filter(item => key === item.key)[0]
      // const targetCache = newCacheData.filter(item => key === item.key)[0]
      if (target) {
        delete target.editable
        this.data = newData
        console.log(this.data)
        // Object.assign(targetCache, target)
        // this.cacheData = newData
        // console.log(this.cacheData)
      }
      this.editingKey = ''
    },
    // 取消
    cancel(key) {
      const newData = [...this.data]
      const target = newData.filter(item => key === item.key)[0]
      this.editingKey = ''
      if (target) {
        // Object.assign(target, this.cacheData.filter(item => key === item.key)[0])
        delete target.editable
        this.data = newData
      }
    },
    // 删除
    onDelete(key) {
      console.log(key)
      const data = [...this.data]
      this.data = data.filter(item => item.key !== key)
    },
    // 新增
    added(val) {
      const activeKey = `newKey${this.newTabIndex++}`
      this.data.push({
        // key: (this.data.length + 1).toString(),
        key: activeKey,
        cctv_name: '',
        cctv_rtsp: null,
        order: '',
        cctv_status: 'n'
      })
      this.edit(activeKey)
    }
  },
  beforeDestroy() {
    clearTimeout(this.timer)
  }
}
</script>

<style lang="less" scoped>
.video {
  margin-top: 3px;
  padding: 3px 0;
  border: 1px dotted #ccc;

  a {
    color: #1890ff;
  }
}
.editable-row-operations a {
  margin-right: 8px;
}
.stepFormText {
  margin-bottom: 24px;

  .ant-form-item-label,
  .ant-form-item-control {
    line-height: 22px;
  }
}
/deep/.ant-table-pagination.ant-pagination {
  display: none;
}
</style>
原文地址:https://www.cnblogs.com/huoshengmiao/p/14775680.html