欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue封裝form表單組件拒絕重復(fù)寫form表單

 更新時間:2022年07月29日 12:10:22   作者:前端貳貨道士  
這篇文章主要為大家介紹了vue封裝form表單組件拒絕重復(fù)寫form表單的實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

在日常工作中,當(dāng)需要處理的form表單很多時,我們沒有必要一遍又一遍地重復(fù)寫form表單,直接封裝一個組件去處理就好。其實(shí)很早之前就有涉獵通過使用類似配置json方法寫form表單的文章,雖然當(dāng)時也沒怎么認(rèn)真看...我們前端組也是使用這種思想配置的。

然而,這個思想和方法很早就有出現(xiàn)過,并不怎么新穎,還望不喜勿噴...在此我封裝了一個最最最基礎(chǔ)的form表單,離我們前端組封裝的組件差距還很大,有興趣朋友們的可以繼續(xù)往下完善。

核心思想:

  • 通過配置js文件的變量,使用vueis屬性動態(tài)切換組件,默認(rèn)顯示的組件為el-input
  • 通過element的分欄和柵格屬性,對form表單進(jìn)行響應(yīng)式布局
  • baseForm在組件初始化時,需要動態(tài)添加校驗(yàn)規(guī)則請求接口以及初始化form的部分值
  • 正統(tǒng)思想是對element組件的各個組件進(jìn)行二次封裝,然后通過is屬性切換二次封裝后的組件,在此不做過多描述,有興趣的朋友可以自行研究
  • 更好的思想是將頁面請求、搜索項(xiàng)、表格、分頁封裝到一起,形成一個整體,這也是我們前端小組目前的處理思路

實(shí)現(xiàn)重點(diǎn):

  • 任何標(biāo)簽或者組件都可以通過vue的is屬性來動態(tài)切換組件。本組件中使用div,將它的寬度設(shè)置為100%,使得element組件能夠完全撐開。(使用vue內(nèi)置組件component會與el-radio-group相沖突,因?yàn)樗讓泳褪怯?code>component實(shí)現(xiàn)的)
  • 表單上添加validate-on-rule-change="false"屬性,防止在表單初始化時就校驗(yàn)表單
  • 當(dāng)為對象添加不存在的字段屬性時,需要使用$set實(shí)現(xiàn)數(shù)據(jù)的響應(yīng)式
  • 如果form表單中只有一個輸入框,在輸入框中按下回車會提交表單,刷新頁面。為了阻止這一默認(rèn)行為,需要在el-form標(biāo)簽上添加@submit.native.prevent
  • 使用lodash中的get方法獲取對象的屬性值,如果屬性值不存在,可以給一個默認(rèn)值
  • baseForm子組件中可以傳一個form對象給父組件,那么添加或者編輯form對象,就都可以在父組件中進(jìn)行。

表單雙向綁定的方式有兩種: 

1.使用v-model進(jìn)行雙向綁定

<div
  v-else
  clearable
  style="width: 100%"
  type="daterange"
  range-separator="至"
  start-placeholder="開始日期"
  end-placeholder="結(jié)束日期"
  v-model="form[column.prop]"
  :label-width="get(column, 'size', column || defaultFormSize)"
  :disabled="get(column, 'disabled', false)"
  :is="get(column, 'type', 'el-input')"
>

2.使用v-model的語法糖

(`:value以及@input`)進(jìn)行雙向綁定

<div
  v-else
  clearable
  style="width: 100%"
  type="daterange"
  range-separator="至"
  start-placeholder="開始日期"
  end-placeholder="結(jié)束日期"
  :value="form[column.prop]"
  :label-width="get(column, 'size', column || defaultFormSize)"
  :disabled="get(column, 'disabled', false)"
  :is="get(column, 'type', 'el-input')"
  @input="input($event,column.prop)"
>
methods: {
    input(e,prop) {
      this.$set(this.form, prop, e)
    }
}

配置項(xiàng)

(本組件寫得比較基礎(chǔ),目前僅支持element的五個常用組件):

整體字段:

formSize (表單中各element組件的整體大小)

column數(shù)組中每一個對象對應(yīng)的字段(非請求接口):

  • label (表單label的名稱)
  • span (這個表單項(xiàng)占據(jù)的份數(shù),一行為24,默認(rèn)為12)
  • labelWidth (這個表單項(xiàng)的label寬度,默認(rèn)為90px)
  • labelHeight (這個表單項(xiàng)占據(jù)的高度,默認(rèn)為50px)
  • slotName (插槽名)
  • prop (這個表單項(xiàng)綁定的屬性名稱)
  • size (這個表單項(xiàng)組件的大小,默認(rèn)為small)
  • disabled (是否禁用這個表單項(xiàng))
  • type (使用的element組件,默認(rèn)為el-input)
  • dic (非接口請求的靜態(tài)表單數(shù)據(jù),使用{label以及value字段}表示的數(shù)組形式)

column數(shù)組中每一個對象對應(yīng)的字段(請求接口):

  • url (接口的api地址)
  • requestParams (非必填項(xiàng),需要額外傳入的傳參)
  • requestLabel (接口返回對應(yīng)的id)
  • requestValue (接口返回對應(yīng)的value)

效果瀏覽

源碼放送

1. baseForm組件

<template>
  <el-form
    ref="form"
    :model="form"
    :rules="formRules"
    :size="get(option, 'formSize', defaultFormSize)"
    :validate-on-rule-change="false"
    @submit.native.prevent
  >
    <el-row :gutter="20" :span="24">
      <el-col 
        v-for="column in formColumn" 
        :key="column.label" 
        :md="column.span || 12" 
        :sm="12" 
        :xs="24"
      >
        <el-form-item
          :label="`${column.label}:`"
          :prop="column.prop"
          :label-width="get(column, 'labelWidth', column.labelWidth || defaultLabelWidth)"
          :style="{
            height: get(column, 'labelHeight', column.labelHeight || defaultLabelHeight)
          }"
        >
          <slot
            v-if="column.slotName"
            :name="column.slotName"
            :form="form"
            :prop="column.prop"
            :value="form[column.prop]"
          ></slot>
          <div
            v-else
            clearable
            style="width: 100%"
            type="daterange"
            range-separator="-"
            start-placeholder="開始日期"
            end-placeholder="結(jié)束日期"
            v-model="form[column.prop]"
            :placeholder="getPlaceholder(column.type, column.label)"
            :label-width="get(column, 'size', column || defaultFormSize)"
            :disabled="get(column, 'disabled', false)"
            :is="get(column, 'type', 'el-input')"
          >
            <template v-if="column.type == 'el-select'">
              <el-option 
                v-for="item in column.dic" 
                :key="item.value" 
                :label="item.label" 
                :value="item.value"
              >
              </el-option>
            </template>
            <template v-if="column.type == 'el-radio-group'">
              <el-radio 
                v-for="item in column.dic" 
                :key="item.value" 
                :label="item.label"
              >
                {{ item.value }}
              </el-radio>
            </template>
            <template v-if="column.type == 'el-checkbox-group'">
              <el-checkbox 
                v-for="item in column.dic" 
                :key="item.label" 
                :label="item.value"
              >
                {{ item.label }}
              </el-checkbox>
            </template>
          </div>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script>
import get from 'lodash/get'
import request from '@/service/request'
export default {
  props: {
    option: {
      type: Object,
      default: () => {}
    },
    form: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      formRules: {},
      defaultFormSize: 'small',
      defaultLabelWidth: '90px',
      defaultLabelHeight: '50px'
    }
  },
  computed: {
    formColumn() {
      return this.option.column
    }
  },
  created() {
    this.initRules()
    this.initRequest()
    this.initValue()
  },
  methods: {
    get,
    getPlaceholder(type, label) {
      return type == 'el-select' ? `請選擇${label}` : `請輸入${label}`
    },
    initRequest() {
      if (!Array.isArray(this.formColumn)) return
      // 根據(jù)實(shí)際請求接口地址的前綴來判斷
      const urls = this.formColumn?.filter((item) => item.url && item.url.indexOf('/emes') == 0) || []
      urls.forEach(async (item) => {
        const data = { page: { pageIndex: 1, pageSize: 0 }, ...item.requestParams }
        const { detail } = await request({
          url: item.url,
          method: 'post',
          data
        }) || []
        const finalResult = detail.map((result) => ({
          label: result[item.requestLabel],
          value: result[item.requestValue]
        }))
        this.$set(item, 'dic', finalResult)
      })
    },
    initRules() {
      if (!Array.isArray(this.formColumn)) return
      this.formColumn?.forEach((item) => {
        if (item.rules) {
          item.rules.map((rule, index) => {
            if (rule.required) {
              item.rules.splice(index, 1, {
                message: ['el-radio-group', 'el-checkbox-group'].includes(item.type) ? `${item.label}必選` : `${item.label}必填`,
                ...rule
              })
            }
          })
          this.$set(this.formRules, item.prop, item.rules)
        }
      })
    },
    initValue() {
      const selectList = this.formColumn.filter((item) => ['el-radio-group', 'el-checkbox-group'].includes(item.type))
      selectList.forEach((item) => {
        this.$set(this.form, item.prop, item.type == 'el-radio-group' ? item.dic[0].label : [item.dic[0].value])
      })
    }
  }
}
</script>

2. 父組件

<template>
  <div class="app-container">
    <myForm :option="option" :form="form">
      <template #usageSlot="{form, prop}">
        <el-input 
          size="small" 
          placeholder="請輸入插槽使用" 
          v-model="form[prop]" 
          clearable
        >
        </el-input>
      </template>
    </myForm>
  </div>
</template>
<script>
import { option } from './const.js'
export default {
  data() {
    return {
      option,
      form: {}
    }
  }
}
</script>

3. 配置項(xiàng)

export const option = {
  column: [
    {
      label: '姓名',
      prop: 'name',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '職業(yè)',
      prop: 'job',
      type: 'el-select',
      span: 8,
      dic: [
        {
          label: '教師',
          value: 0
        },
        {
          label: '程序猿',
          value: 1
        },
        {
          label: '作家',
          value: 2
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '性別',
      prop: 'sex',
      span: 8,
      type: 'el-radio-group',
      dic: [
        {
          label: 0,
          value: '男'
        },
        {
          label: 1,
          value: '女'
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '城市',
      prop: 'city',
      type: 'el-checkbox-group',
      span: 8,
      dic: [
        {
          label: '仙桃',
          value: 0
        },
        {
          label: '泉州',
          value: 1
        },
        {
          label: '武漢',
          value: 2
        }
      ],
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '出生日期',
      prop: 'data',
      type: 'el-date-picker',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '測試',
      prop: 'test',
      type: 'el-select',
      span: 8,
      url:'/emes/factoryOrderService/warehouse/list',
      requestLabel: 'warehouseName',
      requestValue: 'id',
      rules: [
        {
          required: true
        }
      ]
    },
    {
      label: '插槽使用',
      prop: 'usage',
      slotName: 'usageSlot',
      span: 8,
      rules: [
        {
          required: true
        }
      ]
    }
  ]
}

4. 添加或編輯

  • 添加: 如果是添加狀態(tài),直接在父組件中引入就好。在點(diǎn)擊確定按鈕時,拿到子組件的ref并進(jìn)行表單校驗(yàn)。校驗(yàn)通過后,使用后端定義好的接口進(jìn)行傳參;
  • 編輯: 如果是編輯狀態(tài),則需要在父組件頁面初始化時,將后端返回的數(shù)據(jù)使用$set進(jìn)行初始賦值,其余操作同添加狀態(tài)。

以上就是vue封裝form表單組件拒絕重復(fù)寫form表單的詳細(xì)內(nèi)容,更多關(guān)于vue封裝form表單組件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue3 異步組件 suspense使用詳解

    Vue3 異步組件 suspense使用詳解

    vue在解析我們的組件時, 是通過打包成一個 js 文件,當(dāng)我們的一個組件 引入過多子組件是,頁面的首屏加載時間 由最后一個組件決定 優(yōu)化的一種方式就是采用異步組件,這篇文章主要介紹了Vue3 異步組件 suspense,需要的朋友可以參考下
    2022-12-12
  • VUE2.0中Jsonp的使用方法

    VUE2.0中Jsonp的使用方法

    使用JSONP主要是目的通過動態(tài)創(chuàng)建Script,動態(tài)拼接url,進(jìn)而抓取數(shù)據(jù),實(shí)現(xiàn)跨域。這篇文章主要介紹了VUE2.0中Jsonp的使用方法(前端),需要的朋友可以參考下
    2018-05-05
  • 詳解vue v-model

    詳解vue v-model

    這篇文章主要介紹了vue v-model的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下
    2020-08-08
  • vue 全局環(huán)境切換問題

    vue 全局環(huán)境切換問題

    小編在開發(fā)使經(jīng)常會碰到全局切換問題,今天小編給大家?guī)硪黄坛探o大家介紹vue 全局環(huán)境切換問題,感興趣的朋友一起看看吧
    2019-10-10
  • vue中table實(shí)現(xiàn)真正的跨越全選

    vue中table實(shí)現(xiàn)真正的跨越全選

    本文主要介紹了vue中table實(shí)現(xiàn)真正的跨越全選,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 解決Vue 刷新頁面導(dǎo)航顯示高亮位置不對問題

    解決Vue 刷新頁面導(dǎo)航顯示高亮位置不對問題

    這篇文章主要介紹了解決Vue 刷新頁面導(dǎo)航顯示高亮位置不對問題,本文圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • 詳解Vue.js 作用域、slot用法(單個slot、具名slot)

    詳解Vue.js 作用域、slot用法(單個slot、具名slot)

    這篇文章主要介紹了Vue.js 作用域、slot用法(單個slot、具名slot),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • 使用vuepress搭建靜態(tài)博客的示例代碼

    使用vuepress搭建靜態(tài)博客的示例代碼

    這篇文章主要介紹了使用vuepress搭建靜態(tài)博客的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • vue項(xiàng)目實(shí)現(xiàn)多語言切換的思路

    vue項(xiàng)目實(shí)現(xiàn)多語言切換的思路

    這篇文章主要介紹了vue項(xiàng)目實(shí)現(xiàn)多語言切換的思路,幫助大家完成多語言翻譯,感興趣的朋友可以了解下
    2020-09-09
  • 基于Vue3和element-plus實(shí)現(xiàn)登錄功能(最終完整版)

    基于Vue3和element-plus實(shí)現(xiàn)登錄功能(最終完整版)

    這篇文章主要介紹了基于Vue3和element-plus實(shí)現(xiàn)一個完整的登錄功能,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03

最新評論