溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

使用vue怎么構(gòu)建一個動態(tài)表單

發(fā)布時間:2021-04-12 17:04:37 來源:億速云 閱讀:761 作者:Leah 欄目:web開發(fā)

本篇文章給大家分享的是有關(guān)使用vue怎么構(gòu)建一個動態(tài)表單,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

概述

后臺管理系統(tǒng)里面有非常多的表單需求,我們希望能夠通過寫一個json格式的數(shù)據(jù),通過vue的循環(huán)動態(tài)地去渲染動態(tài)表單。并且能夠在外部得到渲染出來的表單的數(shù)據(jù),可以對表單進行重置操作。我結(jié)合element ui的控件的下拉框,輸入框,時間選擇控件和vue-treeselect,做了一個動態(tài)表單。

使用vue怎么構(gòu)建一個動態(tài)表單

v-model的理解

先簡單講一下vue-model是怎么玩的。其實vue-model相當于給表單元素傳遞一個value,外部監(jiān)聽input事件。所以我們自己封裝表單組件的時候也是可以傳遞一個value值,監(jiān)聽input事件獲取輸入的值。

<input type="text" v-model="something">
<!--等價于-->
<input type="text"
    v-bind:value="something"
    v-on:input="something = $event.target.value">

封裝表單組件

組件最重要的開發(fā)思想就是設(shè)計好輸入輸出。這里就以下拉框組件為例吧。使用的是element ui的下拉框,進行一個簡單封裝。
輸入:name:每個表單的數(shù)據(jù)標識,如區(qū)域編碼輸入框,父元素應(yīng)該傳遞areaCode過來。

value: 表單選擇/輸入的值,從父元素獲取后賦值給currentValue,通過監(jiān)聽父元素的值實現(xiàn)同步變
化。

options:下拉框要渲染的選項值,一般是個對象數(shù)組。

輸出:onInputEvent,emit一個input事件,讓父元素能夠感知組件的數(shù)據(jù)變化。

也就是可以在組件使用的地方監(jiān)聽input事件

<template>
 <el-form-item :label="label">
  <el-select v-model="currentValue" @input="onInputEvent">
   <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value">
   </el-option>
  </el-select>
 </el-form-item>
</template>

<script>
 import formMixins from '../../../mixins/form-model'
 export default {
  name: "SelectList",
  props: ['name', 'label', 'value','options'],
  mixins: [formMixins],
  data() {
   return {
    currentValue: this.value
   }
  },
  methods: {
   onInputEvent(value) {
    this.$emit('input', this.name, value);
   }
  },
  watch: {
   value(val) {
    this.currentValue= val;
   }
  }
 }
</script>

一點封裝

由于每個表單組件都是監(jiān)聽父元素的value值變化,數(shù)據(jù)變化時都是觸發(fā)onInputEvent并執(zhí)行this.$emit('input'),所以我們可以把這部分內(nèi)容抽取出來放在mixins里面。

form-model.js

export default {
 props: ['name', 'value'],

 data () {
  return {
   currentValue: this.value
  };
 },
 methods: {
  onInputEvent(value) {
   this.$emit('input', this.name, value);
  },
  reset() {
   this.currentValue = "";
  }
 },
 watch: {
  value (val) {
   this.currentValue = val;
  }
 }
};

然后我們的下拉框組件就可以少寫一些共用的代碼,直接用 mixins: [formMixins]

<template>
 <el-form-item :label="label">
  <el-select v-model="currentValue" @input="onInputEvent">
   <el-option
    v-for="item in options"
    :key="item.value"
    :label="item.label"
    :value="item.value">
   </el-option>
  </el-select>
 </el-form-item>
</template>

<script>
 import formMixins from '../../../mixins/form-model'
 export default {
  name: "SelectList",
  props: ['name', 'label', 'value', 'options'],
  mixins: [formMixins],
  data() {
   return {
    currentValue: this.value
   }
  }
 }
</script>

動態(tài)生成表單

這里主要是根據(jù)配置的數(shù)據(jù),循環(huán)生成表單組件。默認提供提交和重置按鈕,如果不需要可以通過slot傳遞其他操作按鈕。這里的要點主要有:

監(jiān)聽表單組件的數(shù)據(jù)變化:

每個表單組件都有一個name標識它的業(yè)務(wù)含義,綁定的數(shù)據(jù)也是formData[field.name],@input事件傳遞updateForm,在updateForm里面更新this.formData[name],保證了this.formData里面的數(shù)據(jù)是和表單組件選擇/填寫的內(nèi)容一致。

重置時改變表單組件的數(shù)據(jù):

因為組件內(nèi)部會監(jiān)聽父元素的value,所以這里只要清空this.formData的值,組件內(nèi)部的數(shù)據(jù)也會跟著清空。

 <template>
 <div>
  <el-form :inline="true" ref="form" :model="formData" class="demo-form-inline">
   <el-col :span="field.cols" v-for="(field, index) in config.fieldsConfig" v-bind:key="index">
    <component :key="index"
          :is="field.fieldType"
          :label="field.label"
          :value="formData[field.name]"
          :multiple="field.multiple"
          @input="updateForm"
          v-bind="field"
          :options="field.options"
          :ref="field.name"
    >
    </component>
   </el-col>
   <slot name="buttons">
    <el-button type="primary" @click="submit" size="small">{{onSubmitText}}</el-button>
    <el-button type="default" @click="reset" size="small">{{onResetText}}</el-button>
   </slot>
  </el-form>
 </div>
</template>
<script>
 import SelectList from './basicComponent/SelectList'
 import TextInput from './basicComponent/TextInput'
 import TimeSelector from './basicComponent/TimeSelector'
 import SelectTree from './basicComponent/SelectTree'
 import StaffSelectPopedit from './businessComponent/StaffSelectPopedit'
 export default {
  name: "FormGenerator",
  components: { SelectList, TextInput, TimeSelector, SelectTree, StaffSelectPopedit},
  props: ["config", "value"],
  data() {
   return {
    formData: this.value,
    onSubmitText: this.config.buttons.onSubmitText || '提交',
    onResetText: this.config.buttons.onResetText || '重置'
   }
  },
  methods: {
   updateForm(fieldName, value) {
    this.formData[fieldName] = value;
   },
   submit() {
    this.$emit("submit");
   },
   reset() {
    for(var name in this.formData) {
     if(typeof this.formData === "String") {
      this.formData[name] = "";
     } else {
      this.formData[name] = null;
     }
    }
   }
  }
 }
</script>

業(yè)務(wù)使用的地方

像下拉框的選擇數(shù)據(jù),這些應(yīng)該是后臺渲染的,所以我們暫時用setTimeout模擬一下。感覺這里this.config.fieldsConfig[4].options寫的不太優(yōu)雅,依賴于配置數(shù)據(jù)的順序肯定不是啥好事情。求大神指點。

<template>
 <div>
  <form-generator :config="config"
           @submit="getFormData"
           v-model="formData"
  >
  </form-generator>
 </div>
</template>
<script>
 import FormGenerator from '../components/form/FormGenerator'
 export default {
  name: "FormGeneratorDemo",
  components: { FormGenerator },
  created () {
   this.queryOrderType();
   this.queryAreaTree();
  },
  data() {
   return {
    formData: {
     orderCode: "",
     orderType: "",
     beginTime: "",
     endTime: "",
     area: [],
     staff:""
    },
    config: {
     fieldsConfig: [
      {
       name: 'orderCode',
       label: '定單編碼',
       fieldType: 'TextInput',
       cols: 8
      },
      {
       name: 'orderType',
       label: '定單類型',
       fieldType: 'SelectList',
       options: [],
       cols: 8
      },
      {
       name: 'beginTime',
       label: '開始時間',
       fieldType: 'TimeSelector',
       cols: 8
      },
      {
       name: 'endTime',
       label: '結(jié)束時間',
       fieldType: 'TimeSelector',
       cols: 8
      },
      {
       name: 'area',
       label: '區(qū)域',
       fieldType: 'selectTree',
       options: [],
       multiple: true,
       cols: 8
      },
      {
       name: 'staff',
       label: '人員選擇',
       fieldType: 'StaffSelectPopedit',
       cols: 8
      }
     ],
     buttons: {
      onSubmitText: '提交',
      onResetText: '重置'
     }
    }
   }
  },
  methods: {
   getFormData() {
    console.log(this.formData);
   },
   queryOrderType() {
    setTimeout(() => {
     this.config.fieldsConfig[1].options = [
      { label: 'select1', value: 'key1'},
      { label: 'select2', value: 'key2'},
      { label: 'select3', value: 'key3'}
     ];
     }, 100)
   },
   queryAreaTree() {
    this.config.fieldsConfig[4].options = [
     {
      id: 'a',
      label: 'a',
      children: [{
       id: 'aa',
       label: 'AA',
      }, {
       id: 'ab',
       label: 'AB',
      }],
     }, {
      id: 'b',
      label: 'B',
     }, {
      id: 'c',
      label: 'C',
     }
    ]
   }
  }
 }
</script>

以上就是使用vue怎么構(gòu)建一個動態(tài)表單,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI