基于ant-design-vue实现这样的表格

需求分析:

1、表格每一行为input组件,可以输入

2、操作栏可以进行表格行的新增下一行和删除该行,

3、参数名称和参数别名是必填的,未填写时给出input框标红,并且不让进行新增下一行

实现代码如下:

<template>
  <a-table :columns="columns" :data-source="dataSource" bordered :pagination="false" :scroll="{ y: 300 }" class="edit-table">
    <template #bodyCell="{ column, record }">
      <template v-if="column.dataIndex === 'paramsName'">
        <a-input :placeholder="`${column.title}`" v-model:value="editTable[record.id][column.dataIndex]" :class="`name${record.id}`"></a-input>
      </template>
      <template v-if="column.dataIndex === 'paramsAlia'">
        <a-input :placeholder="`${column.title}`" v-model:value="editTable[record.id][column.dataIndex]" :class="'alias' + record.id"></a-input>
      </template>
      <template v-if="column.dataIndex === 'paramsValue'">
        <a-input :placeholder="`${column.title}`" v-model:value="editTable[record.id][column.dataIndex]"></a-input>
      </template>
      <template v-if="column.dataIndex === 'operation'">
        <plus-circle-filled style="color: var(--ant-success-color);font-size: 16px;margin-right: 5px;" @click="handleField('add', record)" />
        <minus-circle-filled style="color: var(--ant-error-color); font-size: 16px;" @click="handleField('delete', record)" />
      </template>
    </template>
  </a-table>
</template>
<script lang="ts">
import { cloneDeep } from 'lodash-es'
import { defineComponent, ref, reactive, watch, onMounted } from 'vue'
import { PlusCircleFilled, MinusCircleFilled } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue/es'

const columns = ref<any[]>([
  {
    title: '参数名称',
    dataIndex: 'paramsName',
    width: '20%',
    align: 'center'
  },
  {
    title: '参数别名',
    dataIndex: 'paramsAlia',
    width: '20%',
    align: 'center'
  },
  {
    title: '参数值',
    dataIndex: 'paramsValue',
    align: 'center'
  },
  {
    title: '操作',
    width: '12%',
    dataIndex: 'operation',
    align: 'center'
  }
])
interface DataItem {
  id?: string
  paramsName?: string
  paramsAlia?: string
  paramsValue?: string
}
export default defineComponent({
  emits: ['customField'],
  setup(_props, _context) {
    //字段保存的数据
    const editTable = reactive<any>({
      '1': {
        id: '1',
        paramsName: '',
        paramsAlia: '',
        paramsValue: ''
      }
    })

    // 表格默认数据
    const dataSource = ref<DataItem[]>([
      {
        id: '1',
        paramsName: '',
        paramsAlia: '',
        paramsValue: ''
      }
    ])

      // 参数名称下一个dom
    const currNextName = ref<HTMLElement>()
    // 参数别名下一个dom
    const currNextAlias = ref<HTMLElement>()

    // 监听input框的focus事件,消除未填写提示
    watch(currName, nv => {
      nv?.addEventListener('focus', function () {
        nv.style.borderColor = ''
        nv.style.boxShadow = ''
      })
    })
    watch(currAlias, nv => {
      nv?.addEventListener('focus', function () {
        nv.style.borderColor = ''
        nv.style.boxShadow = ''
      })
    })
    // 发送父组件实时数据
    watch(
      () => editTable,
      nv => {
        _context.emit('customField', nv)
      },
      { deep: true }
    )
    const handleField = (val: string, record: any) => {
      // 新增行
      if (val === 'add') {
        // 控制当前行字段是否填写
        if (editTable[record.id].paramsName === '') {
          nextTick(() => {
           let currName = document.querySelector(`.name${record.id}`) as HTMLInputElement
           currName.style.borderColor = 'var(--polar-error-color-hover)'
           currName.style.boxShadow = '0 0 0 1px #F59B9B'
          })
          return message.error('参数名称不能为空!')
        }
        if (editTable[record.id].paramsAlia === '') {
          nextTick(() => {
            let currAlias = document.querySelector(`.alias${record.id}`) as HTMLInputElement
            currAlias.style.borderColor = 'var(--polar-error-color-hover)'
            currAlias.style.boxShadow = '0 0 0 1px #F59B9B'
          })
          return message.error('参数别名不能为空!')
        }
        let obj = {
          id: new Date().getTime().toString(),
          paramsName: '',
          paramsAlia: '',
          paramsValue: ''
        }
        editTable[obj.id] = cloneDeep(obj)
        dataSource.value.push({ id: obj.id })
      
      } else {
        // 删除行
        if (record.id === '1') return
        let currIndex = dataSource.value.findIndex(item => item.id === record.id)
        if (currIndex !== -1) {
          dataSource.value.splice(currIndex, 1)
        }
        delete editTable[record.id]
      }
    }
    return {
      dataSource,
      columns,
      editTable,
      handleField
    }
  }
})
</script>

以上代码可以实现逻辑功能,但是有个bug是点击时点击必填字段不为空的情况下,新增一行后,再次点击①这个新增按钮,还会新增一行,原因是每次判断是否为空的时候,我都是根据点击的这样的id去找 editTable对象中的值进行判空,只要这一行的字段不为空就增加一行,但是下面已经有一行为空的了,理论上不应该在新增一行空,而是提示下一行不能为空,

所以思路不能仅仅根据当前行是否字段为空进行判断,而应该根据保存数据得到editTable这个整体对象循环判断那个子对象为空进行判空处理:

逻辑如下:

   // 控制非当前行字段是否填写
        for (let item in editTable) {
          if (editTable[item].paramsName === '') {
            nextTick(() => {
              if (currNextName.value) {
                currNextName.value.style.borderColor = 'var(--polar-error-color-hover)'
                currNextName.value.style.boxShadow = '0 0 0 1px #F59B9B'
              }
            })
            return message.error('参数名称不能为空!')
          }
          if (editTable[item].paramsAlia === '') {
            nextTick(() => {
              if (currNextAlias.value) {
                currNextAlias.value.style.borderColor = 'var(--polar-error-color-hover)'
                currNextAlias.value.style.boxShadow = '0 0 0 1px #F59B9B'
              }
            })
            return message.error('参数别名不能为空!')
          }
        }

 为了首行未填写出现提示后,消除未填写提示,必须赋值,否则监听input中focus拿不到currNextName,为空值

    onMounted(() => {
      // 初始化默认值
      currNextName.value = document.querySelector(`.name${dataSource.value[0].id}`) as HTMLElement
      currNextAlias.value = document.querySelector(`.alias${dataSource.value[0].id}`) as HTMLElement
    })

并且为了解决上面bug的问题,必须控制点击新增下一行的时候,把当前保存 dom结点更新为最新下一行的dom数据,这样每次点击都可以找到新一行的字段,提示未填写

       nextTick(() => {
          currNextName.value = document.querySelector(`.name${obj.id}`) as HTMLInputElement
          currNextAlias.value = document.querySelector(`.alias${obj.id}`) as HTMLInputElement
        })

完整代码如下:

     

<script lang="ts">
import { cloneDeep } from 'lodash-es'
import { defineComponent, ref, reactive, watch, onMounted } from 'vue'
import { PlusCircleFilled, MinusCircleFilled } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue/es'

const columns = ref<any[]>([
  {
    title: '参数名称',
    dataIndex: 'paramsName',
    width: '20%',
    align: 'center'
  },
  {
    title: '参数别名',
    dataIndex: 'paramsAlia',
    width: '20%',
    align: 'center'
  },
  {
    title: '参数值',
    dataIndex: 'paramsValue',
    align: 'center'
  },
  {
    title: '操作',
    width: '12%',
    dataIndex: 'operation',
    align: 'center'
  }
])
interface DataItem {
  id?: string
  paramsName?: string
  paramsAlia?: string
  paramsValue?: string
}
export default defineComponent({
  emits: ['customField'],
  setup(_props, _context) {
    //字段保存的数据
    const editTable = reactive<any>({
      '1': {
        id: '1',
        paramsName: '',
        paramsAlia: '',
        paramsValue: ''
      }
    })

    // 表格默认数据
    const dataSource = ref<DataItem[]>([
      {
        id: '1',
        paramsName: '',
        paramsAlia: '',
        paramsValue: ''
      }
    ])

    // 参数名称下一个dom
    const currNextName = ref<HTMLElement>()
    // 参数别名下一个dom
    const currNextAlias = ref<HTMLElement>()
    onMounted(() => {
      // 初始化默认值
      currNextName.value = document.querySelector(`.name${dataSource.value[0].id}`) as HTMLElement
      currNextAlias.value = document.querySelector(`.alias${dataSource.value[0].id}`) as HTMLElement
    })
    // 监听input框的focus事件,消除未填写提示
    watch(currNextName, nv => {
      nv?.addEventListener('focus', function () {
        nv.style.borderColor = ''
        nv.style.boxShadow = ''
      })
    })
    watch(currNextAlias, nv => {
      nv?.addEventListener('focus', function () {
        nv.style.borderColor = ''
        nv.style.boxShadow = ''
      })
    })
    // 发送父组件实时数据
    watch(
      () => editTable,
      nv => {
        _context.emit('customField', nv)
      },
      { deep: true }
    )
    const handleField = (val: string, record: any) => {
      // 新增行
      if (val === 'add') {
        // 控制当前行字段是否填写
        if (editTable[record.id].paramsName === '') {
          nextTick(() => {
           let currName = document.querySelector(`.name${record.id}`) as HTMLInputElement
           currName.style.borderColor = 'var(--polar-error-color-hover)'
           currName.style.boxShadow = '0 0 0 1px #F59B9B'
          })
          return message.error('参数名称不能为空!')
        }
        if (editTable[record.id].paramsAlia === '') {
          nextTick(() => {
            let currAlias = document.querySelector(`.alias${record.id}`) as HTMLInputElement
            currAlias.style.borderColor = 'var(--polar-error-color-hover)'
            currAlias.style.boxShadow = '0 0 0 1px #F59B9B'
          })
          return message.error('参数别名不能为空!')
        }
        // 控制非当前行字段是否填写
        for (let item in editTable) {
          if (editTable[item].paramsName === '') {
            nextTick(() => {
              if (currNextName.value) {
                currNextName.value.style.borderColor = 'var(--polar-error-color-hover)'
                currNextName.value.style.boxShadow = '0 0 0 1px #F59B9B'
              }
            })
            return message.error('参数名称不能为空!')
          }
          if (editTable[item].paramsAlia === '') {
            nextTick(() => {
              if (currNextAlias.value) {
                currNextAlias.value.style.borderColor = 'var(--polar-error-color-hover)'
                currNextAlias.value.style.boxShadow = '0 0 0 1px #F59B9B'
              }
            })
            return message.error('参数别名不能为空!')
          }
        }
        let obj = {
          id: new Date().getTime().toString(),
          paramsName: '',
          paramsAlia: '',
          paramsValue: ''
        }
        editTable[obj.id] = cloneDeep(obj)
        dataSource.value.push({ id: obj.id })
        nextTick(() => {
          currNextName.value = document.querySelector(`.name${obj.id}`) as HTMLInputElement
          currNextAlias.value = document.querySelector(`.alias${obj.id}`) as HTMLInputElement
        })
      } else {
        // 删除行
        if (record.id === '1') return
        let currIndex = dataSource.value.findIndex(item => item.id === record.id)
        if (currIndex !== -1) {
          dataSource.value.splice(currIndex, 1)
        }
        delete editTable[record.id]
      }
    }
    return {
      dataSource,
      columns,
      editTable,
      handleField
    }
  }
})
</script>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: ant-design-vue是一个基于Vue.js的UI组件库,提供了丰富的组件供开发者使用。在ant-design-vue,我们可以使用表格组件来展示和编辑数据,同时还可以进行表格的校验。 在ant-design-vue表格,我们可以通过配置rules属性来实现校验功能。每个表格列都可以设置rules属性,该属性接受一个数组,数组每个对象代表一条校验规则。 每条校验规则对象需要指定validator属性,该属性是一个函数,用来校验对应表格列的数据。在validator函数,我们可以根据具体需求编写校验逻辑,比如判断输入是否为空、是否满足特定格式等。validator函数需要返回一个Boolean值,true表示校验成功,false表示校验失败。 除了validator函数外,校验规则对象还可以指定message属性,用来定义校验失败时的提示信息。当校验失败时,ant-design-vue会自动显示message的内容。 在表格使用校验功能时,我们可以通过监听表单提交事件来进行校验。在提交事件,我们可以通过表格的validate方法来执行校验操作。validate方法会遍历所有表格列的校验规则,根据规则来验证数据。如果所有校验规则都通过,则提交成功;如果存在校验失败的规则,则提交失败,并且会自动显示相应的提示信息。 总结来说,通过ant-design-vue内置的校验功能,我们可以方便地对表格的数据进行校验,提高用户输入的准确性和数据的可靠性。 ### 回答2: ant-design-vue(以下简称AntD)提供了一种方便的方式来实现表格校验。在AntD表格校验是通过自定义校验规则和使用校验器函数来实现的。 首先,我们需要创建一个自定义的校验规则对象。可以使用AntD提供的`Validators`来创建一个规则对象,例如: ```javascript import { Validators } from 'ant-design-vue'; const customValidationRule = Validators.pattern(/\d+/); ``` 上述代码创建了一个校验规则对象,该规则会检查输入值是否匹配正则表达式`/\d+/`,即是否为数字。 接下来,我们需要在表格的列定义使用该校验规则。在AntD的Table组件的columns属性,我们可以使用`scopedSlots`来自定义列的渲染方式。在这里,我们可以使用`edit`字段来实现可编辑的单元格,并应用校验规则。 ```javascript const columns = [ { title: '姓名', dataIndex: 'name', scopedSlots: { customRender: 'name', edit: (text, record, index) => { return ( <a-input v-decorator={['name', { rules: [{ validator: customValidationRule }] }]} placeholder='请输入姓名' /> ) } } }, // 其他列... ]; ``` 上述代码的`v-decorator`用于绑定校验规则,`rules`属性用于指定校验规则对象。此处我们使用了之前创建的`customValidationRule`规则。在用户输入时,AntD会自动校验输入是否符合规则。 最后,我们需要对整个表单使用AntD的`Form`组件进行校验。在提交表单时,使用`form.validateFields`方法来手动校验所有字段。 ```javascript <template> <a-form @submit="handleSubmit"> <a-table :columns="columns" :dataSource="data"> <span slot='name' slot-scope='text, record, index'> {{ record.name }} </span> </a-table> <a-button type='primary' html-type='submit'>提交</a-button> </a-form> </template> <script> export default { // ... methods: { handleSubmit() { this.$refs.form.validateFields((errors, values) => { if (errors) { console.log('表格校验未通过'); return; } console.log('表格校验通过'); console.log(values); // 处理表单数据 }); }, }, } </script> ``` 上述代码的`validateFields`方法会遍历表单所有绑定校验规则的字段,并进行校验。如果校验未通过,则会通过`errors`参数返回错误信息。如果校验通过,则`values`参数会返回表格所有的字段值。 这就是AntD实现表格校验的方法。我们只需要定义校验规则、在列定义应用规则,并在提交时对整个表单进行校验。这样可以有效地实现表格输入值的校验。 ### 回答3: ant-design-vue 是一个基于 Vue.js 的 UI 组件库,提供了丰富的组件用于开发界面。在 ant-design-vue 表格校验是一个常见的需求。 在 ant-design-vue表格组件,我们可以通过配置校验规则来实现表格校验。首先,我们需要为表格的列定义校验规则。可以使用 `customRender` 属性来自定义渲染表格单元格的内容,并在自定义的渲染函数添加校验规则。 当我们需要对单元格的内容进行校验时,可以使用内置的校验规则,例如,`required` 表示必填项,`min` 和 `max` 表示最小值和最大值。如果内置的校验规则不能满足需求,我们还可以自定义校验规则。 在校验规则,我们可以通过 `validator` 属性来指定校验函数。校验函数接收三个参数:`rule`,`value` 和 `callback`。`rule` 表示当前的校验规则,`value` 表示当前单元格的内容,`callback` 用于异步校验。我们可以在校验函数判断 `value` 是否满足规则,并通过调用 `callback` 返回校验结果。 在校验函数,如果发现校验失败,可以通过 `callback` 返回一个错误信息,这样 ant-design-vue 会自动显示错误提示,并阻止表格单元格内容的修改。 总的来说,ant-design-vue 提供了丰富的表格校验功能,可以通过配置校验规则和自定义校验函数来实现表格数据的校验。这样可以有效地提高数据的准确性和完整性,为用户提供更好的交互体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值