Vue 学习随笔系列四 -- form 表单封装

Vue 学习随笔系列四 – form 表单封装


一、form 表单封装方法(1)

1、组件封装

<template>
  <el-form
    ref="form"
    :model="form"
    :label-width="80"
    :label-colon="true"
    label-position="left"
  >
    <el-row >
      <el-col :span="8">
        <el-form-item label="姓名">
          <el-input v-model="form.name" clearable></el-input>
        </el-form-item>
      </el-col>
      <el-col :span="8">
        <el-form-item label="年龄">
          <el-input v-model="form.age" clearable></el-input>
        </el-form-item>
      </el-col>
      <el-col :span="8">
        <div class="button-box">
          <el-button class="search" type="primary" @click="handleQuery"
            >筛 选</el-button
          >
        </div>
      </el-col>
    </el-row>
  </el-form>
</template>

<script>
export default {
  data () {
    return {
      form: {
        name: '', // 查询条件1 
        age: '' //  查询条件2
      }
    }
  },
  methods: {
    handleQuery () {
      this.$emit('handleQuery', this.form)
    }
  },
  mounted () {
    // this.handleQuery()
  }
}
</script>

<style scoped>
.button-box {
  white-space: nowrap;
}
.search {
  background-color: #0049CA;
  color: #FFFFFF;
}
</style>

2、组件使用

<template>
	<div>
		<SearchPanel class="mb25" @handleQuery="handleQuery"></SearchPanel>
	</div>
</template>

<script>
	import SearchPanel from './SearchPanel.vue'

	export default {
	  components: {  SearchPanel,  },
	  data(){
	  	return{
  		  total: 0, // 总条数
	      pageNum: 1,
	      pageSize: 10,
	      pageSizes: [10, 20, 50, 100],
	      searchParams: {},
	  	}
	  },
	  methods: {
	  	hadleQuery(){
	  		this.searchParams = { ...params, pageNum: this.pageNum, pageSize: this.pageSize }
	  	}
	  }
  }
</script>

二、form 表单封装方法(2)

1、form 表单组件封装

此案例包含 input 输入框, select 选择框 等,根据实际需求使用

<template>
  <div class="form">
      <el-form
          ref="form"
          :model="formData"
          :inline="inline"
          :label-width="labelWidth"
          :label-position="labelPosition"
      >
          <el-form-item
              v-for="item in formConfig"
              :key="item.model"
              :label="item.label"
              :label-width="item.labelWidth"
          >
              <el-input
                  v-if="item.type === 'input'"
                  v-model="formData[item.model]"
                  :type="item.inputType ? item.inputType : 'text'"
                  clearable
              />

              <el-date-picker
                  v-if="item.type === 'daterange'"
                  v-model="formData[item.model]"
                  type="daterange"
                  value-format="yyyy-MM-dd"
                  start-placeholder="开始日期"
                  end-placeholder="结束日期"
                  :style="`
                      width: ${item.width ? item.width : 300}px
                  `"
                  @onChange="setDateRange(formData[item.model], item.model)"
              />

              <el-select
                  v-if="item.type === 'select'"
                  v-model="formData[item.model]"
                  clearable
                  placeholder="请选择"
                  :multiple="item.multiple"
                  :filterable="item.filterable"
                  :max-tag-count="item.max_tag_count"
                  style="width:100%;"
              >
                  <el-option
                      v-for="data in item.list"
                      :key="getSelectKeys(data, 'key')"
                      :value="getSelectKeys(data, 'key')"
                  >
                      {{ getSelectKeys(data, "value") }}
                  </el-option>
              </el-select>

              <slot name="item" />

              <el-button
                v-if="item.type === 'confirm'"
                type="primary"
                :loading="item.isSearching"
                @click="query"
              >
                查询
              </el-button>

              <el-button
                v-if="item.type === 'add'"
                type="primary"
                @click="addItem"
              >
                新增
              </el-button>

              <el-button
                v-if="item.type === 'mod'"
                type="primary"
                @click="modItem"
              >
                修改
              </el-button>

              <el-button
                v-if="item.type === 'delete'"
                type="primary"
                @click="deleteItem"
              >
                删除
              </el-button>

              <el-button
                v-if="item.type === 'upload'"
                type="primary"
                @click="upload"
              >
                上传
              </el-button>

              <el-button
                v-if="item.type === 'download'"
                type="primary"
                @click="download"
              >
                下载
              </el-button>

              <el-button
                v-if="item.type === 'reset'"
                type="primary"
                @click="reset"
              >
                重置
              </el-button>

              <slot name="button" />
          </el-form-item>

          <slot name="form" />
      </el-form>
  </div>
</template>

<script>
export default {
  name: 'CommonForm',
  props: {
      // 表单项是否行内显示
      inline: {
          type: Boolean,
          default: true,
      },
      // 表单项配置
      formConfig: {
          type: Array,
          default: () => []
      },
      // 表单项数据
      form: {
          type: Object,
          default: () => {}
      },
      // 表单标签宽度
      labelWidth: {
          type: String,
          default: '100',
      },
      // 表单标签位置,默认左侧
      labelPosition: {
          type: String,
          default: 'left',
      },
  },
  data() {
      return {
          formData: this.form,
          selectKeys: []
      };
  },
  mounted() {
      // 初始化设置formdata项的开始时间和结束时间
      this.formConfig
          .filter(item => item.type === 'daterange')
          .map(item => {
              this.setDateRange(this.formData[item.model], item.model);
          });
  },
  methods: {
      getSelectKeys(obj, type) {
          const key = Object.keys(obj);
          return type === 'key' ? obj[key[0]] : obj[key[1]];
      },
      // 选取日期后赋给 form 对应属性名
      setDateRange(date, model) {
        console.log("date", date)
          this.formData[`${model}_start`] = date[0];
          this.formData[`${model}_stop`] = date[1];
      },
      // 查询
      query() {
        this.$emit('query');
      },
      // 编辑
      modItem() {
        this.$emit('modItem')
      },
      addItem(){
        this.$emit('addItem')
      },
      // 删除
      deleteItem() {
        this.$emit('deleteItem');
      }, 
      upload() {
        this.$emit('upload')
      },
      download() {
        this.$emit('download')
      },
      // 重置表单
      reset() {
        this.$refs.form.resetFields();
      },
      // 获取表单参数
      getForm() {
        console.log("formData", this.formData)
        return this.formData
      }
  },
};
</script>

2、表单组件引用

<template>
  <div class="index">
    <QueryForm
      ref="queryForm"
      :form="form"
      :form-config="formConfig"
      @query="query"
      @refresh="refresh"
      @addItem="addItem"
      @modItem="modItem"
      @deleteItem="deleteItem"
      @upload="upload"
      @download="download"
    >
    </QueryForm>
  </div>
</template>

<script>
import QueryForm  from "./QueryForm.vue"

export default {
  name: 'HelloWorld',
  components: {
    QueryForm
  },
  props: {
    // msg: String
  },
  data(){
    return{
      isSearching: false, // 是否查询种
      form: {
        id: '',
        status: '',
        time: '',
        pageSize: 10,
        pageNum: 1,
      },
      formConfig: [
        {model:'id', label: "ID", type: 'input', placeholder: "请输入"},
        {
          model: 'status', 
          label: "状态", 
          type: 'select', 
          list:[
            {
              key: "1",
              value: "选项1"
            },
            {
              key: "2",
              value: "选项2"
            }
          ],
          placeholder: "请选择"
        },
        {model: 'time', label: "日期", type: 'daterange', placeholder: "请选择"},
        {
          model: "confirm", // 确认按钮
          text: "查询",
          type: 'confirm',
          label: '',
          isSearching: this.isSearching
        },
        {
          model: "add", // 确认按钮
          text: "新增",
          type: 'add',
          label: '',         
        },
        {
          model: "mod", // 确认按钮
          text: "修改",
          type: 'mod',
          label: '',         
        },
        {
          model: "delete", // 确认按钮
          text: "删除",
          type: 'delete',
          label: '',         
        },
        {
          model: "upload", // 确认按钮
          text: "上传",
          type: 'upload',
          label: '',         
        },
        {
          model: "download", // 确认按钮
          text: "下载",
          type: 'download',
          label: '',         
        },
      ],
    }
  },
  methods: {
    query(){
      const formParams = this.$refs.queryForm.getForm() || {}
      console.log("query", formParams)
    },
    // 查询
    refresh(){
      console.log("refresh")
    },
    // 新增
    addItem(){
      console.log("addItem")
      this.$refs.addForm.handleOpen({
        title: '新增'
      })
    },
    // 修改
    modItem() {
      console.log("modItem")
    },
    // 删除
    deleteItem() {
      console.log("deleteItem")
    },
    // 上传
    upload() {
      console.log("upload")
      this.$refs.uploadBox.handleOpen()
    },
    // 下载
    download() {
      console.log("download")
    },
  }
}
</script>

实现效果:
在这里插入图片描述

三、form 表单封装方法(3)

1、组件封装

<template>
  <el-form
    ref="form"
    :model="formData"
    size="small"
    label-width="100px"
    class="form-box"
  >
    <el-row>
      <el-col 
        v-for=" item in formConfig.itemList"
        :span="8">
        
        <el-form-item        
          :key = "item.model"
          :label="item.label"
        >
          <el-input
            v-if="item.type === 'input'"
            v-model="formData[item.model]"
            :type="item.inputType ? item.inputType : 'text'"
            :placeholder="item.placeholder"
            :disabled="item.disabled"
            clearable
          >
          </el-input>

          <el-select
            v-if="item.type === 'select'"
            v-model="formData[item.model]"
            :type="item.inputType ? item.inputType : 'text'"
            :placeholder="item.placeholder"
            :disabled="item.disabled"
            :multiple="item.multiple"
            :filterable="item.filterable"
            clearable
          >
            <el-option
              v-for="data in item.list"
              :key="getSelectKeys(data, 'key')"
              :label="getSelectKeys(data, 'label')"
              :value="getSelectKeys(data, 'key')"
            >
            {{ getSelectKeys(data, "value") }}
            </el-option>
          </el-select>

          <el-cascader
            v-if="item.type === 'cascader'"
            v-model="formData[item.model]"
            :options="item.formOptions"
            :multiple="item.multiple"
            :filterable="item.filterable"
            :placeholder="item.placeholder"
            @change="handleChange"
          ></el-cascader>

          <el-date-picker
            v-if="item.type === 'daterange'"
            v-model="formData[item.model]"
            :type="daterange"
            format="yyyy-MM-dd"
            @onChange="datechange"
          ></el-date-picker>

        </el-form-item>
      </el-col>  

      <el-col :span="24">
            type="warning"
            @click="emitEvent({eventName: 'addorModItem', params: 'mod'})"
          >
            <i class="el-icon-edit"></i>
            修改 
          </el-button>

          <el-button
            size="small"
            type="danger"
            @click="emitEvent({eventName: 'deleteItem', params: ''})"
          >
            <i class="el-icon-delete"></i>
            删除 
          </el-button>
        </el-form-item>

        <el-form-item>
          <el-button
            v-for="(item, index) in formConfig.operate"
            :key="index"
            size="small"
            :type="item.type"
            :icon="item.icon"
            @click="emitEvent({eventName: item.handleClick, params: ''})"
          >{{ item.name }}</el-button>
        </el-form-item>
      </el-col>

    </el-row>
  </el-form>
</template>

<script>
export default {
name: 'QueryForm',
// props: ['busItemList'],
props: {
  // 表单项是否行内显示
  inline: {
    type: Boolean,
    default: true
  },
  // 表单项配置
  formConfig: {
    type: Array,
    default: () => []
  },
  // 表单项数据
  form: {
    type: Object,
    default: () => { }
  },
},
computed: {
},
data () {
  return {
    formData: this.form,
  }
},
mounted() {
  // 
},
methods: {
  // 下拉框
  getSelectKeys(obj, type) {
    const key = Object.keys(obj);

    // console.log("obj==", obj)
    // console.log('type==', obj[key[1]])

    return type === 'key' ? obj[key[0]] : obj[key[1]];
  },
  // 重置
  reset () {
    this.$refs.form.resetFields()
    // this.formData = {}
    Object.keys(this.formData).forEach(key=>{this.formData[key]=''})
  },
  // 获取form数据
  getFormParams () {
    console.log("formData==", this.formData)
    return this.formData
  },
  // 触发查询
  emitEvent ({eventName, params}) {
    this.$emit(eventName, params)
  },
  handleChange(val){
    console.log("val==", val)
  }
  
}
}
</script>
<style lang='scss' scoped>
  .form-box {
    // margin-bottom: 10px;
    :deep .el-form-item__label {
      font-size: 14px;
    }
    :deep .el-input__inner {
      font-size: 14px;
    }
  }
  .el-button {
    font-size: 14px;
  }
  .export {
    background-color: #0049CA;
    color: #FFFFFF;
    float: right;
    margin-right: 5%;
  }
  .el-buttom :active {
    background-color: #0049CA;
    color: #FFFFFF;
  }
</style>

2、组件引用

<template>
  <div class="index">
    <QueryForm
      ref="queryForm"
      :form="form"
      :form-config="formConfig"
      @query="query"
    >
    </QueryForm>
  </div>
</template>

<script>
import QueryForm  from "../component/QueryForm.vue"

export default {
  name: 'HelloWorld',
  components: {
    QueryForm
  },
  props: {
    // msg: String
  },
  data(){
    return{
      isSearching: false, // 是否查询中
      form: {
        id: '',
        status: '',
        time: '',
        pageSize: 10,
        pageNum: 1,
      },
      formConfig:{
        itemList: [
          {model:'id', label: "ID", type: 'input', placeholder: "请选择请选择", formOptions: this.options},
        ],
        operate: [
          {type: "success", name: "查询", handleClick: "query"}
        ]
      },
    }
  },
  methods: {
    query(){
      // const formParams = this.$refs.queryForm.getForm() || {}
      console.log("query")
    },
    // 查询
    refresh(){
      console.log("refresh")
    },
  }
}
</script>


  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在Vue3中,可以使用v-model指令来绑定表单元素,例如input、textarea和select等。在表单元素上使用v-model指令,可以将表单元素的值与Vue实例中的数据进行双向绑定。 例如,我们可以在Vue组件中使用以下代码来绑定一个input元素: ``` <template> <div> <form> <label for="name">姓名:</label> <input type="text" id="name" v-model="name"> </form> </div> </template> <script> export default { data() { return { name: '' } } } </script> ``` 在上面的代码中,我们使用v-model指令将input元素的值与Vue实例中的name属性进行双向绑定。当用户在input元素中输入内容时,Vue实例中的name属性也会随之更新。反之,当Vue实例中的name属性发生变化时,input元素的值也会随之更新。 需要注意的是,在Vue3中,v-model指令的默认行为已经发生了变化。在Vue2中,v-model指令默认会将表单元素的value属性与Vue实例中的数据进行双向绑定。但在Vue3中,v-model指令默认会将表单元素的modelValue属性与Vue实例中的数据进行双向绑定。因此,在使用v-model指令时,需要根据表单元素的类型和属性进行相应的配置。例如,对于checkbox和radio等表单元素,需要使用:checked和:value等属性来进行绑定。 ### 回答2: 在Vue 3中,v-model绑定form表单变得更加灵活和易用。使用v-model,可以实现双向绑定,也就是说,当用户在表单中输入内容时,表单的值会自动更新到Vue实例中的数据,反之亦然。以下是在Vue 3中绑定form表单的步骤: 1. 在data选项中定义表单中的数据属性。例如,您可以定义一个名为“formData”的对象,其中包含表单中所有输入字段的值。 2. 使用v-model指令将数据属性绑定到表单输入组件上。例如,您可以在文本框中使用“v-model = 'formData.username'”将formData对象中的“username”属性与文本框值绑定。 3. 当用户在表单中输入内容时,v-model指令会自动更新formData对象中相应的属性值。 4. 如果您还需要在表单提交时执行自定义操作,可以使用@submit事件监听表单提交事件,并在事件处理程序中执行所需的操作。 以下是一个简单的注册表单的示例代码: ``` <template> <form v-on:submit.prevent="onSubmit"> <div> <label for="username">用户名:</label> <input type="text" id="username" v-model="formData.username" /> </div> <div> <label for="password">密码:</label> <input type="password" id="password" v-model="formData.password" /> </div> <button type="submit">注册</button> </form> </template> <script> export default { data() { return { formData: { username: '', password: '', }, }; }, methods: { onSubmit() { // 执行表单提交操作 console.log(this.formData); }, }, }; </script> ``` 在上面的示例中,formData对象用于存储输入字段的值,v-model指令将formData对象中的属性与输入字段值绑定在一起,@submit事件监听表单提交事件,并在事件处理程序中输出formData对象的值。 ### 回答3: Vue3中v-model绑定form表单,与Vue2有所不同,Vue3使用了Composition API。处理表单数据的方式也更加智能化,灵活性更高。下面是具体解析: 1. V-model的使用方式 在Vue3中,我们可以使用v-model实现数据的双向绑定。与Vue2相比,Vue3的v-model使用方式有所改变,我们不再传递一个value和update事件,而是使用一个ModelValue对象。同时,在定义组件时,需使用.emits属性指定自定义组件可触发的事件列表。在composition API中也提供了一个useModel函数,可以方便地定义双向绑定数据。 2. Form表单数据的处理 在Vue2中,我们一般使用v-model绑定form表单,通过@submit事件提交form表单数据。在Vue3中,我们可以使用v-model绑定表单元素,然后通过watch监听表单元素的变化。当表单元素发生变化时,watch函数可以自动更新数据。在提交表单时,我们可以直接使用ref获取表单数据,然后通过AJAX请求来提交数据。 3. 使用响应式对象管理表单数据 在Vue3中,我们可以使用reactive对象来管理表单数据,使表单数据变为响应式的。这样,在表单元素发生变化时,实时更新表单数据。同时,我们还可以使用toRefs函数将响应式对象转化为可响应的对象,使得更新表单数据时,可以自动更新视图。 4. 借助第三方组件库优化表单的处理 Vue3的组合式API让我们可以方便地封装逻辑,将表单数据的处理功能封装为一个能够重复使用的组件。借助第三方组件库,如ElementUI或Ant Design Vue等,我们可以在项目中快速地搭建出完备、效果优美的表单组件,进一步提高开发效率。 总之,Vue3中v-model绑定form表单,可以处理表单数据的方式更加智能化,操作灵活性更高。结合响应式对象等特性,我们可以更快地搭建出效率高、可复用的表单组件,减少开发成本和工作量,提高生产力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值