更新于:2021-07-29 15:30
功能:input,select,搜尋select,textarea,各種年月日,時分秒,switch,單選,多選,檔案上傳,按鈕,text檢視隻讀,富文本編輯器,百度地圖(可選)
詳解:element的form表單二次封裝也很簡單,寫一個form表單你會發現不一樣的地方隻是form-item裡面的元件類型而已。是以把form-item裡面的内容可變化就行了。父級也隻需通過一個數組(form-item裡面元件類型數組),一個對象(form表單資料對象)控制就行了!為什麼要多一個對象,是為了友善資料送出,以及資料驗證。這次封裝多加了el-col,也沒有直接放進彈出框,是為了更加靈活可變!
1、form表單子元件代碼(富文本編輯器,可根據項目需求,不引入也行)引入了自己單獨二次封裝一下
<template>
<el-form :model="formData" class="demo-ruleForm" ref="ruleForm" label-position="left" label-width="120px">
<el-col :span="formobj.width ? formobj.width : 24" v-for=" (formobj,index) in formObj" :key="index" v-show="!formobj.notShow">
<el-form-item :label="formobj.label" :prop="formobj.prop" :rules="formobj.rules">
<!-- inupt輸入框 -->
<el-input size="small" v-if="formobj.input" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder" @input="inputINPUT($event,index,formobj.prop)" @change="inputChange($event,index,formobj.prop)"></el-input>
<!-- textarea輸入框 -->
<el-input size="small" type="textarea" v-if="formobj.textarea" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder"></el-input>
<!-- select選擇器 -->
<el-select size="small" v-if="formobj.select" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder" @change="selectChange($event,index,formobj.prop)">
<el-option :label="options.label" :value="options.value" v-for="(options, index) in formobj.options" :key="index">
</el-option>
</el-select>
<!-- select搜尋框 -->
<el-select size="small" v-if="formobj.searchSelect" :disabled="formobj.disabled" v-model="formData[formobj.prop]" filterable remote reserve-keyword :placeholder="formobj.placeholder" :remote-method="(query)=>remoteMethod(query,index,formobj.prop)" @change="selectChange($event,index,formobj.prop)" :loading="searchSelectLoading">
<el-option
v-for="(item,index) in formobj.options"
:key="index"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- 年月日時分秒選擇器 -->
<el-date-picker value-format="yyyy-MM-dd HH:mm:ss" type="datetime" size="small" v-if="formobj.dateTime" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder" ></el-date-picker>
<!-- 年月日時分秒,開始和結束時間 -->
<el-date-picker value-format="yyyy-MM-dd HH:mm:ss" format="yyyy-MM-dd HH:mm:ss" size="small" v-if="formobj.dateTimeRange" type="datetimerange":disabled="formobj.disabled" v-model="formData[formobj.prop]" range-separator="至" start-placeholder="開始日期" end-placeholder="結束日期" ></el-date-picker>
<!-- 時分秒選擇器 -->
<el-time-picker value-format="HH:mm:ss" format="HH:mm:ss" size="small" v-if="formobj.timePicker" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder" :picker-options="formobj.options">
</el-time-picker>
<!-- 時分秒選擇器,開始和結束時間 -->
<el-time-picker value-format="HH:mm:ss" format="HH:mm:ss" is-range size="small" v-if="formobj.timePickerIsRange" :disabled="formobj.disabled" v-model="formData[formobj.prop]" range-separator="至" start-placeholder="開始時間" end-placeholder="結束時間" placeholder="選擇時間範圍"></el-time-picker>
<!-- 年月日選擇器 -->
<el-date-picker value-format="yyyy-MM-dd" size="small" v-if="formobj.datePicker" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder">
</el-date-picker>
<!-- 年月日選擇器,開始和介紹年月日 -->
<el-date-picker value-format="yyyy-MM-dd" type="daterange" size="small" v-if="formobj.datePickerIsRange" :disabled="formobj.disabled" v-model="formData[formobj.prop]" :placeholder="formobj.placeholder" range-separator="至" start-placeholder="開始日期" end-placeholder="結束日期"></el-date-picker>
<!-- switch開關 -->
<el-switch size="small" v-if="formobj.switch" :disabled="formobj.disabled" v-model="formData[formobj.prop]" @change="formSwitchChange($event,index,formobj.prop)"></el-switch>
<!-- radio單選框 -->
<el-radio-group v-if="formobj.radio" :disabled="formobj.disabled" v-model="formData[formobj.prop]">
<el-radio :label="options.label" :value="options.value" v-for="(options, index) in formobj.options" :key="index">
</el-radio>
</el-radio-group>
<!-- checkbox複選框 -->
<el-checkbox-group v-if="formobj.checkbox" :disabled="formobj.disabled" v-model="formData[formobj.prop]">
<el-checkbox :label="options.label" :key="options.value" v-for="(options, index) in formobj.options">
</el-checkbox>
</el-checkbox-group>
<!-- 檔案上傳 --><!-- 如果對象有值就回顯,沒有值就為空 -->
<el-upload :accept="formobj.accept ? formobj.accept : 'PNG,JPEG'" v-if="formobj.upload" :ref="formobj.prop" :file-list=" formData[formobj.prop] ? formData[formobj.prop] : []" :action="`${uploadUrl}${formobj.uploadObj.fileType ? formobj.uploadObj.fileType : '' }`" :limit="formobj.uploadObj.limit" :class="{'hide':formobj.uploadObj.hideUpload || formData[formobj.prop].length==formobj.uploadObj.limit}" :on-preview="handlePictureCardPreview" :on-remove="(file,fileList)=>handleRemove(file,fileList,formobj.uploadObj.limit,formobj.prop,index)" :on-success="(response,file,fileList)=>uploadSuccess(response,file,fileList,formobj.uploadObj.limit,formobj.prop,index)" list-type="picture-card" :auto-upload="true">
<i slot="default" class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible" v-if="formobj.upload" :modal-append-to-body="false" width="40%">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<!-- 按鈕 -->
<el-button size="small" v-if="formobj.button" :disabled="formobj.disabled" :loading="formobj.loading" :type="formobj.buttonType || 'primary'" @click="buttonClick(formobj.prop,index)">{{formobj.placeholder}}</el-button>
<!-- text展示 -->
<span v-if="formobj.text" v-text="formData[formobj.prop]"></span>
<!-- 計量機關 -->
<span class="left10" v-if="formobj.unit">{{formobj.unit}}</span>
<!-- 高德地圖 -->
<!-- <div class="amap_div" v-if="formobj.aMap">
<el-input size="small" v-model="formData[formobj.prop]" @input="aMapInput($event,formobj.prop)"></el-input>
<ul v-show="searchShow==formobj.prop" class="sreach_ul">
<li @click="selectVal(sval,formobj.prop,index)" v-for=" (sval, index) in setSearchVal" :key="index">{{sval.name}}
<span style="color:#8591A6 ;font-size: 12px;">{{sval.district}}</span>
</li>
</ul>
<aMap :ref="'aMap'+formobj.prop" :aMapId="'aMapId'+formobj.prop" :location="formData[formobj.prop+'location']" @cbSearch="cbSearch($event,formobj.prop)"></aMap>
</div> -->
<quillEditor v-if="formobj.quillEditor" :quill="formData[formobj.prop]"></quillEditor>
</el-form-item>
</el-col>
</el-form>
</template>
<!-- zoutiancong封裝,date:20210429,詳細使用見根目錄@/views/home/testForm/testForm.vue,———————————————————————————————————————————————————————————————————————————————— -->
<script>
// import aMap from '../../map/aMap.vue'
import quillEditor from '@/components/quillEditor/quillEditor.vue'
export default {
components:{
quillEditor
},
props: {
formObj: {
type: Array,
required: true
},
formData: {
type: Object,
required: true
},
searchSelectOptionsCb:{
type:Array,
}
},
data() {
let uploadFileUrl = this.$store.state.user.uploadFileUrl;
return {
uploadUrl:uploadFileUrl,
dialogImageUrl: '',
searchSelectLoading:false,
dialogVisible: false,
disabled: false,
searchShow: '', //高德地圖input收索聯想
setSearchVal: [], //高德地圖指派搜尋内容
};
},
created() {
},
watch:{
},
methods: {
//select變化調用
selectChange(value, index, prop) {
this.$emit('selectChange', value, index, prop);
},
// input的input事件
inputINPUT(value, index, prop){
this.$emit('inputINPUT', value, index, prop);
},
// input的change事件
inputChange(value, index,prop){
this.$emit('inputChange', value,index, prop);
},
// 搜尋類型select搜尋
remoteMethod(query,index,prop) {
if (query) {
this.searchSelectLoading = true;
this.$emit('querySelectValue',query,index,prop);
setTimeout(() => {
this.formObj[index].options = this.searchSelectOptionsCb;
this.searchSelectLoading = false;
}, 500)
} else {
this.searchSelectOptios = [];
}
},
//switch變化
formSwitchChange(val,index,prop){
this.$emit("formSwitchChange",val,index,prop);
},
//按鈕點選事件
buttonClick(prop,index){
this.$emit("buttonClick",prop,index);
},
//檔案上傳成功回調
uploadSuccess(response,file,fileList,limit,prop,index) {
this.formObj[index].uploadObj.hideUpload=fileList.length==limit;//檔案清單變化後判斷目前檔案清單長度是否等于限制長度。目的,當長度相等時隐藏檔案上傳按鈕
this.pushUpload(file,fileList,limit,prop);
},
//檔案删除
handleRemove(file,fileList,limit,prop,index) {
this.formObj[index].uploadObj.hideUpload=fileList.length==limit;//檔案删除後判斷目前檔案清單長度是否等于限制長度。目的,當長度相等時隐藏檔案上傳按鈕
this.pushUpload(file,fileList,limit,prop);
},
// 檔案預覽
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
//送出時驗證表單,直接在父級調用
submitForm() {
let formValidate=Boolean;
this.$refs.ruleForm.validate((valid) => {
if (valid) {
formValidate=true;
} else {
this.$message.warning("請把資訊填寫完整!");
formValidate = false;
}
});
return formValidate;
},
/* 清空表單
邏輯:
1 、如果要清空檔案上傳清單,要傳入要清空的upload的字段名,假如多個upload用for循環,調用清空方法!
2、清空upload之後,還要把upload上傳框展示出來,通過字段名比對,擷取到在formObj中的下标,通過下标操作對象屬性,進行展示
*/
resetForm(uploadArr) {
this.$refs.ruleForm.resetFields();
if(uploadArr){
for(let i=0;i<uploadArr.length;i++){
this.$refs[uploadArr[i]][0].clearFiles();
let index=this.formObj.findIndex(item=>item.prop==uploadArr[i]);
this.formObj[index].uploadObj.hideUpload=false;
}
}
},
// 單個字段驗證
validateFieldProp(prop){
let formValidate=Boolean;
this.$refs.ruleForm.validateField(prop,valid => {
if (!valid) {
formValidate=true;
} else {
formValidate = false;
}
});
return formValidate;
},
// 對檔案上傳,删除進行指派,調用form驗證
pushUpload(file, fileList,limit,prop){
if(fileList.length>0){
this.formData[prop]=fileList;
}else{
// 表示沒有資料,把字段置空
this.formData[prop]="";
}
this.$refs.ruleForm.validateField(prop);//調用驗證form表單的檔案上傳
},
//地圖input的input事件
aMapInput(value, prop) {
this.$refs[`aMap${prop}`][0].getSearch(value);
},
//子元件傳回地圖搜尋值
cbSearch(val,prop) {
this.setSearchVal = val.tips; //子元件
this.searchShow = prop; //顯示input輸入聯想
},
//選中地圖值
selectVal(val,prop,index) {
// 指派的時候,拿到鍵,及formobj的下标,進行指派
this.formData[prop] = val.name; //input輸入框指派
this.formData.district = val.district; //傳入省市區
let lngLat = {
lng: val.location.lng,
lat: val.location.lat
};
this.formData[`${prop}location`] = lngLat;
this.searchShow = ''; //隐藏input輸入聯想
},
}
}
</script>
<style scoped>
@width: 220px;
/deep/.el-input {
width: @width;
}
/deep/.el-select {
width: @width;
}
/deep/.el-date-editor.el-input {
width: @width;
}
/deep/.el-date-editor .el-range-separator{
width: 20px !important;
}
/deep/.el-range-editor--small.el-input__inner{
width: 400px;
}
.el-textarea {
width: 400px;
}
.hide {
/deep/ .el-upload--picture-card {
display: none;
}
}
.amap_div {
overflow: hidden;
height: 400px;
width: 600px;
position: relative;
.sreach_ul {
position: absolute;
top: 1;
background-color: white;
z-index: 9;
min-width: 210px;
float: auto;
height: 200px;
overflow: auto;
padding: 0 20px;
line-height: 24px;
}
}
</style>
2、父元件調用
<template>
<div>
<el-button type="primary" @click="dialog = true" size="mini">點選打開 Dialog</el-button>
<el-dialog title="提示" :visible.sync="dialog" width="1200px" :modal-append-to-body="false">
<publicForm ref="publicForm" :formObj="formObj" :formData="formData"
:searchSelectOptionsCb="searchSelectOptionsCb" @selectChange="selectChange" @inputINPUT="inputINPUT"
@inputChange="inputChange" @querySelectValue="querySelectValue" @formSwitchChange="formSwitchChange"
@buttonClick="buttonClick">
</publicForm>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="dialogOK">确認</el-button>
<el-button @click="dialog=false">取 消</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import formJs from './js/testForm.js'
export default {
components: {},
data() {
return {
dialog: false, //彈出框
formObj: formJs.formObj,
formData: formJs.formData,
searchSelectOptionsCb: [], //form表單搜尋select傳回值
};
},
watch: {
dialog(newVal, oldVal) {
if (!newVal) {
this.$refs.publicForm.resetForm(); //視窗關閉清空表單
}
},
},
methods: {
// select選擇框變化
selectChange(value, index, prop) {
console.log(value, index, prop)
},
// inpuit變化
inputINPUT(value, index, prop) {
console.log(value, index, prop)
},
// inpuit Change
inputChange(value, index, prop) {
console.log(value, index, prop)
},
// select 搜尋值
querySelectValue(value, index, prop) {
console.log(value, index, prop)
let arr = [{
label: '搜尋傳回1号',
value: 1
}, {
label: '搜尋傳回2号',
value: 2
}];
this.searchSelectOptionsCb = arr;
},
// form表單switch變化
formSwitchChange(val, index, prop) {
console.log(val, index, prop)
},
// 按鈕點選
buttonClick(index, prop) {
console.log(index, prop)
},
dialogOK() {
//判斷表單驗證是否通過
if (this.$refs.publicForm.submitForm()) {
console.log("success");
console.log(this.formData)
} else {
console.log("error")
}
},
}
}
</script>
<style scoped>
</style>
3、父元件js(正規表達式js可以不用,或者自己封裝)
import regex from '../../../../utils/regex.js' // 正規表達式
export default {
formObj: [{
input: true, //是input
label: "input+正則", //字段
prop: "input", //字段名
placeholder: "請填寫手機号", //提示内容
width: 12, //參考el-col
disabled: false, //是否禁用
unit:'機關',
rules: [{
required: true,
message: '聯系方式'
}, { //可以自己寫utils,封裝正則驗證
validator: (rule, value, callback) => {
if (!value || !regex.isPhone(value)) {
callback(new Error());
} else {
callback();
}
},
message: "聯系方式不對",
}] //驗證
}, {
textarea: true, //是input
label: "輸入框", //字段
prop: "textearea", //字段名
placeholder: "請填寫輸入框", //提示内容
width: 12, //參考el-col
disabled: false, //是否禁用
rules: [{
required: true,
message: '輸入框'
}, ] //驗證
},
{
select: true,
label: "選擇框",
prop: "select",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: [{
label: "options1",
value: "1"
}, {
label: "options2",
value: "2"
}, ],
rules: [{
required: true,
message: '選擇框不能為空!'
}]
}, {
searchSelect: true,
label: "select搜尋框",
prop: "searchSelect",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: [],
rules: [{
required: true,
message: 'select搜尋框!'
}]
}, {
dateTimeRange: true,
label: "年月日時分秒開",
prop: "dateTimeRange",
width: 12, //參考el-col
disabled: false,
options: {
selectableRange: '18:30:00 - 20:30:00'
},
rules: [{
required: true,
message: '年月日時分秒開'
}, ]
}, {
timePicker: true,
label: "時分秒選擇器",
prop: "timePicker",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: "",
rules: [{
required: true,
message: '時分秒選擇器'
}, ]
}, {
timePickerIsRange: true,
label: "時分秒開始結束",
prop: "timePickerIsRange",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: "",
rules: [{
required: true,
message: '時分秒開始結束'
}, ]
}, {
datePicker: true,
label: "年月日選擇器",
prop: "datePicker",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: "",
rules: [{
required: true,
message: '年月日選擇器'
}, ]
}, {
datePickerIsRange: true,
label: "年月日開始結束",
prop: "datePickerIsRange",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: "",
rules: [{
required: true,
message: '年月日開始結束'
}, ]
}, {
dateTime: true,
label: " 年月日時分秒",
prop: "dateTime",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: "",
rules: [{
required: true,
message: ' 年月日時分秒'
}, ]
}, {
switch: true,
label: "switch",
prop: "switch",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
rules: [{
required: true,
message: 'switch'
}, ]
}, {
radio: true,
label: "單選框",
prop: "radio",
placeholder: "請選擇",
width: 12, //參考el-col
disabled: false,
options: [{
label: "單選框1",
value: "1"
}, {
label: "單選框2",
value: "2"
}, ],
rules: [{
required: true,
message: '單選框不能為空'
}, ]
}, {
checkbox: true,
label: "複選框",
prop: "checkbox",
disabled: false,
width: 12, //參考el-col
options: [{
label: "複選框1",
value: "1"
}, {
label: "複選框2",
value: "2"
}, {
label: "複選框3",
value: "3"
}, ],
rules: [{
required: true,
message: '複選框不能為空'
}, ]
},
{
upload: true,
label: "檔案上傳",
prop: "upload",
disabled: false,
uploadObj: {
fileType: "2001",
limit: 1, //上傳長度限制
hideUpload: false, //是否隐藏上傳框
},
rules: [{
required: true,
message: '檔案上傳'
}, ]
},
{
button: true,
label: "按鈕",
prop: "buttona",
placeholder:"發送驗證碼",
width: 12, //參考el-col
disabled: false,
},
{
text: true,
label: "文本",
prop: "text",
width: 12, //參考el-col
disabled: false,
},
{
quillEditor: true,
label: "富文本",
prop: "quill",
disabled: false,
},
],
formData: {
input: "",
textearea: "",
select: "",
searchSelect: "",
dateTimeRange: [],
timePicker: "",
timePickerIsRange: [],
datePicker: "",
datePickerIsRange: [],
dateTime: "",
date1: "",
switch: false,
radio: "",
checkbox: [],
upload: [],
text:"這是一段文本,用于預覽",
quill:{
content:""
}
},
}
4、效果圖預覽