还在头疼后台管理页面?Vue3+ElementPlus封装的页面级组件让你5分钟一个页面

Vue3实现常规后台查询页面。

上一篇我用vue2实现了对后台管理常规查询页面的封装。今天我们来用vue3来实现一下。Vue2的文章大家可以去看看

还在写重复的增删改查的重复代码?还在重复写Ajax请求?Vue2+Element-ui实现常规后台查询展示页面来了

需求我们就不分析那么多了跟vue2的一样,我们这次直接上代码。看看vue3的实现逻辑是怎么样的。

源码地址: https://github.com/fengligao/vue-template-page-3 也可以扫描下方二维码关注我的公众号或微信获取。

首先我们来看看页面实现的效果:

image.png

可以看到页面中集成了查询条件操作,表格数据展示,表格数据等操作,分页切换等基础功能。

我们可以根据功能分为4个基础操作区域:

image.png

我们先来看看条件查询区域该如何实现Vue3和Vue2写法不同 可以使用组合式api

不墨迹具体实现思路和Vue2的思路一样 还是根据form的数组来动态渲染条件类型。来看代码:

import { defineComponent, onBeforeMount, ref } from 'vue'
import { ElForm, ElFormItem, ElButton } from 'element-plus'

import { formProps } from './props'

import type { IFormItem } from './interface'

import MiJiInput from "@/components/miji-input.vue"
import MiJiSelect from '@/components/miji-select.vue'
import MiJiDateRange from '@/components/miji-daterange.vue'
import MiJiDate from '@/components/miji-date.vue'
import MiJiRadio from '@/components/miji-radio.vue'
import MiJiCheckbox from '@/components/miji-checkbox.vue'

import MiJiFormItem from './formItem.vue'

export default defineComponent({
  props: formProps,
  emits: ['search'],
  setup(props, { emit }) {
    const { form, isAsync } = props
    const forms = ref<Array<IFormItem>>([])
    const formData = ref({})
    // 表单 异步数据处理
    const optionsMap = (item: IFormItem) => {
      return new Promise((resolve) => {
        item.getOptions().then((res: any) => {
          const options = res.map(v => {
            return {
              label: v[item.optionsLabel || 'label'],
              value: v[item.optionsValue || 'value']
            }
          });
          resolve(options)
        })
      })
    }
    // 初始化表单项
    const initForm = async (_form) => {
      for (let i = 0; i < _form.length; i++) {
        const newItem: IFormItem = Object.assign(_form[i])
        newItem.weight = newItem.weight || 1; // 保留了用户可以自定义权重排序
        switch (newItem.type) {
          case 'daterange':
            newItem.value = Array.isArray(newItem.defaultValue) ? newItem.defaultValue : [];
            newItem.weight = 2;
            break;
          case 'date':
            newItem.value = newItem.defaultValue || '';
            break;
          case 'text':
            newItem.value = newItem.defaultValue || '';
            break;
          case 'select':
          case 'checkbox':
            newItem.value = newItem.defaultValue || (newItem.type === 'select' ? newItem.multiple ? [] : '' : newItem.multiple ? [] : []); // 多选 默认:空数组
            newItem.options = newItem.options || [];
            if (typeof newItem.getOptions === 'function') {
              if (isAsync || newItem.type === 'checkbox') {
                newItem.options = await optionsMap(newItem)
              } else {
                optionsMap(newItem).then(res => {
                  newItem.options = res
                })
              }
            }
            break;
          case 'radio-button':
          case 'radio':
            newItem.value = newItem.defaultValue || '';
            newItem.options = newItem.options || [];
            if (typeof newItem.getOptions === 'function') {
              newItem.options = await optionsMap(newItem)
            }
            break;
          case 'selectInput':
            // 选择 默认第一个
            newItem[newItem.selectKey] = newItem.selectOptions[0] ? newItem.selectOptions[0].value : '';
            newItem[newItem.selectInputKey] = '';
            break;
          default:
            break;
        }
        forms.value.push(newItem);
      }
    }

    const sortForm = (formlist) => {
      return new Promise((resolve) => {
        // 权重大的前置
        formlist.sort((prev, next) => prev.weight - next.weight);
        // radio checkbox 选项后置
        formlist.sort((prev, next) => {
          if (next.type === 'checkbox' || next.type === 'radio' || next.type === 'radio-button') {
            return -1
          }
        });
        formlist.sort((prev, next) => {
          if (next.label && prev.label) {
            return 0;
          }
          if (next.label && (!prev.label)) {
            return 1;
          }
          if ((!next.label) && prev.label) {
            return -1;
          }
        });

        resolve(formlist)
      })
    }

    // 生成表单的默认数据
    const initFormData = () => {
      const data = {}
      forms.value.forEach(item => {
        switch (item.type) {
          case 'daterange':
            data[item.key] = Array.isArray(item.defaultValue) ? item.defaultValue : [];
            break;
          case 'select':
          case 'checkbox':
            data[item.key] = item.defaultValue || (item.type === 'select' ? item.multiple ? [] : '' : []); // 多选 默认:空数组
            break;
          default:
            data[item.key] = item.defaultValue || '';
            break;
        }
      });
      return data
    }

    onBeforeMount(async () => {
      // 条件排序
      const newForm = await sortForm(form)
      await initForm(newForm)
      formData.value = initFormData()
      console.log('默认值:', formData.value);
      const param = await getParamByForm(formData.value);
      emit('search', param)
    })

    const onChangeFormValue = (value, index) => {
      // forms.value[index].value = value
      formData.value[forms.value[index].key] = value;
    }

    const renderInput = (formItem: IFormItem, formIndex: number) => {
      return <MiJiInput
        value={formData.value[formItem.key]}
        placeholder={formItem.placeholder}
        onInput={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 下拉选择框
    const renderSelect = (formItem: IFormItem, formIndex: number) => {
      return <MiJiSelect
        options={formItem.options}
        value={formData.value[formItem.key]}
        placeholder={formItem.placeholder}
        valueFormat={formItem.valueFormat}
        onChange={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 时间范围选择器
    const renderDateRange = (formItem: IFormItem, formIndex: number) => {
      return <MiJiDateRange
        value={formData.value[formItem.key]}
        startPlaceholder={formItem.startPlaceholder}
        valueFormat={formItem.valueFormat}
        endPlaceholder={formItem.endPlaceholder}
        onChange={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 时间选择器
    const renderDate = (formItem: IFormItem, formIndex: number) => {
      return <MiJiDate
        value={formData.value[formItem.key]}
        placeholder={formItem.placeholder}
        valueFormat={formItem.valueFormat}
        onChange={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 单选框组
    const renderRadio = (formItem: IFormItem, formIndex: number) => {
      return <MiJiRadio
        value={formData.value[formItem.key]}
        type={formItem.type}
        options={formItem.options}
        onChange={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 多选框组
    const renderCheckbox = (formItem: IFormItem, formIndex: number) => {
      return <MiJiCheckbox
        value={formData.value[formItem.key]}
        options={formItem.options}
        onChange={(value) => onChangeFormValue(value, formIndex)}
      />
    }
    // 渲染表单
    const renderFormItem = (item: IFormItem, i: number) => {
      let formItem = null
      switch (item.type) {
        case 'text':
          formItem = renderInput(item, i)
          break;
        case 'select':
          formItem = renderSelect(item, i)
          break;
        case 'daterange':
          formItem = renderDateRange(item, i)
          break;
        case 'date':
          formItem = renderDate(item, i)
          break;
        case 'radio-button':
          formItem = renderRadio(item, i)
          break;
        case 'radio':
          formItem = renderRadio(item, i)
          break;
        case 'checkbox':
          formItem = renderCheckbox(item, i)
          break;
        default:
          break;
      }
      return <MiJiFormItem
        label={item.label}
        width={item.width}
        type={item.type}
      >
        {formItem}
      </MiJiFormItem>
    }

    const renderForm = () => {
      const formItem: any = []
      for (let i = 0; i < forms.value.length; i++) {
        const item = forms.value[i];
        formItem.push(renderFormItem(item, i))
      }
      return <ElForm
        class="template-page__form"
        inline={true}
        model={formData}
        label-width={'80px'}
      >
        {formItem}
        <ElFormItem style={{ paddingLeft: 0, borderColor: 'rgba(0,0,0,0)' }}>
          <ElButton class="search-btn" type="primary" onClick={onSubmit}>查 询</ElButton>
          <ElButton style={{ height: '100%' }} onClick={onCancel}>重 置</ElButton>
        </ElFormItem>
      </ElForm>
    }

    const getParamByForm = (data) => {
      const param = {}
      for (const i in data) {
        const item: any = forms.value.find(v => v.key === i)
        switch (item.type) {
          // 时间范围
          case 'daterange':
            if (item.isSelectKey) {
              param[item.key] = data[i]
              param['isArrayKey'] = item.key
            } else {
              param[item.startDateKeyName || 'kaiShiSJ'] = Array.isArray(data[i]) ? data[i][0] : '';
              param[item.endDateKeyName || 'jieShuSJ'] = Array.isArray(data[i]) ? data[i][1] : '';
            }
            break;
          case 'checkbox':
            param[item.key] = (data[i] || []).join();
            break;
          case 'select':
            param[item.key] = Array.isArray(data[i]) ? data[i].join() : data[i];
            break;
          default:
            param[item.key] = data[i];
        }
      }
      return param
    }

    const onSubmit = () => {
      const param = getParamByForm(formData.value);
      emit('search', param)
    }

    const onCancel = async () => {
      formData.value = initFormData()
    }

    return () => renderForm()
  }
})

在表单的组件中我有单独分装了一下input、select、checkbox等组件,包括项目中扩展了新增编辑的通用组件,这里也可以直接使用这些表单组件。

表单区域实现以后我们来看下页面的代码

页面模版中分为 条件查询、表格展示、表格分页、插槽内容。

这里我预留了只保留条件查询,查询数据后不使用常规的表格展示使用的自定义内容的插槽。

import { defineComponent, ref } from 'vue'
import './index.scss'

import { pageProps } from './props'
import MiJiPage from '../miji-page.vue'

import Form from './form'
import Table from './table'
import Pagination from './pagination.vue'

export default defineComponent({
  name: 'miji-template-page',
  props: pageProps,
  setup(props, ctx) {
    console.log(ctx);
    const {
      url,
      form,
      method,
      beforeRequest,
      afterResponse,
      showPagination,
      columns,
      isAsync,
      tableConfig = {}
    } = props
    const dataSource = ref()

    const requestData = ref()
    const urlQuery = ref()

    const pageNo = ref<number>(1)
    const total = ref<number>(0)
    const pageSize = ref<number>(20)

    const initPage = () => {
      return <MiJiPage className="template-page">
        <Form
          form={form}
          isAsync={isAsync}
          onSearch={(param) => onSearch(param)}
        />
        <div class="template-page__content">
          {
            ctx.slots.tableOptions || tableConfig.title
              ? <div className="content-options">
                <div className="content-options__title">{tableConfig.title || ''}</div>
                <div className="content-options__slot">
                  {ctx.slots.tableOptions ? ctx.slots.tableOptions() : ''}
                </div>
              </div>
              : ''
          }
          {
            ctx.slots.defaultContent ? ctx.slots.defaultContent() : <Table
              dataSource={dataSource.value}
              columns={columns}
            >
              {{
                ...ctx.slots
              }}
            </Table>
          }
        </div>
        {
          !ctx.slots.defaultContent && showPagination && total.value > 0 ? <Pagination
            pageNo={pageNo.value}
            pageSize={pageSize.value}
            total={total.value}
            onCurrentChange={(page: number) => handleCurrentChange(page)}
            onPageSizeChange={(size: number) => handlePageSizeChange(size)}
          /> : ''
        }
      </MiJiPage>
    }

    const handleCurrentChange = (page: number) => {
      pageNo.value = page
      getData()
    }

    const handlePageSizeChange = (size: number) => {
      pageSize.value = size
      pageNo.value = 1
      getData()
    }

    const onSearch = (param) => {
      pageNo.value = 1
      requestData.value = param
      if (method === 'get' && param.isArrayKey) {
        urlQuery.value = param.isArrayKey ? '?' + param[param.isArrayKey].map(v => param.isArrayKey + '=' + v).join(',').replace(',', '&') : ''
        delete requestData.value[param.isArrayKey]
        delete requestData.value.isArrayKey
      }
      getData()
    }

    const getData = () => {
      if (showPagination) {
        const page = {
          current: pageNo.value,
          size: pageSize.value
        }
        Object.assign(requestData.value, page);
      }
      if (beforeRequest) {
        requestData.value = beforeRequest(requestData.value);
        if (!requestData.value) return false; // 如果返回false,则取消当前请求
      }
      const data = method === 'get' ? { params: requestData.value } : requestData.value; // 请求入参
      console.log('最终入参:', data);

      setTimeout(() => {
        let data: { records: any } = { records: [] }
        data = afterResponse ? afterResponse(data) : data;
        console.log('处理后的出参:', data);
        dataSource.value = data.records
        pageNo.value = 1
        pageSize.value = 10
        total.value = 100
      }, 2000)
    }

    return () => initPage()
  }
})

在常规页面中我们使用的表格组件正是我上一篇文章的组件这里也不过多介绍了可以看看这篇文章 Vue3 ElementPlus 二次封装常用表格展示组件 或者直接下载本篇文章的 源代码

下面这个弹层是封装的一个通用新增编辑表单的组件

image.png

组件的实现思路和页面查询表单的动态渲染一样的原理,这里呢 我用了一个element-plus的抽屉组件来当作统一弹层,大家有想用dialog得或者切换页面新增编辑的可以在这个基础之上进行拓展。下面来看看代码:

import { defineComponent, ref, reactive, onMounted } from "vue";
import {
  ElDrawer,
  ElFooter,
  ElForm,
  ElFormItem,
  ElButton,
  ElNotification
} from 'element-plus'

import type { FormInstance, FormRules } from 'element-plus'

import './index.scss'

import IProps from './props'
import MiJiRadio from '@/components/miji-radio.vue'
import MiJiInput from "@/components/miji-input.vue"
import MiJiSelect from '@/components/miji-select.vue'
import MiJiDateRange from '@/components/miji-daterange.vue'
import MiJiDate from '@/components/miji-date.vue'
import MiJiCheckbox from '@/components/miji-checkbox.vue'

import {
  initFormValues,
  initFormRules,
  initFormItems,
} from './form'

export default defineComponent({
  name: 'miji-a-u-drawer', // 右侧抽屉新增编辑形式 a: add u: update
  props: IProps,
  emits: {
    close: null
  },
  setup(props, { emit, slots }) {
    const drawer = ref(true)
    // props
    const {
      method,
      url,
      title,
      size,
      showFooter,
      labelWidth,
      formSize,
      forms,
      labelPosition,
      className,
      formValues,
      cancelText,
      enterText
    } = props
    // 插槽
    const { header } = slots

    // 表单ref
    const ruleFormRef = ref<FormInstance>()

    console.log('新增编辑的数据:', forms);
    const formItems = ref<any>([])

    onMounted(async () => {
      formItems.value = await initFormItems(forms)
      console.log(formItems.value);
    })

    const rulesItem = initFormRules(forms) // 初始化表单校验规则
    const ruleFormItem = initFormValues(forms, formValues) // 初始化表单数据

    const rules = reactive<FormRules>(rulesItem)
    const ruleForm = reactive<any>(ruleFormItem)

    console.log('初始化数据:', ruleForm, rules);

    const handleEnter = (formEl) => {
      console.log('enter option', formEl, ruleFormRef);
      if (!formEl) return
      formEl.validate((valid) => {
        if (valid) {
          console.log('submit!', ruleForm)
          ElNotification({
            title: '提示',
            message: '新增编辑成功',
          })
        } else {
          console.log('error submit!')
          return false
        }
      })
    }
    const handleCancel = () => {
      console.log('cancel option');
      emit('close', false)
    }

    const onChangeFormValue = (value, v) => {
      // forms.value[index].value = value
      ruleForm[v.name] = value;
      // 表单值发生变化后 针对当前字段重新验证
      if (!ruleFormRef.value) return false
      ruleFormRef.value.validateField(v.name)
    }

    const renderFormItem = (v) => {
      let item = null
      switch (v.type) {
        case 'input':
          item = <MiJiInput
            value={ruleForm[v.name]}
            placeholder={v.placeholder}
            onInput={(value) => onChangeFormValue(value, v)}
          />
          break;
        case 'select':
          item = <MiJiSelect
            options={v.options}
            value={ruleForm[v.name]}
            placeholder={v.placeholder}
            onChange={(value) => onChangeFormValue(value, v)}
          />
          break;
        case 'checkbox':
          item = <MiJiCheckbox
            value={ruleForm[v.name]}
            options={v.options}
            onChange={(value) => onChangeFormValue(value, v)}
          />
          break;
        case 'radio':
          item = <MiJiRadio
            value={ruleForm[v.name]}
            type={v.radioType}
            options={v.options}
            onChange={(value) => onChangeFormValue(value, v)}
          />
          break;
        case 'daterange':
          item = <MiJiDateRange
            value={ruleForm[v.name]}
            startPlaceholder={v.startPlaceholder}
            valueFormat={v.valueFormat}
            endPlaceholder={v.endPlaceholder}
            onChange={(value) => onChangeFormValue(value, v)}
          />
          break;
        case 'date':
          item = <MiJiDate
            value={ruleForm[v.name]}
            placeholder={v.placeholder}
            valueFormat={v.valueFormat}
            onChange={(value) => onChangeFormValue(value, v)}
          />
          break;
        default:
          break;
      }
      return <ElFormItem
        label={v.label}
        prop={v.name}
      >
        {item}
      </ElFormItem>
    }

    const renderForm = () => {
      const items: any = []
      console.log(formItems);

      formItems.value.forEach((v: any) => {
        items.push(renderFormItem(v))
      })
      return <ElForm
        ref={ruleFormRef}
        model={ruleForm}
        rules={rules}
        labelPosition={labelPosition}
        labelWidth={labelWidth}
        class={className}
        size={formSize}
      >
        {items}
      </ElForm>
    }

    // 关闭弹窗
    const beforeClose = () => [
      emit('close', false)
    ]

    return () => (
      <ElDrawer
        modelValue={drawer.value}
        title={title || '提示'}
        size={size}
        beforeClose={beforeClose}
        v-slots={{
          header: () => header && header(),
          footer: () => showFooter && <ElFooter>
            <div style={{
              height: '100%',
              alignItems: 'flex-end',
              justifyContent: 'flex-end',
              display: 'flex'
            }}>
              <ElButton onClick={handleCancel}>{cancelText}</ElButton>
              <ElButton
                type="primary"
                onClick={() => handleEnter(ruleFormRef.value)}
              >{enterText}</ElButton>
            </div>
          </ElFooter>
        }}
      >
        {renderForm()}
      </ElDrawer>
    )
  },
})

思路一样也是动态根据数组类型来动态渲染表单。

这里注意的是 我用几个方法 单独处理了一下传递进来的表单数组。

把form需要的初始化数据、form的校验规则、form要渲染的内容处理、需要异步加载的数据。

// 初始化表单认值,
export const initFormValues = (forms, values) => {
  const obj = {}
  for (let i = 0; i < forms.length; i++) {
    const e: any = forms[i];
    switch (e.type) {
      case 'select':
        obj[e.name] = values ? values[e.name] : e.value || (e.multiple ? [] : '')
        break;
      case 'checkbox':
        obj[e.name] = values ? values[e.name] : e.value || []
        break;
      default:
        obj[e.name] = values ? values[e.name] : e.value || ''
        break;
    }
  }
  return obj
}
// 初始化表单规则
export const initFormRules = (forms) => {
  const obj = {}
  for (let i = 0; i < forms.length; i++) {
    const e: any = forms[i];
    obj[e.name] = {
      required: e.required,
      message: e.message,
      trigger: e.trigger,
    }
  }
  return obj
}

// 表单 异步数据处理
const optionsMap = (item) => {
  return new Promise((resolve) => {
    item.getOptions().then((res: any) => {
      const options = res.map(v => {
        return {
          label: v[item.optionsLabel || 'label'],
          value: v[item.optionsValue || 'value']
        }
      });
      resolve(options)
    })
  })
}
// 初始化表单渲染内容中的异步数据
export const initFormItems = async (forms) => {
  const arr: Array<any> = []
  for (let i = 0; i < forms.length; i++) {
    const item = Object.assign({}, forms[i])
    if (typeof item.getOptions === 'function') {
      item.options = await optionsMap(item)
    }
    arr.push(item);
  }
  return arr
}
这里我们看看在页面中如何使用:

组件的全局组册就这样在入口文件引入就好了

import MiJiTable from './components/templatePage/table'
import TemplatePage from './components/templatePage/index'
import MiJiAuDrawer from './components/addOrUpdateItem/index'

const app = createApp(App)

app.component(MiJiTable.name, MiJiTable)
app.component(TemplatePage.name, TemplatePage)
app.component(MiJiAuDrawer.name, MiJiAuDrawer)

在页面中我们可以直接使用我们组件的name属性声明的组件名称

<miji-template-page
    method="get"
    url="/api"
    :form="form"
    :columns="columns"
    :beforeRequest="beforeRequest"
    :afterResponse="afterResponse"
    :pageNo="1"
    :pageSize="20"
    :tableConfig="{ title: '表格标题' }"
  >
    <!-- 页面组件自带表格插槽部分 -->
    <template #xingBie="scope">{{ '插槽:' }}</template>
    <!-- 页面组件 表格前插槽部分 -->
    <template #tableOptions>
      <el-button type="primary" @click="add">新增</el-button>
    </template>
    <!-- 自定义内容插槽 -->
    <template #defaultContent>
      // 这里自定义插槽的内容
      <el-tree
        style="max-width: 600px"
        :data="data"
        :props="defaultProps"
        @node-click="handleNodeClick"
      />
    </template>
  </miji-template-page>

页面中可以直接只用内置表格,也可以使用自定义的展示数据的方式:比如树形图结构的

搭配新增编辑的通用组件来实现页面的基本功能

<miji-a-u-drawer
    v-if="drawer"
    @close="handleClose"
    @success="handleSuccess"
    url="/api"
    labelWidth="100px"
    labelPosition="top"
    size="50%"
    :forms="[
      {
        type: 'input',
        label: '名称',
        name: 'mingCheng',
        value: '',
        required: true,
        placeholder: '请输入名称',
        message: '名称是不可或缺的入参',
        trigger: 'blur'
      },
      {
        type: 'select',
        label: '下拉',
        name: 'xiaLa',
        value: '',
        required: true,
        placeholder: '请选择下拉',
        message: '下拉是不可或缺的入参',
        trigger: 'change',
        options: [
          {
            value: 'Option1',
            label: 'Option1'
          }
        ],
        optionsLabel: 'name',
        optionsValue: 'id',
        getOptions: getAddOrUpdateOptions
      },
     // ... 等等其他的所需数据
    ]"
    :formValues="formValues"
  >
    <template #header>
      <h4>自定义头</h4>
    </template>
  </miji-a-u-drawer>

以上是简单的使用方式大家看兴趣的可以直接去下载源码看看完整代码。

所以一个常规后台管理页面的组件大大提高我们的开发效率,虽然不及低代码,但是在一定程度上也解决了我们重复代码重复开发的难题。

有兴趣的朋友可以在这个基础上面,配合后端的同学把创建页面和一些操作逻辑通过配置存起来。然后再搭配我这个组件来使用也是一种低代码的实现方式。

近期我会出一个开源的后台管理的项目模版,大家可以关注我的公众号及时获取最新文章。

欢迎大家私信留言,多多点评

可以扫描下方二维码关注我的公众号或添加我的微信联系、沟通。

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你可以尝试以下步骤来封装一个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、付费专栏及课程。

余额充值