vue3+ts实现复杂表单组件

<template>
  <el-form ref="formRef" :model="formData" :rules="rules">
    <el-table :data="formData.rows" border>
      <el-table-column label="序号" type="index" width="50"></el-table-column>
      <el-table-column label="名称" prop="name">
        <template #default="{ row }">
          <el-form-item :prop="'rows.' + row.id + '.name'" :rules="rules.name">
            <el-input v-model="row.name"></el-input>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="图片" prop="images">
        <template #default="{ row }">
          <el-form-item :prop="'rows.' + row.id + '.images'" :rules="rules.images">
            <el-upload
              v-model:file-list="row.images"
              action="#"
              list-type="picture-card"
              :limit="3"
              :on-exceed="handleExceed"
            >
              <el-icon><Plus /></el-icon>
            </el-upload>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="视频" prop="videos">
        <template #default="{ row }">
          <el-form-item :prop="'rows.' + row.id + '.videos'" :rules="rules.videos">
            <el-upload
              v-model:file-list="row.videos"
              action="#"
              :limit="2"
              :on-exceed="handleExceed"
            >
              <el-button type="primary">上传视频</el-button>
            </el-upload>
          </el-form-item>
        </template>
      </el-table-column>
      <el-table-column label="项目和分类和数目" prop="items">
        <template #default="{ row }">
          <el-form-item
            v-for="(item, index) in row.items"
            :key="index"
            :prop="'rows.' + row.id + '.items.' + index"
            :rules="rules.items"
          >
            <el-select v-model="item.project" placeholder="项目">
              <el-option v-for="option in projectOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>
            <el-select v-model="item.category" placeholder="分类">
              <el-option v-for="option in categoryOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>
            <el-select v-model="item.number" placeholder="数目">
              <el-option v-for="option in numberOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
            </el-select>
            <el-button @click="removeItem(row, index)" v-if="row.items.length > 1">-</el-button>
          </el-form-item>
          <el-button @click="addItem(row)" v-if="row.items.length < 8">+</el-button>
        </template>
      </el-table-column>
      <el-table-column label="备注" prop="remark">
        <template #default="{ row }">
          <el-form-item :prop="'rows.' + row.id + '.remark'">
            <el-input v-model="row.remark" type="textarea"></el-input>
          </el-form-item>
        </template>
      </el-table-column>
    </el-table>
    <el-button @click="addRow" :disabled="formData.rows.length >= 6">新增行</el-button>
    <el-button @click="removeRow" :disabled="formData.rows.length <= 1">删除行</el-button>
    <el-button type="primary" @click="submitForm">提交</el-button>
  </el-form>
</template>

<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'

const formRef = ref()
const formData = reactive({
  rows: [{
    id: 0,
    name: '',
    images: [],
    videos: [],
    items: [{ project: '', category: '', number: '' }],
    remark: ''
  }]
})

const rules = {
  name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  images: [{ type: 'array', required: true, min: 1, message: '请上传至少一张图片', trigger: 'change' }],
  videos: [{ type: 'array', required: true, min: 1, message: '请上传至少一个视频', trigger: 'change' }],
  items: [{ required: true, message: '请选择项目、分类和数目', trigger: 'change' }]
}

const projectOptions = [
  { value: 'project1', label: '项目1' },
  { value: 'project2', label: '项目2' }
]

const categoryOptions = [
  { value: 'category1', label: '分类1' },
  { value: 'category2', label: '分类2' }
]

const numberOptions = [
  { value: '1', label: '1' },
  { value: '2', label: '2' },
  { value: '3', label: '3' }
]

const handleExceed = () => {
  ElMessage.warning('超出上传限制')
}

const addItem = (row) => {
  if (row.items.length < 8) {
    row.items.push({ project: '', category: '', number: '' })
  }
}

const removeItem = (row, index) => {
  if (row.items.length > 1) {
    row.items.splice(index, 1)
  }
}

const addRow = () => {
  if (formData.rows.length < 6) {
    formData.rows.push({
      id: formData.rows.length,
      name: '',
      images: [],
      videos: [],
      items: [{ project: '', category: '', number: '' }],
      remark: ''
    })
  }
}

const removeRow = () => {
  if (formData.rows.length > 1) {
    formData.rows.pop()
  }
}

const submitForm = async () => {
  if (!formRef.value) return
  
  try {
    await formRef.value.validate()
    // 调用后端新增接口
    console.log('表单数据:', formData.rows)
    // 这里替换为您的实际API调用
    // await api.addNewData(formData.rows)
    ElMessage.success('提交成功')
  } catch (error) {
    console.error('表单验证失败:', error)
    ElMessage.error('表单验证失败,请检查输入')
  }
}
</script>

这个示例实现了以下功能:

  1. 使用el-formel-table创建一个可编辑的表格表单。
  2. 表格最多可以有6行,每行包含序号、名称、图片、视频、项目和分类和数目、备注列。
  3. 图片上传最多3张,最少1张。
  4. 视频上传最多2个,最少1个。
  5. 项目、分类和数目使用下拉框,可以动态增减,最多8个,最少1个。
  6. 实现了表单验证。
  7. 提供了新增和删除行的功能。
  8. 在提交表单时,会先进行验证,然后再调用后端API。

关注微信公众号温暖前端,不定期分享前端知识点和前端资料↓↓↓

你可以尝试以下步骤来封装一个Vue 3和TypeScript下使用Element Plus的表单提交组件: 1. 安装必要的依赖: - Vue 3:`npm install vue@next` - TypeScript:`npm install -D typescript` - Element Plus:`npm install element-plus` 2. 创建一个新的Vue组件,并为其选择一个合适的名称,例如`FormSubmit.vue`。 3. 在`FormSubmit.vue`文件中,导入必要的模块和样式: ```vue <template> <!-- 表单内容 --> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { ElButton, ElForm, ElFormItem } from 'element-plus'; export default defineComponent({ components: { ElButton, ElForm, ElFormItem, }, }); </script> <style scoped> /* Element Plus 样式 */ @import 'element-plus/packages/theme-chalk/src/index.scss'; /* 自定义样式 */ /* ... */ </style> ``` 4. 在模板中编写表单内容,并使用Element Plus的组件来构建表单: ```vue <template> <el-form ref="form" :model="formData" label-width="120px"> <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name"></el-input> </el-form-item> <!-- 更多表单项 --> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> <script lang="ts"> // ... export default defineComponent({ // ... data() { return { formData: { name: '', // 更多表单字段 } }; }, methods: { submitForm() { // 表单提交逻辑 if (this.$refs.form.validate()) { // 表单验证通过,执行提交操作 // ... } } } }); </script> ``` 这样,你就可以使用封装好的表单提交组件来方便地处理表单提交了。你可以根据实际需求添加更多的表单项,并在`submitForm`方法中实现你的提交逻辑。希望这可以帮到你!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温暖前端

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值