Vue 项目封装表单类型组件 iform.vue
当我们在做Vue项目时,有时候项目很大,页面功能比较多时,很多控件堆在一起,很是臃肿,管理起来很麻烦。因此,我们就需要封装一些组件,达到简洁高效、可复用的效果。本章节主要是介绍如何封装表单类型的组件。
封装表单类型组件需要用到的文件以及其他组件(重要)
1、i-input.vue 公用组件,是i-form组件的最重要的组件,主要封装的就是这个,i-form就是将i-input组件套了一层外壳(el-form)。因此,总的来说,是我们这章节主要封装的对象。
2、publicform.js 文件,这个文件就是一些封装组件的方法,文件里面定义了几种表单类型(input、select、selects、date、time、combogrid、combopanel、switch、input_number、input_numbers)。
3、myPublicForm i-input封装组件里面注册的子组件,是需要渲染的基础表单子组件,因为当我们publicform.js 文件返回给组件的是一大串html的字符串,如果直接使用 html属性渲染 那一大串html字符串时,是渲染不出来的,为什么呢?因为我这里vue项目使用了ElementUi框架,直接使用 html属性渲染是渲染不出来Elementui的各种标签的。因此,我们需要使用注册的子组件来渲染Elementui字符串。
一、publicform.js 文件的实现
// 封装基础组件框架
const getBaseElem = function(elem, opt) {
let baseOptions = {
type: '',
model: '',
placeholder: '',
value: ''
};
var publicFrom = {
input: function (attr) {
if (attr) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var input = '<el-input' + elemetOptions + '></el-input>';
return input;
} else {
return '<el-input></el-input>';
}
} else {
}
},
select: function (attr, isMultiple) {
if (!attr.option) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var select = '<el-select' + elemetOptions + '></el-select>';
return select;
} else {
return '<el-select></el-select>';
}
} else {
let elemetOptions = getElement(attr);
if (elemetOptions) {
let multiple = isMultiple ? ' multiple ' : '';
var select = '<el-select' + elemetOptions + '' + multiple + '>';
attr.option.forEach(item => {
let elemetOptions = getElement(item);
select += '<el-option ' + elemetOptions + '></el-option>'
})
select += '</el-select>';
return select;
} else {
return '<el-select></el-select>';
}
}
},
selects: function (attr) {
return this.select(attr, true)
},
date: function (attr) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var date = '<el-date-picker' + elemetOptions + '></el-date-picker>';
return date;
} else {
return '<el-date-picker></el-date-picker>';
}
},
time: function (attr) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var time = '<el-time-picker' + elemetOptions + '></el-time-picker>';
return time;
} else {
return '<el-time-picker></el-time-picker>';
}
},
combogrid: function (attr) {
if (attr) {
let elemetOptions = JSON.stringify(attr);
if (elemetOptions) {
var input = "<icombogrid ref='combogrid' :getOptions='"+elemetOptions+"'></icombogrid>";
return input;
} else {
return '<icombogrid></icombogrid>';
}
} else {
}
},
combopanel: function (attr) {
if (attr) {
let elemetOptions = JSON.stringify(attr);
if (elemetOptions) {
var input = "<icombopanel :getOptions='"+elemetOptions+"'></icombopanel>";
return input;
} else {
return '<icombopanel></icombopanel>';
}
} else {
}
},
switch: function (attr) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var time = '<el-switch' + elemetOptions + ' active-color="#13ce66"></el-switch>';
return time;
} else {
return '<el-switch></el-switch>';
}
},
input_number: function (attr) {
let elemetOptions = getElement(attr);
if (elemetOptions) {
var time = '<el-input-number' + elemetOptions + ' controls-position="right"></el-input-number>';
return time;
} else {
return '<el-input-number></el-input-number>';
}
},
input_numbers: function (attr) {
let array = {};
let elemetOptions = getElement(attr);
if (elemetOptions) {
let time = '<div ' + elemetOptions + '>';
attr.numbers.forEach((item) => {
array = Object.assign({}, array, item);
let arrayElem = getElement(array);
time += '<el-input-number' + arrayElem + ' controls-position="right"></el-input-number>';
});
time += '</div>'
return time;
} else {
return '<el-input-number></el-input-number>';
}
}
};
return publicFrom[elem](opt)
},
// 解析对象键值对成属性
getElement = function (attr) {
var v = 'v-',
el = 'el-',
typeV = ["model", "if", "show", "for"],
elemHas = ["type", "model", "placeholder", "value", "style", "label", "name"]; // 通用属性
if (attr) {
var attrString = '',
attrElement = '';
for (var key in attr) {
elemHas.forEach(item => {
if (key == item) {
if (key == "model") {
attrString = v + key + '=' + '"' + attr[key] + '"';
attrString = attrString.toString()
attrElement += ' ' + attrString + ' ';
} else {
attrString = key + '=' + '"' + attr[key] + '"';
attrString = attrString.toString()
attrElement += ' ' + attrString + ' ';
}
}
})
}
return attrElement;
} else {
throw new Error("attr属性必须有值!");
}
}
export default getBaseElem
二、i-input组件的实现
template 只需要一个子组件
<template>
<div>
<myPublicForm ref="myPublicForm"></myPublicForm>
</div>
</template>
script 注册子组件,并且引入publicform文件,然后再渲染到子组件里。
<script>
import publicform from '../modules/publicForm.js' // 引入公共表单组件
import {EventBus} from '../modules/event-bus.js' // 引入事件总线
import Vue from 'vue';
export default {
components: { // 需要渲染的基础表单子组件
myPublicForm: {
props: {
showInputElem: {
type: String,
default: '<div></div>'
},
formData: {
type: Object,
default: () => {
return {}
}
},
},
mounted() {
},
watch: {
},
render(h) { // -----------------------渲染--------最重要的部分---------
const that = this
const com = Vue.extend({
data() {
return {
rightFormData: that.newformData,
}
},
template: that.newShowInputElem,
mounted() {
// 判断有没有combogrid的属性
this.$refs.hasOwnProperty("combogrid") && (that.combogrid = this.$refs.combogrid);
},
});
return h(com, {});
},
data() {
return {
newShowInputElem: this.showInputElem,
newformData: this.formData,
combogrid:{}
}
}
}
},
props: {
formTypeValue: {
type: Object,
default: () => {
return {}
}
},
rightFormData: {
type: Object,
default: () => {
return {}
}
}
},
watch: {
rightFormData: {
deep: true,
handler (newValue) {
// console.log('rightform', newValue)
this.$refs.myPublicForm.newformData = this.rightFormData
}
}
},
data() {
return {
}
},
mounted() {
this.getinputElem();
},
methods: {
getinputElem() { // 渲染
this.$refs.myPublicForm.newformData = this.rightFormData;
if (this.formTypeValue.hasOwnProperty('elem')) {
let arr = '';
arr = publicform(this.formTypeValue.elem, this.formTypeValue);
this.$refs.myPublicForm.newShowInputElem = arr;
}
},
disappear() { // 清除
this.$refs.myPublicForm.combogrid.hasOwnProperty("disappear") && this.$refs.myPublicForm.combogrid.disappear();
}
}
}
</script>
style
<style lang="scss">
.el-table__row .el-input {
width: 100%;
.el-input__inner {
height: 100%;
}
}
</style>
三、i-form组件的实现
i-form 组件就比较简单,主要的工作就是将 i-input 包上一层
< el-form>
< el-form-item>**************< /el-form-item>
</ el-form>
template
<template>
<div :model="model" class="i-form">
<el-form :inline="true" class="demo-form-inline">
<el-form-item :label="item.label" v-for="(item, index) in formTypeValue" :key="index">
<iinput :ref="'input_'+index" :formTypeValue="item" :rightFormData="rightFormData"></iinput>
</el-form-item>
</el-form>
<slot></slot>
</div>
</template>
script
<script>
import publicform from '../modules/publicForm.js' // 引入公共表单组件
import {EventBus} from '../modules/event-bus.js' // 引入事件总线
import Iinput from '../allPage/i-input.vue';
import Vue from 'vue';
export default {
name: 'i-form',
components: {Iinput},
props: {
model: { // model
type: Object,
default: () => {
return {}
}
},
rightFormData: { // 父级传的或者自己默认的model值
type: Object,
default: () => {
return {}
}
},
formTypeValue: { // 父级传的或者自己默认的表单集合
type: Array,
default: () => {
return []
}
},
timeValue: {
type: String,
default: ''
}
},
data() {
return {
}
},
watch: {
rightFormData: {
deep: true,
handler(newValue) {
console.log('form', newValue)
}
}
},
mounted() {
},
methods: {
disappear() { // 清除
this.formTypeValue.forEach((item,index) => {
var key = `input_${index}`;
this.$refs[key][0].disappear();
});
},
}
}
</script>
style
<style lang="scss">
.i-form {
padding: 0 10px;
display: flex;
align-items: center;
.el-button {
height: 30px;
}
}
.el-input {
width: 200px;
height: 30px;
}
.el-form--inline .el-form-item {
margin-right: 30px;
margin-bottom: 0px;
}
</style>